From 0a26db53ef2814e705948ff4d6c81c997423bcd3 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Mon, 2 Feb 2026 00:29:47 +0100 Subject: [PATCH] fix(coding-agent): align ToolDefinition.execute signature with AgentTool BREAKING CHANGE: ToolDefinition.execute parameter order changed from (id, params, onUpdate, ctx, signal) to (id, params, signal, onUpdate, ctx). This aligns with AgentTool.execute so wrapping built-in tools no longer requires parameter reordering. Update extensions by swapping signal and onUpdate parameters. --- packages/coding-agent/CHANGELOG.md | 11 +++++++++++ packages/coding-agent/docs/extensions.md | 12 ++++++------ .../examples/extensions/antigravity-image-gen.ts | 2 +- .../examples/extensions/bash-spawn-hook.ts | 2 +- packages/coding-agent/examples/extensions/hello.ts | 2 +- .../coding-agent/examples/extensions/question.ts | 2 +- .../examples/extensions/questionnaire.ts | 2 +- .../examples/extensions/sandbox/index.ts | 2 +- .../examples/extensions/shutdown-command.ts | 4 ++-- packages/coding-agent/examples/extensions/ssh.ts | 8 ++++---- .../examples/extensions/subagent/index.ts | 2 +- packages/coding-agent/examples/extensions/todo.ts | 2 +- .../examples/extensions/tool-override.ts | 2 +- .../examples/extensions/truncated-tool.ts | 2 +- packages/coding-agent/examples/sdk/06-extensions.ts | 2 +- packages/coding-agent/src/core/extensions/types.ts | 2 +- packages/coding-agent/src/core/extensions/wrapper.ts | 2 +- 17 files changed, 36 insertions(+), 25 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 453a3425..7a121fbb 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,17 @@ ## [Unreleased] +### Breaking Changes + +- **Extension tool signature change**: `ToolDefinition.execute` now uses `(toolCallId, params, signal, onUpdate, ctx)` parameter order to match `AgentTool.execute`. Previously it was `(toolCallId, params, onUpdate, ctx, signal)`. This makes wrapping built-in tools trivial since the first four parameters now align. Update your extensions by swapping the `signal` and `onUpdate` parameters: + ```ts + // Before + async execute(toolCallId, params, onUpdate, ctx, signal) { ... } + + // After + async execute(toolCallId, params, signal, onUpdate, ctx) { ... } + ``` + ### New Features - **Android/Termux support**: Pi now runs on Android via Termux. Install with: diff --git a/packages/coding-agent/docs/extensions.md b/packages/coding-agent/docs/extensions.md index 9e4b8bf3..e2e66d72 100644 --- a/packages/coding-agent/docs/extensions.md +++ b/packages/coding-agent/docs/extensions.md @@ -79,7 +79,7 @@ export default function (pi: ExtensionAPI) { parameters: Type.Object({ name: Type.String({ description: "Name to greet" }), }), - async execute(toolCallId, params, onUpdate, ctx, signal) { + async execute(toolCallId, params, signal, onUpdate, ctx) { return { content: [{ type: "text", text: `Hello, ${params.name}!` }], details: {}, @@ -789,7 +789,7 @@ pi.registerTool({ text: Type.Optional(Type.String()), }), - async execute(toolCallId, params, onUpdate, ctx, signal) { + async execute(toolCallId, params, signal, onUpdate, ctx) { // Stream progress onUpdate?.({ content: [{ type: "text", text: "Working..." }] }); @@ -1115,7 +1115,7 @@ export default function (pi: ExtensionAPI) { pi.registerTool({ name: "my_tool", // ... - async execute(toolCallId, params, onUpdate, ctx, signal) { + async execute(toolCallId, params, signal, onUpdate, ctx) { items.push("new item"); return { content: [{ type: "text", text: "Added" }], @@ -1146,7 +1146,7 @@ pi.registerTool({ text: Type.Optional(Type.String()), }), - async execute(toolCallId, params, onUpdate, ctx, signal) { + async execute(toolCallId, params, signal, onUpdate, ctx) { // Check for cancellation if (signal?.aborted) { return { content: [{ type: "text", text: "Cancelled" }] }; @@ -1224,7 +1224,7 @@ const remoteRead = createReadTool(cwd, { // Register, checking flag at execution time pi.registerTool({ ...remoteRead, - async execute(id, params, onUpdate, _ctx, signal) { + async execute(id, params, signal, onUpdate, _ctx) { const ssh = getSshConfig(); if (ssh) { const tool = createReadTool(cwd, { operations: createRemoteOps(ssh) }); @@ -1272,7 +1272,7 @@ import { DEFAULT_MAX_LINES, // 2000 } from "@mariozechner/pi-coding-agent"; -async execute(toolCallId, params, onUpdate, ctx, signal) { +async execute(toolCallId, params, signal, onUpdate, ctx) { const output = await runCommand(); // Apply truncation diff --git a/packages/coding-agent/examples/extensions/antigravity-image-gen.ts b/packages/coding-agent/examples/extensions/antigravity-image-gen.ts index f561d126..9ba08b20 100644 --- a/packages/coding-agent/examples/extensions/antigravity-image-gen.ts +++ b/packages/coding-agent/examples/extensions/antigravity-image-gen.ts @@ -352,7 +352,7 @@ export default function antigravityImageGen(pi: ExtensionAPI) { description: "Generate an image via Google Antigravity image models. Returns the image as a tool result attachment. Optional saving via save=project|global|custom|none, or PI_IMAGE_SAVE_MODE/PI_IMAGE_SAVE_DIR.", parameters: TOOL_PARAMS, - async execute(_toolCallId, params: ToolParams, onUpdate, ctx, signal) { + async execute(_toolCallId, params: ToolParams, signal, onUpdate, ctx) { const { accessToken, projectId } = await getCredentials(ctx); const model = params.model || DEFAULT_MODEL; const aspectRatio = params.aspectRatio || DEFAULT_ASPECT_RATIO; diff --git a/packages/coding-agent/examples/extensions/bash-spawn-hook.ts b/packages/coding-agent/examples/extensions/bash-spawn-hook.ts index 977638ae..ae543fba 100644 --- a/packages/coding-agent/examples/extensions/bash-spawn-hook.ts +++ b/packages/coding-agent/examples/extensions/bash-spawn-hook.ts @@ -23,7 +23,7 @@ export default function (pi: ExtensionAPI) { pi.registerTool({ ...bashTool, - execute: async (id, params, onUpdate, _ctx, signal) => { + execute: async (id, params, signal, onUpdate, _ctx) => { return bashTool.execute(id, params, signal, onUpdate); }, }); diff --git a/packages/coding-agent/examples/extensions/hello.ts b/packages/coding-agent/examples/extensions/hello.ts index df9aa740..39ecf3f6 100644 --- a/packages/coding-agent/examples/extensions/hello.ts +++ b/packages/coding-agent/examples/extensions/hello.ts @@ -14,7 +14,7 @@ export default function (pi: ExtensionAPI) { name: Type.String({ description: "Name to greet" }), }), - async execute(_toolCallId, params, _onUpdate, _ctx, _signal) { + async execute(_toolCallId, params, _signal, _onUpdate, _ctx) { const { name } = params as { name: string }; return { content: [{ type: "text", text: `Hello, ${name}!` }], diff --git a/packages/coding-agent/examples/extensions/question.ts b/packages/coding-agent/examples/extensions/question.ts index d202114d..73a52b9e 100644 --- a/packages/coding-agent/examples/extensions/question.ts +++ b/packages/coding-agent/examples/extensions/question.ts @@ -40,7 +40,7 @@ export default function question(pi: ExtensionAPI) { 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, _onUpdate, ctx, _signal) { + async execute(_toolCallId, params, _signal, _onUpdate, ctx) { if (!ctx.hasUI) { return { content: [{ type: "text", text: "Error: UI not available (running in non-interactive mode)" }], diff --git a/packages/coding-agent/examples/extensions/questionnaire.ts b/packages/coding-agent/examples/extensions/questionnaire.ts index 4bb92af8..c73fa76a 100644 --- a/packages/coding-agent/examples/extensions/questionnaire.ts +++ b/packages/coding-agent/examples/extensions/questionnaire.ts @@ -81,7 +81,7 @@ export default function questionnaire(pi: ExtensionAPI) { "Ask the user one or more questions. Use for clarifying requirements, getting preferences, or confirming decisions. For single questions, shows a simple option list. For multiple questions, shows a tab-based interface.", parameters: QuestionnaireParams, - async execute(_toolCallId, params, _onUpdate, ctx, _signal) { + async execute(_toolCallId, params, _signal, _onUpdate, ctx) { if (!ctx.hasUI) { return errorResult("Error: UI not available (running in non-interactive mode)"); } diff --git a/packages/coding-agent/examples/extensions/sandbox/index.ts b/packages/coding-agent/examples/extensions/sandbox/index.ts index e9d07c77..1e31ee20 100644 --- a/packages/coding-agent/examples/extensions/sandbox/index.ts +++ b/packages/coding-agent/examples/extensions/sandbox/index.ts @@ -211,7 +211,7 @@ export default function (pi: ExtensionAPI) { pi.registerTool({ ...localBash, label: "bash (sandboxed)", - async execute(id, params, onUpdate, _ctx, signal) { + async execute(id, params, signal, onUpdate, _ctx) { if (!sandboxEnabled || !sandboxInitialized) { return localBash.execute(id, params, signal, onUpdate); } diff --git a/packages/coding-agent/examples/extensions/shutdown-command.ts b/packages/coding-agent/examples/extensions/shutdown-command.ts index fa0063f5..b2243056 100644 --- a/packages/coding-agent/examples/extensions/shutdown-command.ts +++ b/packages/coding-agent/examples/extensions/shutdown-command.ts @@ -23,7 +23,7 @@ export default function (pi: ExtensionAPI) { label: "Finish and Exit", description: "Complete a task and exit pi", parameters: Type.Object({}), - async execute(_toolCallId, _params, _onUpdate, ctx, _signal) { + async execute(_toolCallId, _params, _signal, _onUpdate, ctx) { // Do any final work here... // Request graceful shutdown (deferred until agent is idle) ctx.shutdown(); @@ -44,7 +44,7 @@ export default function (pi: ExtensionAPI) { parameters: Type.Object({ environment: Type.String({ description: "Target environment (e.g., production, staging)" }), }), - async execute(_toolCallId, params, onUpdate, ctx, _signal) { + async execute(_toolCallId, params, _signal, onUpdate, ctx) { onUpdate?.({ content: [{ type: "text", text: `Deploying to ${params.environment}...` }], details: {} }); // Example deployment logic diff --git a/packages/coding-agent/examples/extensions/ssh.ts b/packages/coding-agent/examples/extensions/ssh.ts index 5c2eb217..73add6a5 100644 --- a/packages/coding-agent/examples/extensions/ssh.ts +++ b/packages/coding-agent/examples/extensions/ssh.ts @@ -127,7 +127,7 @@ export default function (pi: ExtensionAPI) { pi.registerTool({ ...localRead, - async execute(id, params, onUpdate, _ctx, signal) { + async execute(id, params, signal, onUpdate, _ctx) { const ssh = getSsh(); if (ssh) { const tool = createReadTool(localCwd, { @@ -141,7 +141,7 @@ export default function (pi: ExtensionAPI) { pi.registerTool({ ...localWrite, - async execute(id, params, onUpdate, _ctx, signal) { + async execute(id, params, signal, onUpdate, _ctx) { const ssh = getSsh(); if (ssh) { const tool = createWriteTool(localCwd, { @@ -155,7 +155,7 @@ export default function (pi: ExtensionAPI) { pi.registerTool({ ...localEdit, - async execute(id, params, onUpdate, _ctx, signal) { + async execute(id, params, signal, onUpdate, _ctx) { const ssh = getSsh(); if (ssh) { const tool = createEditTool(localCwd, { @@ -169,7 +169,7 @@ export default function (pi: ExtensionAPI) { pi.registerTool({ ...localBash, - async execute(id, params, onUpdate, _ctx, signal) { + async execute(id, params, signal, onUpdate, _ctx) { const ssh = getSsh(); if (ssh) { const tool = createBashTool(localCwd, { diff --git a/packages/coding-agent/examples/extensions/subagent/index.ts b/packages/coding-agent/examples/extensions/subagent/index.ts index 5bd41124..1c43cbfc 100644 --- a/packages/coding-agent/examples/extensions/subagent/index.ts +++ b/packages/coding-agent/examples/extensions/subagent/index.ts @@ -416,7 +416,7 @@ export default function (pi: ExtensionAPI) { ].join(" "), parameters: SubagentParams, - async execute(_toolCallId, params, onUpdate, ctx, signal) { + async execute(_toolCallId, params, signal, onUpdate, ctx) { const agentScope: AgentScope = params.agentScope ?? "user"; const discovery = discoverAgents(ctx.cwd, agentScope); const agents = discovery.agents; diff --git a/packages/coding-agent/examples/extensions/todo.ts b/packages/coding-agent/examples/extensions/todo.ts index d55415f2..0f41abb8 100644 --- a/packages/coding-agent/examples/extensions/todo.ts +++ b/packages/coding-agent/examples/extensions/todo.ts @@ -141,7 +141,7 @@ export default function (pi: ExtensionAPI) { description: "Manage a todo list. Actions: list, add (text), toggle (id), clear", parameters: TodoParams, - async execute(_toolCallId, params, _onUpdate, _ctx, _signal) { + async execute(_toolCallId, params, _signal, _onUpdate, _ctx) { switch (params.action) { case "list": return { diff --git a/packages/coding-agent/examples/extensions/tool-override.ts b/packages/coding-agent/examples/extensions/tool-override.ts index 3651b9d6..8ee56349 100644 --- a/packages/coding-agent/examples/extensions/tool-override.ts +++ b/packages/coding-agent/examples/extensions/tool-override.ts @@ -72,7 +72,7 @@ export default function (pi: ExtensionAPI) { "Read the contents of a file with access logging. Some sensitive paths (.env, secrets, credentials) are blocked.", parameters: readSchema, - async execute(_toolCallId, params, _onUpdate, ctx) { + async execute(_toolCallId, params, _signal, _onUpdate, ctx) { const { path, offset, limit } = params; const absolutePath = resolve(ctx.cwd, path); diff --git a/packages/coding-agent/examples/extensions/truncated-tool.ts b/packages/coding-agent/examples/extensions/truncated-tool.ts index e211ca0f..0a0b3892 100644 --- a/packages/coding-agent/examples/extensions/truncated-tool.ts +++ b/packages/coding-agent/examples/extensions/truncated-tool.ts @@ -52,7 +52,7 @@ export default function (pi: ExtensionAPI) { description: `Search file contents using ripgrep. Output is truncated to ${DEFAULT_MAX_LINES} lines or ${formatSize(DEFAULT_MAX_BYTES)} (whichever is hit first). If truncated, full output is saved to a temp file.`, parameters: RgParams, - async execute(_toolCallId, params, _onUpdate, ctx) { + async execute(_toolCallId, params, _signal, _onUpdate, ctx) { const { pattern, path: searchPath, glob } = params; // Build the ripgrep command diff --git a/packages/coding-agent/examples/sdk/06-extensions.ts b/packages/coding-agent/examples/sdk/06-extensions.ts index 9c95ec4c..2d03d387 100644 --- a/packages/coding-agent/examples/sdk/06-extensions.ts +++ b/packages/coding-agent/examples/sdk/06-extensions.ts @@ -71,7 +71,7 @@ export default function (pi: ExtensionAPI) { parameters: Type.Object({ input: Type.String(), }), - execute: async (_toolCallId, params, _onUpdate, _ctx, _signal) => ({ + execute: async (_toolCallId, params, _signal, _onUpdate, _ctx) => ({ content: [{ type: "text", text: \`Processed: \${params.input}\` }], details: {}, }), diff --git a/packages/coding-agent/src/core/extensions/types.ts b/packages/coding-agent/src/core/extensions/types.ts index efdb6027..0e927b82 100644 --- a/packages/coding-agent/src/core/extensions/types.ts +++ b/packages/coding-agent/src/core/extensions/types.ts @@ -324,9 +324,9 @@ export interface ToolDefinition, + signal: AbortSignal | undefined, onUpdate: AgentToolUpdateCallback | undefined, ctx: ExtensionContext, - signal?: AbortSignal, ): Promise>; /** Custom rendering for tool call display */ diff --git a/packages/coding-agent/src/core/extensions/wrapper.ts b/packages/coding-agent/src/core/extensions/wrapper.ts index 0626afaf..e88f96e8 100644 --- a/packages/coding-agent/src/core/extensions/wrapper.ts +++ b/packages/coding-agent/src/core/extensions/wrapper.ts @@ -18,7 +18,7 @@ export function wrapRegisteredTool(registeredTool: RegisteredTool, runner: Exten description: definition.description, parameters: definition.parameters, execute: (toolCallId, params, signal, onUpdate) => - definition.execute(toolCallId, params, onUpdate, runner.createContext(), signal), + definition.execute(toolCallId, params, signal, onUpdate, runner.createContext()), }; }