diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 1372460e..ba5451bd 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -50,7 +50,7 @@ - `ToolAPI` renamed to `CustomToolAPI` - `ToolContext` renamed to `CustomToolContext` - `ToolSessionEvent` renamed to `CustomToolSessionEvent` - - `execute()` signature changed: now takes `(toolCallId, params, signal, onUpdate, ctx: CustomToolContext)` + - `execute()` signature changed: now takes `(toolCallId, params, onUpdate, ctx: CustomToolContext, signal?)` - `onSession()` signature changed: now takes `(event: CustomToolSessionEvent, ctx: CustomToolContext)` - `CustomToolSessionEvent` simplified: only has `reason` and `previousSessionFile` (use `ctx.sessionManager.getBranch()` to get entries) - `CustomToolContext` provides `sessionManager: ReadonlySessionManager`, `modelRegistry`, and `model` diff --git a/packages/coding-agent/README.md b/packages/coding-agent/README.md index e1b55bed..0289bb38 100644 --- a/packages/coding-agent/README.md +++ b/packages/coding-agent/README.md @@ -659,7 +659,7 @@ const factory: CustomToolFactory = (pi) => ({ name: Type.String({ description: "Name to greet" }), }), - async execute(toolCallId, params, signal, onUpdate, ctx) { + async execute(toolCallId, params, onUpdate, ctx, signal) { const { name } = params as { name: string }; return { content: [{ type: "text", text: `Hello, ${name}!` }], diff --git a/packages/coding-agent/docs/custom-tools.md b/packages/coding-agent/docs/custom-tools.md index 020c1414..68c4d01a 100644 --- a/packages/coding-agent/docs/custom-tools.md +++ b/packages/coding-agent/docs/custom-tools.md @@ -36,7 +36,7 @@ const factory: CustomToolFactory = (pi) => ({ name: Type.String({ description: "Name to greet" }), }), - async execute(toolCallId, params, signal, onUpdate, ctx) { + async execute(toolCallId, params, onUpdate, ctx, signal) { const { name } = params as { name: string }; return { content: [{ type: "text", text: `Hello, ${name}!` }], @@ -112,7 +112,7 @@ const factory: CustomToolFactory = (pi) => ({ text: Type.Optional(Type.String()), }), - async execute(toolCallId, params, signal, onUpdate, ctx) { + async execute(toolCallId, params, onUpdate, ctx, signal) { // signal - AbortSignal for cancellation // onUpdate - Callback for streaming partial results // ctx - CustomToolContext with sessionManager, modelRegistry, model @@ -181,7 +181,7 @@ Always check `pi.hasUI` before using UI methods. Pass the `signal` from `execute` to `pi.exec` to support cancellation: ```typescript -async execute(toolCallId, params, signal, onUpdate, ctx) { +async execute(toolCallId, params, onUpdate, ctx, signal) { const result = await pi.exec("long-running-command", ["arg"], { signal }); if (result.killed) { return { content: [{ type: "text", text: "Cancelled" }] }; @@ -262,7 +262,7 @@ const factory: CustomToolFactory = (pi) => { onSession: reconstructState, - async execute(toolCallId, params, signal, onUpdate, ctx) { + async execute(toolCallId, params, onUpdate, ctx, signal) { // Modify items... items.push("new item"); @@ -384,7 +384,7 @@ If `renderCall` or `renderResult` is not defined or throws an error: ## Execute Function ```typescript -async execute(toolCallId, args, signal, onUpdate, ctx) { +async execute(toolCallId, args, onUpdate, ctx, signal) { // Type assertion for params (TypeBox schema doesn't flow through) const params = args as { action: "list" | "add"; text?: string }; diff --git a/packages/coding-agent/examples/custom-tools/hello/index.ts b/packages/coding-agent/examples/custom-tools/hello/index.ts index c2bf07b8..e72e7f05 100644 --- a/packages/coding-agent/examples/custom-tools/hello/index.ts +++ b/packages/coding-agent/examples/custom-tools/hello/index.ts @@ -9,7 +9,7 @@ const factory: CustomToolFactory = (_pi) => ({ name: Type.String({ description: "Name to greet" }), }), - async execute(_toolCallId, params) { + async execute(_toolCallId, params, _onUpdate, _ctx, _signal) { const { name } = params as { name: string }; return { content: [{ type: "text", text: `Hello, ${name}!` }], diff --git a/packages/coding-agent/examples/custom-tools/question/index.ts b/packages/coding-agent/examples/custom-tools/question/index.ts index 6949efcc..e75e8c45 100644 --- a/packages/coding-agent/examples/custom-tools/question/index.ts +++ b/packages/coding-agent/examples/custom-tools/question/index.ts @@ -24,7 +24,7 @@ const factory: CustomToolFactory = (pi) => { description: "Ask the user a question and let them pick from options. Use when you need user input to proceed.", parameters: QuestionParams, - async execute(_toolCallId, params) { + async execute(_toolCallId, params, _onUpdate, _ctx, _signal) { if (!pi.hasUI) { return { content: [{ type: "text", text: "Error: UI not available (running in non-interactive mode)" }], diff --git a/packages/coding-agent/examples/custom-tools/subagent/index.ts b/packages/coding-agent/examples/custom-tools/subagent/index.ts index c9fd89e2..3361e6d6 100644 --- a/packages/coding-agent/examples/custom-tools/subagent/index.ts +++ b/packages/coding-agent/examples/custom-tools/subagent/index.ts @@ -433,7 +433,7 @@ const factory: CustomToolFactory = (pi) => { }, parameters: SubagentParams, - async execute(_toolCallId, params, signal, onUpdate, _ctx) { + async execute(_toolCallId, params, onUpdate, _ctx, signal) { const agentScope: AgentScope = params.agentScope ?? "user"; const discovery = discoverAgents(pi.cwd, agentScope); const agents = discovery.agents; diff --git a/packages/coding-agent/examples/custom-tools/todo/index.ts b/packages/coding-agent/examples/custom-tools/todo/index.ts index 6b4d1feb..a20bf3de 100644 --- a/packages/coding-agent/examples/custom-tools/todo/index.ts +++ b/packages/coding-agent/examples/custom-tools/todo/index.ts @@ -78,7 +78,7 @@ const factory: CustomToolFactory = (_pi) => { // Called on session start/switch/branch/clear onSession: reconstructState, - async execute(_toolCallId, params) { + async execute(_toolCallId, params, _onUpdate, _ctx, _signal) { switch (params.action) { case "list": return { diff --git a/packages/coding-agent/src/core/custom-tools/types.ts b/packages/coding-agent/src/core/custom-tools/types.ts index dc9cfd75..a4baf9df 100644 --- a/packages/coding-agent/src/core/custom-tools/types.ts +++ b/packages/coding-agent/src/core/custom-tools/types.ts @@ -84,7 +84,7 @@ export type CustomToolResult = AgentToolResult; * description: "Does something useful", * parameters: Type.Object({ input: Type.String() }), * - * async execute(toolCallId, params, signal, onUpdate, ctx) { + * async execute(toolCallId, params, onUpdate, ctx, signal) { * // Access session state via ctx.sessionManager * // Access model registry via ctx.modelRegistry * // Current model via ctx.model @@ -114,16 +114,16 @@ export interface CustomTool { * Execute the tool. * @param toolCallId - Unique ID for this tool call * @param params - Parsed parameters matching the schema - * @param signal - AbortSignal for cancellation * @param onUpdate - Callback for streaming partial results (for UI, not LLM) * @param ctx - Context with session manager, model registry, and current model + * @param signal - Optional abort signal for cancellation */ execute( toolCallId: string, params: Static, - signal: AbortSignal | undefined, onUpdate: AgentToolUpdateCallback | undefined, ctx: CustomToolContext, + signal?: AbortSignal, ): Promise>; /** Called on session lifecycle events - use to reconstruct state or cleanup resources */ diff --git a/packages/coding-agent/src/core/custom-tools/wrapper.ts b/packages/coding-agent/src/core/custom-tools/wrapper.ts index 253f6092..b24ee028 100644 --- a/packages/coding-agent/src/core/custom-tools/wrapper.ts +++ b/packages/coding-agent/src/core/custom-tools/wrapper.ts @@ -16,7 +16,7 @@ export function wrapCustomTool(tool: CustomTool, getContext: () => CustomToolCon description: tool.description, parameters: tool.parameters, execute: (toolCallId, params, signal, onUpdate) => - tool.execute(toolCallId, params, signal, onUpdate, getContext()), + tool.execute(toolCallId, params, onUpdate, getContext(), signal), }; }