Agent loop stops after first tool call with non-Claude models (GLM-5): generateSandboxedUi never invoked
維護者通常 1 天內回覆
還沒有人認領這個 Issue。
評估
- 難度
- 4/5
- 預估耗時
- 3-5 天
- 新手友好度
- 48/100
- Issue 類型
- 缺陷
- 描述清晰度
- 基本清楚
- 活躍度
- 冷清
- 技術堆疊
- python, typescript
研究方向
Reproduce the issue using apps/agent/src/model.py and its build_model() configuration for GLM-5. Trace the tool-call continuation after plan_visualization through deepagents, CopilotKitMiddleware, and ag-ui-langgraph, using the reported _generate/_agenerate and HTTP-request observations as checkpoints. Done means a second LLM request invokes generateSandboxedUi and the UI renders an iframe.
由索引模型根據 Issue 內容生成。
描述
Summary
When using a non-Claude OpenAI-compatible model (tested with GLM-5 via Zhipu coding endpoint https://open.bigmodel.cn/api/coding/paas/v4), the agent correctly calls plan_visualization on the first LLM turn but never proceeds to a second LLM turn to call generateSandboxedUi. The result is that the user sees the assistant's text description of the widget that "would" be built, but no sandboxed iframe is ever rendered (0 iframes in the DOM).
The README warns that "weaker models will produce broken layouts", but this is a different failure mode: GLM-5 successfully generates a complete, valid widget when prompted directly (9.6 KB of JS, all 6 generateSandboxedUi parameters emitted in the correct order). The failure is not model capability — it's that the agent loop doesn't give the model a second turn after the plan_visualization tool returns.
Environment
- Repo commit:
457e60c(currentmainas of 2026-07-18) - Model:
glm-5(Zhipu coding endpoint), wired in vialangchain_openai.ChatOpenAIwithLLM_MODEL=glm-5,LLM_PROVIDER=openai - Python 3.13, Node 24, pnpm 10, uv
- macOS Darwin 25.5.0
- Same behavior on fresh thread (cleared localStorage + reopened browser)
Repro
- Replace
apps/agent/src/model.pybuild_model()so thatLLM_MODEL=glm-5+LLM_PROVIDER=openairoutes toChatOpenAIwith the Zhipubase_url. make setup+make dev.- Open http://localhost:3000, type "Draw binary search visualization".
- GLM-5 replies with text + calls
plan_visualization. UI shows the "✓ Plan: visualization" pill. - Nothing else happens. No iframe, no
generateSandboxedUiactivity event.
Evidence
What the agent loop sees (first LLM turn) — captured by monkey-patching bind_tools on the model:
[MODEL_DEBUG] bind_tools (19): ['write_todos', 'ls', 'read_file', 'write_file', 'edit_file', 'glob', 'grep', 'task', 'query_data', 'plan_visualization', 'manage_todos', 'get_todos', 'generate_form', 'generateSandboxedUi', 'toggleTheme', 'pieChart', 'barChart', 'scheduleTime', 'render_a2ui']
generateSandboxedUi IS in the offered tools. GLM-5 returns:
finish_reason: tool_calls
content: "I'll create an interactive binary search visualization that shows how the algorithm narrows down the search space step by step. Let me plan and build this for you."
tool_calls: [plan_visualization(approach=..., technology=..., key_elements=[...])]
After plan_visualization returns its string, no further LLM call is made — verified by hooking both _generate / _agenerate and the underlying httpx client; zero additional HTTP requests to /chat/completions after the first turn.
Direct replay against GLM-5 API with the same system prompt + same tool list + the plan_visualization tool result already in messages:
messages = [
{"role":"system","content":"You MUST call generateSandboxedUi now that plan is done."},
{"role":"user","content":"Draw binary search visualization"},
{"role":"assistant","content":"I'll build this.","tool_calls":[{"id":"call_1",...,"function":{"name":"plan_visualization","arguments":"..."}}]},
{"role":"tool","tool_call_id":"call_1","content":"Plan: step-by-step\nTech: SVG\n- array\n- pointers\n- controls"},
]
GLM-5 returns:
finish_reason: tool_calls
content: "" (empty)
tool_calls: [generateSandboxedUi(
initialHeight=580,
placeholderMessages=[3 items],
css="<3201 chars>",
html="<2086 chars>",
jsFunctions="<9673 chars>", # full binary search algorithm + UI
jsExpressions=["<347 chars>"]
)]
usage: completion_tokens=4839 (incl. 87 reasoning_tokens)
So the model is fully capable of producing the widget in a single shot once the plan_visualization tool result is fed back — but the agent loop never feeds it back.
Hypothesis
When finish_reason=tool_calls and content is non-empty simultaneously (GLM-5's default style — it emits a short sentence alongside the tool call), some layer in deepagents + CopilotKitMiddleware + ag-ui-langgraph appears to treat the message as a final response and does not run the tool-→-LLM-continue cycle. Claude models, per the README's recommended config, apparently emit plan + widget in a single turn or in a way that sidesteps this path; GLM emits them across two turns and gets stuck between.
I tried to nail down the exact layer but the LangChain 1.x callback surface (on_chat_model_start etc.) doesn't fire for the calls that GLM-5 actually answers, so I couldn't trace whether deepagents ran the second turn and it was dropped at the CopilotKit middleware, or whether deepagents itself never re-entered the model.
Suggested fixes / things to try
- Force a second LLM turn after
plan_visualizationeven when the first turn's message has bothcontentandtool_calls. The current behavior looks like a short-circuit on "has content → treat as final". - Or allow
plan_visualizationto be skipped so a model that prefers to callgenerateSandboxedUidirectly can do so in a single turn. - Or document explicitly that non-Claude models must emit
plan_visualizationandgenerateSandboxedUiin a single assistant turn, with a system-prompt nudge that makes GLM/etc. do that. - Investigate whether
ag-ui-langgraphorCopilotKitMiddlewareis the layer that drops the continuation — happy to dig further if a maintainer can point me at where to instrument.
Reproducibility script
I have a self-contained Python script that hits GLM-5 directly with the same tool schemas and prompts, reproducing the "2-turn happy path" reliably — can paste it in if useful.
Why I'm reporting this
The project is marketed as "open-source showcase for AI-generated UI" and the README explicitly supports gpt-* fallback via LLM_MODEL. Any user trying it with a non-Claude OpenAI-compatible endpoint (GLM / DeepSeek / Qwen / Kimi / MiniMax / etc.) will hit this silent half-failure and conclude the model is too weak, when in fact it's an agent-loop bug. Worth either fixing or documenting.
- 主要語言
- TypeScript
- 星號
- 3.9k
- 分支
- 414
- 平均合併
- 4 小時
- 30 天內合併 PR
- 6
環境準備
- 沒有 Dockerfile 或 Docker Compose 檔案
- 沒有 Pull Request 範本
- 閱讀貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
CopilotKit/OpenIntelligentUI 的其他 Issue
-
Script dedup key truncation may cause collisions可能已有人在做 @saschabuehrle 於 220 天前認領。 未關閉bug
難度 2/5 1-3 小時 新手友好度 72/100
CopilotKit/OpenIntelligentUI#37 ·
維護者通常 1 天內回覆
-
enhancement
難度 2/5 1-3 小時 新手友好度 72/100
CopilotKit/OpenIntelligentUI#29 ·
維護者通常 1 天內回覆
-
Self-host with Docker Compose and optional server-held keys可能已有人在做 @kannan983 於 20 天前認領。 未關閉
難度 4/5 3-5 天 新手友好度 18/100
CopilotKit/OpenIntelligentUI#98 ·
維護者通常 1 天內回覆
-
Support OpenAI-compatible gateways (OpenRouter) via vendor/model names可能已有人在做 @kannan983 於 20 天前認領。 未關閉
難度 2/5 1-3 小時 新手友好度 25/100
CopilotKit/OpenIntelligentUI#97 ·
維護者通常 1 天內回覆
-
UI未關閉
難度 5/5 一週以上 新手友好度 8/100
CopilotKit/OpenIntelligentUI#96 ·
維護者通常 1 天內回覆
查看 CopilotKit/OpenIntelligentUI 的全部 Issue
相似的 Issue
-
bug
難度 1/5 1 小時以內 新手友好度 86/100
awslabs/visual-asset-management-system#937 ·
維護者通常 1 天內回覆
-
t0ggles
難度 1/5 1 小時以內 新手友好度 82/100
nolimits4web/swiper#8255 · 1 則留言 ·
維護者通常 15 天內回覆
-
render: --variables-file (and --variables <path>) fails with "io.readFile is not a function" since 0.8.212可能已有人在做 @miguel-heygen 今天認領。 未關閉bug triage/needs-triage
難度 2/5 1-3 小時 新手友好度 76/100
heygen-com/hyperframes#6830 ·
維護者通常 1 天內回覆
-
bug launch local use
難度 2/5 1-3 小時 新手友好度 65/100
維護者通常 1 天內回覆
-
account: profile bug
難度 2/5 1-3 小時 新手友好度 78/100
維護者通常 5 天內回覆