From f2270cdb63facefb5e03aaeedb00350cedd4c402 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 27 Sep 2026 18:00:25 +0200 Subject: [PATCH] feat(agent): let tools return error results without throwing AgentToolResult.isError marks a result as failed while keeping details and structuredContent, so partial output and structured failures (such as MCP isError results) reach the UI and nested callers. --- packages/agent/src/agent-loop.ts | 2 +- packages/agent/src/types.ts | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/agent/src/agent-loop.ts b/packages/agent/src/agent-loop.ts index 5e25c35ce..029aae278 100644 --- a/packages/agent/src/agent-loop.ts +++ b/packages/agent/src/agent-loop.ts @@ -936,7 +936,7 @@ async function executePreparedToolCall( ); acceptingUpdates = false; await Promise.all(updateEvents); - return { result, isError: false }; + return { result, isError: result.isError === true }; } catch (error) { acceptingUpdates = false; await Promise.all(updateEvents); diff --git a/packages/agent/src/types.ts b/packages/agent/src/types.ts index 44617bb66..89c0ad5ab 100644 --- a/packages/agent/src/types.ts +++ b/packages/agent/src/types.ts @@ -447,6 +447,12 @@ export interface AgentToolResult { structuredContent?: JsonValue; /** Usage from the final tool execution itself, if available. Not used for main LLM context accounting. */ usage?: Usage; + /** + * Report a failure without throwing. The model sees `content` as an error result, like a thrown + * error, but `details` and `structuredContent` are kept, so the UI and programmatic callers can + * still read partial output or a structured failure (for example an MCP result with `isError`). + */ + isError?: boolean; /** * Hint that the agent should stop after the current tool batch. * Early termination only happens when every finalized tool result in the batch sets this to true. @@ -511,7 +517,8 @@ export interface AgentTool