fix(ai): recover from invalid tool-call input instead of aborting the agent stream#2192
Open
boomyao wants to merge 1 commit into
Open
fix(ai): recover from invalid tool-call input instead of aborting the agent stream#2192boomyao wants to merge 1 commit into
boomyao wants to merge 1 commit into
Conversation
… stream DurableAgent.executeTool threw when a tool call's arguments failed inputSchema validation (and no experimental_repairToolCall fixed it), aborting the whole agent stream — which fails the entire durable workflow run. Tool *execution* errors are already recovered (returned to the model as an error-text tool result so the agent can self-correct); this makes input parse/validation failures consistent: return the error as an error-text tool result instead of throwing, so a single occasionally-malformed model tool-call can no longer kill a long-running task. Aligns with AI SDK streamText behavior. Signed-off-by: yao <zhangyaoruo@outlook.com>
🦋 Changeset detectedLatest commit: 2549cd8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Contributor
|
@boomyao is attempting to deploy a commit to the Vercel Labs Team on Vercel. A member of the Team first needs to authorize it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
In
DurableAgent, the two kinds of tool error are handled in opposite ways insideexecuteTool:execute()throws → caught and converted to anerror-texttool result fed back to the model, so the agent recovers and the stream continues. The code comment even says this "aligns with AI SDK's streamText behavior for individual tool failures."inputSchemavalidation (and noexperimental_repairToolCallfixes them) →throw, which propagates out ofexecuteTool, abortsagent.stream(), and fails the entire durable workflow run.A model occasionally emitting a slightly-malformed tool call (an empty array where
.min(1)is required, a missing required field, a wrong type, truncated-then-JSON-repaired args) is a recoverable event — the model will usually fix it if told. But today it is fatal: one bad tool call kills a long-running task, with no chance for the agent to self-correct. The only hook on this path,experimental_repairToolCall, can't help here because its returned tool call must itself pass the schema — so it can fix malformed JSON syntax but cannot express "tell the model its arguments were invalid and let it regenerate."This is inconsistent (the framework already recovers from the harder case —
execute()throwing) and looks like an oversight rather than intent.Reproduction
Before this PR:
Ashould survive too.Fix
executeToolalready funnels both malformed-JSON and the re-thrown"Invalid input for tool ..."schema-validation error through a singlethrow parseErrorat the end of the parse/validate block. This PR changes that one escape point to return the error as anerror-texttool result — identical to howexecute()errors are handled a few lines below — so the agent receives the error as a tool result and can correct its arguments and retry withinmaxSteps.experimental_repairToolCallstill runs first; only the final give-up changes fromthrowto recover.After this PR, both
AandBprintSTREAM SURVIVED.Notes
maxSteps), consistent withexecute()errors and AI SDKstreamText. Happy to gate it behind an option (e.g.onInvalidToolInput: 'feedback' | 'throw', default'feedback') if you'd prefer to preserve the throw for some callers — let me know.@workflow/aipatch).Verified locally:
packages/aitypecheck clean,vitest run(47 tests) green, Biome clean on the changed files.