docs(coding-agent): clarify that tool errors must be thrown, not returned

Returning { isError: true } from a tool's execute function was silently
ignored - the agent loop only sets isError via the catch block. Fix the
with-deps example to throw instead, add a clear note in the Tool Definition
docs section, and update the Error Handling summary.

closes #1881
This commit is contained in:
Mario Zechner
2026-03-06 14:36:18 +01:00
parent e4172e68d0
commit b079003cf6
3 changed files with 15 additions and 6 deletions

View File

@@ -9,6 +9,7 @@
### Fixed
- Fixed `/new` leaving startup header content, including the changelog, visible after starting a fresh session ([#1880](https://github.com/badlogic/pi-mono/issues/1880))
- Fixed misleading docs and example implying that returning `{ isError: true }` from a tool's `execute` function marks the execution as failed; errors must be signaled by throwing ([#1881](https://github.com/badlogic/pi-mono/issues/1881))
## [0.56.2] - 2026-03-05

View File

@@ -1340,6 +1340,18 @@ pi.registerTool({
});
```
**Signaling errors:** To mark a tool execution as failed (sets `isError: true` on the result and reports it to the LLM), throw an error from `execute`. Returning a value never sets the error flag regardless of what properties you include in the return object.
```typescript
// Correct: throw to signal an error
async execute(toolCallId, params) {
if (!isValid(params.input)) {
throw new Error(`Invalid input: ${params.input}`);
}
return { content: [{ type: "text", text: "OK" }], details: {} };
}
```
**Important:** Use `StringEnum` from `@mariozechner/pi-ai` for string enums. `Type.Union`/`Type.Literal` doesn't work with Google's API.
### Overriding Built-in Tools
@@ -1880,7 +1892,7 @@ const highlighted = highlightCode(code, lang, theme);
- Extension errors are logged, agent continues
- `tool_call` errors block the tool (fail-safe)
- Tool `execute` errors are reported to the LLM with `isError: true`
- Tool `execute` errors must be signaled by throwing; the thrown error is caught, reported to the LLM with `isError: true`, and execution continues
## Mode Behavior

View File

@@ -21,11 +21,7 @@ export default function (pi: ExtensionAPI) {
execute: async (_toolCallId, params) => {
const result = ms(params.duration as ms.StringValue);
if (result === undefined) {
return {
content: [{ type: "text", text: `Invalid duration: "${params.duration}"` }],
isError: true,
details: {},
};
throw new Error(`Invalid duration: "${params.duration}"`);
}
return {
content: [{ type: "text", text: `${params.duration} = ${result} milliseconds` }],