* feat(web-shell): run read-only info commands immediately mid-turn
/stats, /about (/status) and /context were silently swallowed while a
turn was streaming, because their local user echo would act as a turn
boundary in applyTurnCollapse and split the active turn. Their output
is a status block, which is not a turn boundary and is not counted in
turn metrics, so only the echo needs to be skipped mid-turn.
Add appendLocalUserEchoIfIdle, which echoes when idle and skips the
echo while streaming without blocking the command, and switch these
three commands to it so their results render inline immediately even
during an active turn.
* fix(web-shell): keep streaming assistant block intact for mid-turn info commands
Address PR review. A status dispatch finalizes the active assistant
block by default, so running /stats, /about or /context mid-turn would
fragment the streaming answer around the status card and drop later
usage frames. Add an optional clearActiveText flag to the status event
and pass false from these three command dispatches, covered by
reducer-level tests.
Also collapse the echo gate into a single body (the new helper now
delegates to appendOrDeferLocalUserMessage), add App-level wiring tests
for the responding/idle behavior of /stats and /about, and surface
failed getStats via reportError instead of swallowing them.
* fix(web-shell): reset the echo user block when info output keeps streaming (#8496)
The clearActiveText: false opt-out skipped the whole clearActiveText call,
leaving the local command echo as the active user block indefinitely. A
peer client's prompt echo then merged into it, corrupting turn boundaries.
Keep the streaming assistant/thought block open on the opt-out path but
still drop the user pointer.
Also report /about load failures like /stats and /context already do, and
pin the new /context wiring plus the /stats failure path with tests.
* refactor(web-shell): centralize the mid-turn read-only status dispatch (#8496)
Address the round-3 review feedback on the mid-turn read-only commands:
- The read-only result dispatch (status block with clearActiveText:
false plus the follow-resume) was copied verbatim at the /context,
/stats, and /about sites, leaving the load-bearing flag enforced by
convention at three places. Centralize it in one
dispatchReadOnlyStatus callback next to echoLocalCommandIfIdle; the
three .then bodies now call it with their serialized text.
- Pin the /about catch the way the sibling /stats catch is pinned:
make collectSystemInfo throw once and assert the failure surfaces
through console.error instead of becoming an unhandled rejection
with zero user feedback.
* test: pin thought opt-out and serialized mid-turn status payloads (#8496)
* refactor(web-shell): consolidate read-only command echo into echoOrDeferLocalCommand (#8496)
* test(web-shell): cover /status routing and document the echo-suppression exception (#8496)
---------
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
* fix(web-shell): defer transcript-appending local commands while a turn streams
Local slash commands that echo into the transcript (/context, /stats,
/status, /bug, /model --voice, /skills, /tools, /extensions) appended a user
message mid-turn, which applyTurnCollapse treats as a turn boundary — splitting
the active turn and corrupting its tool/thinking/token counts.
Route these echoes through a single choke point (appendOrDeferLocalUserMessage):
while a turn streams they defer to the prompt queue and re-dispatch as their own
clean turn once it settles. showContextUsage self-guards so the keyboard,
status-bar button and in-chat "context detail" click are all covered.
/extensions install defers via a top-of-branch guard, replacing its bespoke
"wait for turn" message.
* fix(web-shell): disable queue "insert" for command entries
The queue's "insert" action injects a queued message's raw text into the
running turn via enqueueMidTurnMessage; for a slash/shell command the model
would only see the literal "/context …" and the command would never run.
Disable (grey out) the insert action for command entries and guard the
handler, so commands only run when the queue drains and re-dispatches them
through handleSubmit. Plain prompts are unaffected.