Repository navigation
fix(core): return bad tool params to the model instead of ending the run - #57
Merged
Merged
Conversation
With tool resolution disabled, streamText decodes each tool call's params against the tool's schema while it reads the reply, so one bad call failed the reply and ended the run. The tools handed to streamText now accept any params there; Fold's toolkit.handle checks them when it runs the tool and returns a failed tool result the model can fix. Providers still build the same JSON schema, since only setParameters changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> HumanLayer-Session: https://app.dev.codelayer.gg/sessions/01a1196a-ea93-79e6-9500-a2651678f1ea
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
When the model sends a tool call whose params don't match the tool's schema (for example a missing required key), the whole run ends with an error. The model should get a failed tool result instead, so it can fix the call and carry on.
This happened live in effect-channels: the agent called
update_planwithouttitleand the run ended withMissing key at ["title"].Cause
Fold calls
languageModel.streamText({ ..., disableToolCallResolution: true })(AgentRuntimeLayer.ts). In that mode,streamTextdecodes each tool call's params againsttool.setParameters(Schema.toEncoded(tool.parametersSchema))while it reads the reply (effect/src/ai/LanguageModel.ts:1542,2424). A bad call fails the reply, so Fold writes an error entry and ends the run.Fold's own
toolkit.handlealready checks params when it runs the tool, and turns a bad call into a failed tool result. It never got the chance.Fix
The tools handed to
streamTextaccept any params while the reply is read. Each one is a copy of the tool whosesetParametersreturnstool.setParameters(Schema.Unknown). That's the same thingstreamTextdoes when it runs the tools itself.Nothing else on the tool changes. Providers build the JSON schema from the unchanged
parametersSchema, so OpenAI and Anthropic still apply their schema transforms, and the model sees the same schema as before.Why not use
Tool.dynamicwith a precomputed JSON schema? Providers skip their transforms for dynamic tools, which changes the schema OpenAI and Anthropic models see.Tests
AgentRuntimeToolParams.vi.test.ts: the model callsechowith{ txet: 'hi' }. The run completes, the tool result is aToolParameterValidationErrorreadingMissing key at ["text"], and the model is still offered the realechoschema. The test fails without the fix (outcomeerror).bun run testin fold-core: 332 passed. Typecheck, oxlint, oxfmt and typed-lint are clean.🤖 Generated with Claude Code