fix: keep working spinner alive until all parallel tool calls finish#183
fix: keep working spinner alive until all parallel tool calls finish#183mikenorgate wants to merge 1 commit intomasterfrom
Conversation
The upstream ui.ts stops the working animation on message_start, which fires when assistant text begins streaming. With parallel tool calls (Kimi K2.5+, deepseek, etc.) the message starts before all tool results return, causing the indicator to flash and disappear while tools are still executing. Fix by tracking in-flight tool calls with a counter. message_start now only stops the animation when toolsInFlight === 0. tool_execution_start increments the counter and restarts the animation; tool_execution_end decrements it and hides the indicator only when the counter reaches zero. LLM-1574 Co-Authored-By: Kimchi <noreply@kimchi.dev>
Kimchi Code Review
Summary📊 Review Score: 90/100 (overall code quality — 0 lowest, 100 highest) 🧪 Tests: no — No tests were added or modified for the new No significant issues found. LGTM! 🎉 What to expectKimchi will analyze the changes in this pull request and post:
The review typically completes within a few minutes. This comment will be updated once the review is ready. Interact with Kimchi
ConfigurationReviews are configured by your organization admin. Powered by Kimchi — AI-powered code review by CAST AI |
There was a problem hiding this comment.
📊 Review Score: 90/100 (overall code quality — 0 lowest, 100 highest)
⏱️ Estimated effort to review: 1/5 (1 = trivial, 5 = very complex)
🧪 Tests: no — No tests were added or modified for the new tool_execution_end handler or the toolsInFlight counter logic.
No significant issues found. LGTM! 🎉
What
Fix LLM-1574 — Kimi K2.5+ models execute tool calls correctly but the TUI shows zero progress during execution. With Claude the working spinner appears; with Kimi the session appears frozen.
Why it happened
The upstream
ui.tsstops the working animation onmessage_start, which fires when assistant text begins streaming. With parallel tool calls (Kimi K2.5+, deepseek, etc.) the message starts before all tool results return, causing the indicator to flash and disappear while tools are still running.Fix
Track in-flight tool calls with a counter in
src/extensions/ui.ts:tool_execution_start— increment counter, restart animationtool_execution_end— decrement counter, hide indicator only when counter reaches 0message_start— only stop animation whentoolsInFlight === 0session_start— reset counter to prevent stale stateUses the existing orange spinner. No Kimi-specific code — works for any model doing parallel tool calls.
Verification
pnpm run typecheck✅pnpm run lint✅pnpm run test✅ (1161 passed)Related
Ghost pending indicator (separate upstream bug): Kimi parallel calls expose a rendering race in
ToolExecutionComponent.updateDisplay()— the pending call renderer is unconditionally added to the render container even when a result exists, leaving ghost spinners above completed blocks. Fix belongs upstream in pi-coding-agent, tracked separately.LLM-1574
Kimchi Summary
What changed
Fixes premature dismissal of the working indicator when assistant messages arrive while parallel tool calls are still executing. The UI extension now tracks in-flight tools and delays hiding the indicator until all active tool executions complete.
Why
Parallel tool calling (used by Kimi K2.5+, DeepSeek, and others) allows assistant messages to stream before all tool results return. Stopping the spinner on
message_startcaused a brief flash-and-clear while tools remained active.Key changes
src/extensions/ui.ts: AddedtoolsInFlightcounter to track active parallel tool executions.src/extensions/ui.ts: ResettoolsInFlightto0onsession_start,turn_start, andagent_end.src/extensions/ui.ts: Addedpi.on("tool_execution_start")handler to increment the counter and show the working indicator.src/extensions/ui.ts: Addedpi.on("tool_execution_end")handler to decrement the counter and hide the indicator only whentoolsInFlightreaches zero.src/extensions/ui.ts: Guarded themessage_startanimation stop so it only fires whentoolsInFlight === 0.Impact