mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 08:00:59 +00:00
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.
This commit is contained in:
parent
287a0b606d
commit
0a26db53ef
17 changed files with 36 additions and 25 deletions
|
|
@ -2,6 +2,17 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [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
|
### New Features
|
||||||
|
|
||||||
- **Android/Termux support**: Pi now runs on Android via Termux. Install with:
|
- **Android/Termux support**: Pi now runs on Android via Termux. Install with:
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
parameters: Type.Object({
|
parameters: Type.Object({
|
||||||
name: Type.String({ description: "Name to greet" }),
|
name: Type.String({ description: "Name to greet" }),
|
||||||
}),
|
}),
|
||||||
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `Hello, ${params.name}!` }],
|
content: [{ type: "text", text: `Hello, ${params.name}!` }],
|
||||||
details: {},
|
details: {},
|
||||||
|
|
@ -789,7 +789,7 @@ pi.registerTool({
|
||||||
text: Type.Optional(Type.String()),
|
text: Type.Optional(Type.String()),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
||||||
// Stream progress
|
// Stream progress
|
||||||
onUpdate?.({ content: [{ type: "text", text: "Working..." }] });
|
onUpdate?.({ content: [{ type: "text", text: "Working..." }] });
|
||||||
|
|
||||||
|
|
@ -1115,7 +1115,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
pi.registerTool({
|
pi.registerTool({
|
||||||
name: "my_tool",
|
name: "my_tool",
|
||||||
// ...
|
// ...
|
||||||
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
||||||
items.push("new item");
|
items.push("new item");
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: "Added" }],
|
content: [{ type: "text", text: "Added" }],
|
||||||
|
|
@ -1146,7 +1146,7 @@ pi.registerTool({
|
||||||
text: Type.Optional(Type.String()),
|
text: Type.Optional(Type.String()),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
||||||
// Check for cancellation
|
// Check for cancellation
|
||||||
if (signal?.aborted) {
|
if (signal?.aborted) {
|
||||||
return { content: [{ type: "text", text: "Cancelled" }] };
|
return { content: [{ type: "text", text: "Cancelled" }] };
|
||||||
|
|
@ -1224,7 +1224,7 @@ const remoteRead = createReadTool(cwd, {
|
||||||
// Register, checking flag at execution time
|
// Register, checking flag at execution time
|
||||||
pi.registerTool({
|
pi.registerTool({
|
||||||
...remoteRead,
|
...remoteRead,
|
||||||
async execute(id, params, onUpdate, _ctx, signal) {
|
async execute(id, params, signal, onUpdate, _ctx) {
|
||||||
const ssh = getSshConfig();
|
const ssh = getSshConfig();
|
||||||
if (ssh) {
|
if (ssh) {
|
||||||
const tool = createReadTool(cwd, { operations: createRemoteOps(ssh) });
|
const tool = createReadTool(cwd, { operations: createRemoteOps(ssh) });
|
||||||
|
|
@ -1272,7 +1272,7 @@ import {
|
||||||
DEFAULT_MAX_LINES, // 2000
|
DEFAULT_MAX_LINES, // 2000
|
||||||
} from "@mariozechner/pi-coding-agent";
|
} from "@mariozechner/pi-coding-agent";
|
||||||
|
|
||||||
async execute(toolCallId, params, onUpdate, ctx, signal) {
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
||||||
const output = await runCommand();
|
const output = await runCommand();
|
||||||
|
|
||||||
// Apply truncation
|
// Apply truncation
|
||||||
|
|
|
||||||
|
|
@ -352,7 +352,7 @@ export default function antigravityImageGen(pi: ExtensionAPI) {
|
||||||
description:
|
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.",
|
"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,
|
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 { accessToken, projectId } = await getCredentials(ctx);
|
||||||
const model = params.model || DEFAULT_MODEL;
|
const model = params.model || DEFAULT_MODEL;
|
||||||
const aspectRatio = params.aspectRatio || DEFAULT_ASPECT_RATIO;
|
const aspectRatio = params.aspectRatio || DEFAULT_ASPECT_RATIO;
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
|
|
||||||
pi.registerTool({
|
pi.registerTool({
|
||||||
...bashTool,
|
...bashTool,
|
||||||
execute: async (id, params, onUpdate, _ctx, signal) => {
|
execute: async (id, params, signal, onUpdate, _ctx) => {
|
||||||
return bashTool.execute(id, params, signal, onUpdate);
|
return bashTool.execute(id, params, signal, onUpdate);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
name: Type.String({ description: "Name to greet" }),
|
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 };
|
const { name } = params as { name: string };
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: `Hello, ${name}!` }],
|
content: [{ type: "text", text: `Hello, ${name}!` }],
|
||||||
|
|
|
||||||
|
|
@ -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.",
|
description: "Ask the user a question and let them pick from options. Use when you need user input to proceed.",
|
||||||
parameters: QuestionParams,
|
parameters: QuestionParams,
|
||||||
|
|
||||||
async execute(_toolCallId, params, _onUpdate, ctx, _signal) {
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
||||||
if (!ctx.hasUI) {
|
if (!ctx.hasUI) {
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: "Error: UI not available (running in non-interactive mode)" }],
|
content: [{ type: "text", text: "Error: UI not available (running in non-interactive mode)" }],
|
||||||
|
|
|
||||||
|
|
@ -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.",
|
"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,
|
parameters: QuestionnaireParams,
|
||||||
|
|
||||||
async execute(_toolCallId, params, _onUpdate, ctx, _signal) {
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
||||||
if (!ctx.hasUI) {
|
if (!ctx.hasUI) {
|
||||||
return errorResult("Error: UI not available (running in non-interactive mode)");
|
return errorResult("Error: UI not available (running in non-interactive mode)");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
pi.registerTool({
|
pi.registerTool({
|
||||||
...localBash,
|
...localBash,
|
||||||
label: "bash (sandboxed)",
|
label: "bash (sandboxed)",
|
||||||
async execute(id, params, onUpdate, _ctx, signal) {
|
async execute(id, params, signal, onUpdate, _ctx) {
|
||||||
if (!sandboxEnabled || !sandboxInitialized) {
|
if (!sandboxEnabled || !sandboxInitialized) {
|
||||||
return localBash.execute(id, params, signal, onUpdate);
|
return localBash.execute(id, params, signal, onUpdate);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
label: "Finish and Exit",
|
label: "Finish and Exit",
|
||||||
description: "Complete a task and exit pi",
|
description: "Complete a task and exit pi",
|
||||||
parameters: Type.Object({}),
|
parameters: Type.Object({}),
|
||||||
async execute(_toolCallId, _params, _onUpdate, ctx, _signal) {
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
||||||
// Do any final work here...
|
// Do any final work here...
|
||||||
// Request graceful shutdown (deferred until agent is idle)
|
// Request graceful shutdown (deferred until agent is idle)
|
||||||
ctx.shutdown();
|
ctx.shutdown();
|
||||||
|
|
@ -44,7 +44,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
parameters: Type.Object({
|
parameters: Type.Object({
|
||||||
environment: Type.String({ description: "Target environment (e.g., production, staging)" }),
|
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: {} });
|
onUpdate?.({ content: [{ type: "text", text: `Deploying to ${params.environment}...` }], details: {} });
|
||||||
|
|
||||||
// Example deployment logic
|
// Example deployment logic
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
|
|
||||||
pi.registerTool({
|
pi.registerTool({
|
||||||
...localRead,
|
...localRead,
|
||||||
async execute(id, params, onUpdate, _ctx, signal) {
|
async execute(id, params, signal, onUpdate, _ctx) {
|
||||||
const ssh = getSsh();
|
const ssh = getSsh();
|
||||||
if (ssh) {
|
if (ssh) {
|
||||||
const tool = createReadTool(localCwd, {
|
const tool = createReadTool(localCwd, {
|
||||||
|
|
@ -141,7 +141,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
|
|
||||||
pi.registerTool({
|
pi.registerTool({
|
||||||
...localWrite,
|
...localWrite,
|
||||||
async execute(id, params, onUpdate, _ctx, signal) {
|
async execute(id, params, signal, onUpdate, _ctx) {
|
||||||
const ssh = getSsh();
|
const ssh = getSsh();
|
||||||
if (ssh) {
|
if (ssh) {
|
||||||
const tool = createWriteTool(localCwd, {
|
const tool = createWriteTool(localCwd, {
|
||||||
|
|
@ -155,7 +155,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
|
|
||||||
pi.registerTool({
|
pi.registerTool({
|
||||||
...localEdit,
|
...localEdit,
|
||||||
async execute(id, params, onUpdate, _ctx, signal) {
|
async execute(id, params, signal, onUpdate, _ctx) {
|
||||||
const ssh = getSsh();
|
const ssh = getSsh();
|
||||||
if (ssh) {
|
if (ssh) {
|
||||||
const tool = createEditTool(localCwd, {
|
const tool = createEditTool(localCwd, {
|
||||||
|
|
@ -169,7 +169,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
|
|
||||||
pi.registerTool({
|
pi.registerTool({
|
||||||
...localBash,
|
...localBash,
|
||||||
async execute(id, params, onUpdate, _ctx, signal) {
|
async execute(id, params, signal, onUpdate, _ctx) {
|
||||||
const ssh = getSsh();
|
const ssh = getSsh();
|
||||||
if (ssh) {
|
if (ssh) {
|
||||||
const tool = createBashTool(localCwd, {
|
const tool = createBashTool(localCwd, {
|
||||||
|
|
|
||||||
|
|
@ -416,7 +416,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
].join(" "),
|
].join(" "),
|
||||||
parameters: SubagentParams,
|
parameters: SubagentParams,
|
||||||
|
|
||||||
async execute(_toolCallId, params, onUpdate, ctx, signal) {
|
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
||||||
const agentScope: AgentScope = params.agentScope ?? "user";
|
const agentScope: AgentScope = params.agentScope ?? "user";
|
||||||
const discovery = discoverAgents(ctx.cwd, agentScope);
|
const discovery = discoverAgents(ctx.cwd, agentScope);
|
||||||
const agents = discovery.agents;
|
const agents = discovery.agents;
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
description: "Manage a todo list. Actions: list, add (text), toggle (id), clear",
|
description: "Manage a todo list. Actions: list, add (text), toggle (id), clear",
|
||||||
parameters: TodoParams,
|
parameters: TodoParams,
|
||||||
|
|
||||||
async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
||||||
switch (params.action) {
|
switch (params.action) {
|
||||||
case "list":
|
case "list":
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -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.",
|
"Read the contents of a file with access logging. Some sensitive paths (.env, secrets, credentials) are blocked.",
|
||||||
parameters: readSchema,
|
parameters: readSchema,
|
||||||
|
|
||||||
async execute(_toolCallId, params, _onUpdate, ctx) {
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
||||||
const { path, offset, limit } = params;
|
const { path, offset, limit } = params;
|
||||||
const absolutePath = resolve(ctx.cwd, path);
|
const absolutePath = resolve(ctx.cwd, path);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.`,
|
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,
|
parameters: RgParams,
|
||||||
|
|
||||||
async execute(_toolCallId, params, _onUpdate, ctx) {
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
||||||
const { pattern, path: searchPath, glob } = params;
|
const { pattern, path: searchPath, glob } = params;
|
||||||
|
|
||||||
// Build the ripgrep command
|
// Build the ripgrep command
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
parameters: Type.Object({
|
parameters: Type.Object({
|
||||||
input: Type.String(),
|
input: Type.String(),
|
||||||
}),
|
}),
|
||||||
execute: async (_toolCallId, params, _onUpdate, _ctx, _signal) => ({
|
execute: async (_toolCallId, params, _signal, _onUpdate, _ctx) => ({
|
||||||
content: [{ type: "text", text: \`Processed: \${params.input}\` }],
|
content: [{ type: "text", text: \`Processed: \${params.input}\` }],
|
||||||
details: {},
|
details: {},
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -324,9 +324,9 @@ export interface ToolDefinition<TParams extends TSchema = TSchema, TDetails = un
|
||||||
execute(
|
execute(
|
||||||
toolCallId: string,
|
toolCallId: string,
|
||||||
params: Static<TParams>,
|
params: Static<TParams>,
|
||||||
|
signal: AbortSignal | undefined,
|
||||||
onUpdate: AgentToolUpdateCallback<TDetails> | undefined,
|
onUpdate: AgentToolUpdateCallback<TDetails> | undefined,
|
||||||
ctx: ExtensionContext,
|
ctx: ExtensionContext,
|
||||||
signal?: AbortSignal,
|
|
||||||
): Promise<AgentToolResult<TDetails>>;
|
): Promise<AgentToolResult<TDetails>>;
|
||||||
|
|
||||||
/** Custom rendering for tool call display */
|
/** Custom rendering for tool call display */
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ export function wrapRegisteredTool(registeredTool: RegisteredTool, runner: Exten
|
||||||
description: definition.description,
|
description: definition.description,
|
||||||
parameters: definition.parameters,
|
parameters: definition.parameters,
|
||||||
execute: (toolCallId, params, signal, onUpdate) =>
|
execute: (toolCallId, params, signal, onUpdate) =>
|
||||||
definition.execute(toolCallId, params, onUpdate, runner.createContext(), signal),
|
definition.execute(toolCallId, params, signal, onUpdate, runner.createContext()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue