fix(shell): allow shell-level slash commands during streaming#1825
fix(shell): allow shell-level slash commands during streaming#1825AI-fullcup wants to merge 2 commits intoMoonshotAI:mainfrom
Conversation
When an MCP server fails to connect (e.g., due to a port conflict), the Web UI session worker previously crashed entirely, causing messages to get stuck in thinking state indefinitely. Changes: - In `_agent_loop()`, catch `MCPRuntimeError` during `wait_for_background_mcp_loading()` and log a warning instead of letting the exception crash the agent loop. - In `_read_loop()`, when an unexpected exception occurs, clear `_in_flight_prompt_ids` and emit an error status so the frontend can recover instead of leaving prompts stuck in thinking state. Fixes MoonshotAI#1766
Previously, shell-level slash commands like /task entered while the agent was streaming were blocked with a toast saying they were not available during streaming. This left users unable to inspect background tasks or use other shell commands until the turn finished. Now, when a shell-level slash command is submitted during streaming: - The callback cancels the current agent run. - After the run ends (either cancelled or naturally finished), the shell executes the pending slash command immediately. Fixes the issue where /task and similar commands were queued/rejected instead of being handled interactively during a model run.
| await self._maybe_execute_pending_running_slash_command() | ||
| return True |
There was a problem hiding this comment.
🟡 Reload/SwitchToWeb/SwitchToVis caught by generic Exception handler when pending slash command executes inside try block
The _maybe_execute_pending_running_slash_command() call at line 870 is inside the try block (starting at line 760), whose except Exception as e handler at line 928 catches and logs Reload, SwitchToWeb, and SwitchToVis as "Unexpected error" before re-raising. Many shell slash commands raise Reload (e.g., /model, /theme, /resume, /fork — see src/kimi_cli/ui/shell/slash.py:263,493,511,635). When the pending slash command is executed at line 870, these control-flow exceptions are caught by the generic handler, causing a misleading error message ("Unexpected error: reload") and an erroneous export suggestion to be displayed. The call at line 951 (after finally) is correctly outside the try/except.
Race condition that reaches line 870
This code path is reachable due to a race in run_soul (src/kimi_cli/soul/__init__.py:212-216): when the soul task completes normally AND the _on_running_shell_slash callback fires during await cancel_event_task (line 216), run_soul returns normally instead of raising RunCancelled, so line 870 is reached with _pending_running_slash_command set.
Prompt for agents
The _maybe_execute_pending_running_slash_command() call at line 870 is inside run_soul_command's try block. The except Exception handler at line 928 will catch Reload/SwitchToWeb/SwitchToVis exceptions raised by the pending slash command, displaying a misleading 'Unexpected error' message before re-raising.
The simplest fix is to move this call out of the try block. One approach: extract the pending command check to a local variable before the try block's return, then execute it after the finally block (similar to line 951). Alternatively, add an except clause for (Reload, SwitchToWeb, SwitchToVis) that re-raises before the generic except Exception handler, using a local import from kimi_cli.cli (this pattern is already used in _run_slash_command and _maybe_execute_pending_running_slash_command itself).
Was this helpful? React with 👍 or 👎 to provide feedback.
Problem
When the model is streaming (e.g., executing a long-running tool or generating a response), entering a shell-level slash command such as
/taskwould show a toast saying the command is "not available during streaming". The input was effectively dropped, leaving users unable to inspect background tasks or run other shell commands until the current turn completed.Root Cause
In
_PromptLiveView.handle_local_input()andhandle_immediate_steer(), shell-level slash commands detected during streaming were explicitly blocked with a toast and discarded. There was no mechanism to interrupt the current agent run and execute the command.Changes
src/kimi_cli/ui/shell/visualize/__init__.py:on_running_shell_slashcallback parameter tovisualize()and passes it to_PromptLiveView.src/kimi_cli/ui/shell/visualize/_interactive.py:_PromptLiveViewacceptson_running_shell_slash.src/kimi_cli/ui/shell/__init__.py:Shell.run_soul_command()provides the callback: it stores the command and setscancel_event.run_soul()returns (whether cancelled or naturally finished),_maybe_execute_pending_running_slash_command()runs the pending slash command via_run_slash_command().Tests:
test_shell_running_slash.pyfor end-to-endShell.run_soul_commandbehavior.test_visualize_running_prompt.pyforhandle_local_inputandhandle_immediate_steer.test_visualize_uses_prompt_live_view...to accept the new constructor parameter.Testing
pytest:tests/ui_and_conv/test_visualize_running_prompt.py— 49 passedtests/ui_and_conv/test_shell_running_slash.py— 2 passedtests/ui_and_conv/test_shell_prompt_router.py— 7 passedtests/ui_and_conv/test_shell_run_placeholders.py— 6 passed