Skip to content

fix(shell): allow shell-level slash commands during streaming#1825

Open
AI-fullcup wants to merge 2 commits intoMoonshotAI:mainfrom
AI-fullcup:fix/running-shell-slash-command
Open

fix(shell): allow shell-level slash commands during streaming#1825
AI-fullcup wants to merge 2 commits intoMoonshotAI:mainfrom
AI-fullcup:fix/running-shell-slash-command

Conversation

@AI-fullcup
Copy link
Copy Markdown

@AI-fullcup AI-fullcup commented Apr 10, 2026

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 /task would 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() and handle_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:

    • Added on_running_shell_slash callback parameter to visualize() and passes it to _PromptLiveView.
  • src/kimi_cli/ui/shell/visualize/_interactive.py:

    • _PromptLiveView accepts on_running_shell_slash.
    • During streaming, shell-level slash commands now invoke the callback instead of showing a toast.
    • Soul-level slash commands and regular messages continue to be queued as before.
  • src/kimi_cli/ui/shell/__init__.py:

    • Shell.run_soul_command() provides the callback: it stores the command and sets cancel_event.
    • After run_soul() returns (whether cancelled or naturally finished), _maybe_execute_pending_running_slash_command() runs the pending slash command via _run_slash_command().
  • Tests:

    • Added test_shell_running_slash.py for end-to-end Shell.run_soul_command behavior.
    • Added unit tests in test_visualize_running_prompt.py for handle_local_input and handle_immediate_steer.
    • Updated existing test_visualize_uses_prompt_live_view... to accept the new constructor parameter.

Testing

  • Verified with pytest:
    • tests/ui_and_conv/test_visualize_running_prompt.py — 49 passed
    • tests/ui_and_conv/test_shell_running_slash.py — 2 passed
    • tests/ui_and_conv/test_shell_prompt_router.py — 7 passed
    • tests/ui_and_conv/test_shell_run_placeholders.py — 6 passed

Open with Devin

29448 added 2 commits April 9, 2026 17:38
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.
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +870 to 871
await self._maybe_execute_pending_running_slash_command()
return True
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant