Conversation
…re the SDK parses them Deeply nested tool-call input (observed at depth ~1200/2100 in the app) aborts the turn in AI SDK 7: parseToolCall's outer catch re-parses the raw text even for an INVALID call and cloneModelMessages then recursively clones the deep object at step finish (RangeError, surfaced as a bogus context_exceeded). With a permissive schema (z.record / passthrough) the deep payload was even executed. - toolInputDepthGuardMiddleware (v4; innermost wrap in ProviderModelFactory, DevTools outside so it records what the SDK saw): a non-recursive, string/escape-aware scanner bounds the raw `tool-call.input` text and replaces over-deep input with an intentionally INVALID JSON diagnostic, so the SDK stamps the call `invalid` (never executed regardless of schema) and the model receives the normal invalid-input tool error. `tool-input-delta` text passes through untouched; nothing parses it. - MAX_TOOL_PAYLOAD_JSON_DEPTH = 256: a policy safety bound below the observed V8/SDK failures (app ~1200; in-process Node 22 harness ~4000). - Node/Jest regression (tests/ipc/streaming/toolPayloadDepth.test.ts, live half): 1200/2100/4000/6000 rejected and never executed with a permissive schema, turn settles; depth 2 and 256 execute unchanged; quoted/escaped brackets are not nesting. Bun unit test for the scanner and the invalid-JSON invariant of the diagnostic. - providerModelFactory test no longer asserts the concrete model class (the `<name>.chat` provider id already proves adapter selection). Persisted rows that already hold a deep payload are handled by the follow-up history layer. _Generated with `xum` • Model: `coder:anthropic/claude-fable-5-1` • Thinking: `xhigh`_ <!-- mux-attribution: model=coder:anthropic/claude-fable-5-1 thinking=xhigh --> Signed-off-by: Thomas Kosiewski <tk@coder.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0760d7b032
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
ThomasK33
added this pull request to stack #4340
September 22, 2026 15:16
…, not only v4 Review finding (PR #4336): createModelEffect returned early for any non-v4 model, so the CopilotResponses model (v2) and any v3 provider never received the depth guard and a permissive schema executed deep tool input unguarded. - Wrap every object model with the guard middleware. wrapLanguageModel runs the SDK's own asLanguageModelV4 adapters (v2→v3→v4) — the same adaptation streamText/generateText perform before consuming the model — so no new adapter is introduced. Cleanup ownership moves to the wrapper as before. - DevTools keeps its existing constraint, now gated on the core model's version because the guard wrapper always reports v4. turnRequestBuilder's run-metadata queue keys entries per request and the request clears them, so a queued entry nothing consumes cannot leak into another run. - Tests: actual factory route for github-copilot Codex (v2 CopilotResponses) via generateText with a permissive tool — depth-2100 arguments are turned into an invalid call and never executed (red on the C1 base: executed), shallow arguments execute unchanged; Jest live suite adds v2/v3 mock models through the same wrap (deep rejected, shallow executes). The two Copilot assertions on the concrete class now check the adapted v4 wrapper via its provider id. _Generated with `xum` • Model: `coder:anthropic/claude-fable-5-1` • Thinking: `xhigh`_ <!-- mux-attribution: model=coder:anthropic/claude-fable-5-1 thinking=xhigh --> Signed-off-by: Thomas Kosiewski <tk@coder.com>
This branch has not been deployed
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.
Summary
Reject tool calls whose JSON input exceeds the chosen nesting limit before the AI SDK parses it. The model receives the normal invalid-input tool error instead of a stack overflow, and the rejected call does not execute—even with a permissive tool schema.
This is the live-input prerequisite for #4317. Recovery of already-persisted deep payloads is a separate layer above this one.
Review focus
jsonTextExceedsDepthscans the raw text without recursion and ignores quoted/escaped brackets.ProviderModelFactoryinstalls the guard before SDK parsing. Every object-model version receives the guard through the SDK’s existing adapters, including Copilot Responses v2. DevTools retains its prior core-v4 scope outside the guard, and model cleanup ownership is transferred.Validation
The native-Node regression exercises depths 1200, 2100, 4000, and 6000 through the real streaming service. It checks zero tool executions, normal turn completion, and an error result in the next provider request. Depths 2 and 256 and quoted-bracket inputs remain controls.
On
89ed0a7553f1be668f2f967b093edafbab8234d5:make static-checkpassed, 188 focused Bun tests passed, and all 13 native-Node integration cases passed. A real Copilot Responses factory-route regression first demonstrated deep-input execution on the previous head; the guarded route now rejects it while its shallow control executes. Streaming v2/v3 adapter coverage uses test models, not live external providers. The current gateway SDK is v4; no real v3 factory route is claimed. Bun 1.3.5, Node 22.19.0, and main's frozen AI SDK 7.0.107 dependencies were used. Combined remote UAT and the stack's code/security reviews and CI remain merge gates.Compatibility
256 is an explicit safety policy, not a claim about every external tool. Calls above that nesting limit now fail explicitly. This layer does not repair existing history or add persistence, UI, or provider settings.
Generated with
xum• Model:coder:openai/gpt-6-astra• Thinking:xhigh• Cost:$760.34