Files
oh-my-opencode/src/features/agent-switch/tui-agent-sync.ts
T

133 lines
3.4 KiB
TypeScript

import { getAgentConfigKey } from "../../shared/agent-display-names"
import { log, normalizeSDKResponse } from "../../shared"
type TuiClient = {
app?: {
agents?: () => Promise<unknown>
}
tui?: {
publish?: (input: {
body: {
type: "tui.command.execute"
properties: { command: string }
}
}) => Promise<unknown>
}
}
type AgentInfo = {
name?: string
mode?: "subagent" | "primary" | "all"
hidden?: boolean
}
function isCliClient(): boolean {
return (process.env["OPENCODE_CLIENT"] ?? "cli") === "cli"
}
function resolveCyclePlan(args: {
orderedAgentNames: string[]
sourceAgent: string
targetAgent: string
}): { command: "agent.cycle" | "agent.cycle.reverse"; steps: number } | undefined {
const { orderedAgentNames, sourceAgent, targetAgent } = args
if (orderedAgentNames.length < 2) {
return undefined
}
const orderedKeys = orderedAgentNames.map((name) => getAgentConfigKey(name))
const sourceKey = getAgentConfigKey(sourceAgent)
const targetKey = getAgentConfigKey(targetAgent)
const sourceIndex = orderedKeys.indexOf(sourceKey)
const targetIndex = orderedKeys.indexOf(targetKey)
if (sourceIndex < 0 || targetIndex < 0 || sourceIndex === targetIndex) {
return undefined
}
const size = orderedKeys.length
const forward = (targetIndex - sourceIndex + size) % size
const backward = (sourceIndex - targetIndex + size) % size
if (forward <= backward) {
return { command: "agent.cycle", steps: forward }
}
return { command: "agent.cycle.reverse", steps: backward }
}
export async function syncCliTuiAgentSelectionAfterSwitch(args: {
client: TuiClient
sessionID: string
sourceAgent: string | undefined
targetAgent: string
source: string
}): Promise<void> {
const { client, sessionID, sourceAgent, targetAgent, source } = args
if (!isCliClient()) {
return
}
if (!sourceAgent || !client.app?.agents || !client.tui?.publish) {
return
}
const sourceKey = getAgentConfigKey(sourceAgent)
const targetKey = getAgentConfigKey(targetAgent)
// Scope to Athena handoffs where CLI TUI can show stale local-agent selection.
if (sourceKey !== "athena" || (targetKey !== "atlas" && targetKey !== "prometheus")) {
return
}
try {
const response = await client.app.agents()
const agents = normalizeSDKResponse(response, [] as AgentInfo[], {
preferResponseOnMissingData: true,
})
const orderedPrimaryAgents = agents
.filter((agent) => typeof agent.name === "string" && agent.mode !== "subagent" && agent.hidden !== true)
.map((agent) => agent.name as string)
const plan = resolveCyclePlan({
orderedAgentNames: orderedPrimaryAgents,
sourceAgent,
targetAgent,
})
if (!plan || plan.steps <= 0) {
return
}
for (let step = 0; step < plan.steps; step += 1) {
await client.tui.publish({
body: {
type: "tui.command.execute",
properties: {
command: plan.command,
},
},
})
}
log("[agent-switch] Synced CLI TUI local agent after handoff", {
sessionID,
source,
sourceAgent,
targetAgent,
command: plan.command,
steps: plan.steps,
})
} catch (error) {
log("[agent-switch] Failed syncing CLI TUI local agent after handoff", {
sessionID,
source,
sourceAgent,
targetAgent,
error: String(error),
})
}
}