2026-02-13 12:57:16 +01:00
|
|
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin"
|
2026-02-13 13:18:07 +01:00
|
|
|
import { setPendingSwitch } from "../../features/agent-switch"
|
2026-02-18 19:26:33 +01:00
|
|
|
import { schedulePendingSwitchApply } from "../../features/agent-switch/scheduler"
|
2026-02-13 12:57:16 +01:00
|
|
|
import { updateSessionAgent } from "../../features/claude-code-session-state"
|
2026-02-13 13:18:07 +01:00
|
|
|
import type { SwitchAgentArgs } from "./types"
|
2026-02-13 12:57:16 +01:00
|
|
|
|
|
|
|
|
const DESCRIPTION =
|
|
|
|
|
"Switch the active session agent. After calling this tool, the session will transition to the specified agent " +
|
2026-02-13 13:18:07 +01:00
|
|
|
"with the provided context as its starting prompt. Use this to route work to another agent " +
|
|
|
|
|
"(e.g., Atlas for fixes, Prometheus for planning). The switch executes when the current agent's turn completes."
|
2026-02-13 12:57:16 +01:00
|
|
|
|
|
|
|
|
const ALLOWED_AGENTS = new Set(["atlas", "prometheus", "sisyphus", "hephaestus"])
|
|
|
|
|
|
2026-02-18 19:26:33 +01:00
|
|
|
type SessionClient = {
|
|
|
|
|
session: {
|
|
|
|
|
prompt?: (input: {
|
|
|
|
|
path: { id: string }
|
|
|
|
|
body: { agent: string; parts: Array<{ type: "text"; text: string }> }
|
|
|
|
|
}) => Promise<unknown>
|
|
|
|
|
promptAsync: (input: {
|
|
|
|
|
path: { id: string }
|
|
|
|
|
body: { agent: string; parts: Array<{ type: "text"; text: string }> }
|
|
|
|
|
}) => Promise<unknown>
|
2026-02-28 20:25:50 +01:00
|
|
|
create?: (input?: { body?: { parentID?: string; title?: string } }) => Promise<unknown>
|
2026-02-18 19:26:33 +01:00
|
|
|
messages: (input: { path: { id: string } }) => Promise<unknown>
|
|
|
|
|
status?: () => Promise<unknown>
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function createSwitchAgentTool(args: {
|
|
|
|
|
client: SessionClient
|
|
|
|
|
}): ToolDefinition {
|
|
|
|
|
const { client } = args
|
|
|
|
|
|
2026-02-13 12:57:16 +01:00
|
|
|
return tool({
|
|
|
|
|
description: DESCRIPTION,
|
|
|
|
|
args: {
|
|
|
|
|
agent: tool.schema
|
|
|
|
|
.string()
|
2026-02-13 13:18:07 +01:00
|
|
|
.describe("Target agent name to switch to (e.g., 'atlas', 'prometheus')"),
|
2026-02-13 12:57:16 +01:00
|
|
|
context: tool.schema
|
|
|
|
|
.string()
|
|
|
|
|
.describe("Context message for the target agent — include confirmed findings, the original question, and what action to take"),
|
|
|
|
|
},
|
2026-02-13 13:18:07 +01:00
|
|
|
async execute(args: SwitchAgentArgs, toolContext) {
|
2026-02-13 12:57:16 +01:00
|
|
|
const agentName = args.agent.toLowerCase()
|
|
|
|
|
|
|
|
|
|
if (!ALLOWED_AGENTS.has(agentName)) {
|
2026-02-13 13:18:07 +01:00
|
|
|
return `Invalid switch target: "${args.agent}". Allowed agents: ${[...ALLOWED_AGENTS].join(", ")}`
|
2026-02-13 12:57:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateSessionAgent(toolContext.sessionID, agentName)
|
2026-02-13 13:18:07 +01:00
|
|
|
setPendingSwitch(toolContext.sessionID, agentName, args.context)
|
2026-02-18 19:26:33 +01:00
|
|
|
schedulePendingSwitchApply({
|
|
|
|
|
sessionID: toolContext.sessionID,
|
|
|
|
|
client,
|
|
|
|
|
})
|
2026-02-13 12:57:16 +01:00
|
|
|
|
2026-02-13 13:18:07 +01:00
|
|
|
return `Agent switch queued. Session will switch to ${agentName} when your turn completes.`
|
2026-02-13 12:57:16 +01:00
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|