Skip to content

fix(ai): respect failureMode when tool-call parameter decoding fails#6432

Open
tsushanth wants to merge 1 commit into
Effect-TS:mainfrom
tsushanth:fix/ai-tool-failuremode-param-decode
Open

fix(ai): respect failureMode when tool-call parameter decoding fails#6432
tsushanth wants to merge 1 commit into
Effect-TS:mainfrom
tsushanth:fix/ai-tool-failuremode-param-decode

Conversation

@tsushanth

Copy link
Copy Markdown
Contributor

Summary

Closes #6335

When a language model returns tool-call parameters that fail schema validation, the decode error was thrown before the handler queue was set up, bypassing the failureMode gate entirely. This meant failureMode: "return" had no effect for parameter errors — the effect always propagated the failure.

Root cause

Two decode sites were responsible:

  1. LanguageModel.ts — The Response.StreamPart / Response.Part decoders were applied to the raw LLM output before routing to Toolkit.handle. A parameter schema mismatch here caused an immediate effect failure, skipping handle completely.

  2. Toolkit.ts — Inside handle, decodeParameters failed with an uncaught error before the queue existed, so the failureMode check in Stream.catch was never reached.

Fix

Site 1: Pass { relaxParams: true } to Response.StreamPart/Response.Part for the tool-resolution decode pass. This substitutes Schema.Unknown for tool.parametersSchema, allowing raw params through to handle regardless of shape.

Site 2: Wrap decodeParameters in Effect.matchEffect. On failure, check tool.failureMode:

  • "error" → propagate via Effect.fail (existing behavior)
  • "return" → encode the AiError via schemas.encodeResult and emit it as a tool-result stream with { result, encodedResult, isFailure: true, preliminary: false }

Tests updated

Two existing tests asserted the old broken behavior (expecting Effect.flip to yield an AiError for parameter errors on failureMode: "return" tools). Updated them to assert the correct behavior: the effect succeeds and response.toolResults contains a part with isFailure: true and the encoded validation error.

Tool-call parameter decode errors were thrown before the handler queue
existed, bypassing the failureMode gate entirely. Both the streaming and
generateText paths now use a relaxed schema (Schema.Unknown) for the
initial LLM-output decode pass, deferring strict validation into
Toolkit.handle where failureMode is available.

When decoding fails inside handle, failureMode:"return" now emits a
tool-result part with isFailure:true and the encoded AiError instead of
propagating the error as an effect failure. failureMode:"error" (and the
default) continues to fail the effect as before.

Updated two tests that were asserting the old broken behavior.

Fixes Effect-TS#6335
@github-project-automation github-project-automation Bot moved this to Discussion Ongoing in PR Backlog Jul 16, 2026
@changeset-bot

changeset-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: e8f23c8

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@IMax153 IMax153 added the 4.0 label Jul 16, 2026
@IMax153
IMax153 self-requested a review July 16, 2026 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Discussion Ongoing

Development

Successfully merging this pull request may close these issues.

unstable/ai: tool-call parameter decode failure bypasses failureMode: "return" and kills the whole streamText stream

2 participants