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:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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` }],
|
||||
|
||||
Reference in New Issue
Block a user