Repository navigation
Conversation
This was referenced Oct 10, 2026
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
When the agent runs with server-held keys from
apps/agent/.env, every interactive (generateSandboxedUi) answer is garbled or interrupted, whichever model is used. Text answers look fine. BYOK browser keys don't take this code path, which is probably why it went unnoticed.Symptom
Widgets render with duplicated text and raw tag fragments, or the chat shows "Something interrupted the answer". The runtime logs:
The raw AG-UI stream from the agent has two
TOOL_CALL_STARTevents for the same tool call, and every args delta appears twice, so the concatenated args aren't valid JSON:Root cause
CredentialScopedModeldelegates through the provider model's publicastream(...)/invoke(...), afterbind_toolswraps it in aRunnableBinding. Inside a LangGraph node, that nested call inherits the node's callbacks throughvar_child_runnable_config. So the provider model reportson_chat_model_streamevents and the wrapper reports the same chunks again. Passing{"callbacks": []}doesn't help, becausemerge_configsadds a list onto an inherited callback manager instead of replacing it.With browser keys,
request_modelreturns a plainChatOpenAI, which is called directly, so the duplication never happens.Fix
CredentialScopedModelnow unwraps theRunnableBinding(merging its bound kwargs, e.g. tools) and calls the provider's_generate/_agenerate/_stream/_astreamdirectly. Only the wrapper's own run reports events. Models without streaming support fall back to a single generation chunk, as before.Testing
test_credential_scoped_model_streams_each_chunk_once: wraps the model in aRunnableLambda(as a LangGraph node does) with bound tools and collectson_chat_model_streamtokens. Without the fix it produces'aa bb cc'; with the fix,'a b c'.uv run --directory apps/agent pytest: 112 passedTOOL_CALL_STARTper call, and the args parse as JSON with all sixgenerateSandboxedUifields.anthropic/claude-sonnet-5.5anddeepseek/deepseek-v4.1-flashvia an OpenAI-compatible gateway (LLM_MODELrouting from feat(agent): support OpenAI-compatible gateways via vendor/model names #100). Before the fix, "Make an interactive loan EMI calculator" was garbled or interrupted. After it, the widget streams and renders fully, its controls work, and a follow-up question about the widget's values is answered correctly.Related observation (not changed here)
The runtime server also logs
Failed to apply activity patch ...: a.applyPatch is not a function. Under Node,@ag-ui/client'simport * as a from "fast-json-patch"resolves to the CommonJS entry, whoseObject.assign(exports, ...)exports Node can't detect. I tested with and without a fix for this: widgets and follow-up turns behave the same, because the error is caught and the browser bundle resolves the ESM build. So it looks like log noise only, and I've left it out of this PR. I'm happy to open a separate issue if you'd like it tracked.