* feat(web-shell): support mutable default mid-turn messages * fix(serve): register mid-turn removal telemetry route * test(serve): update telemetry route totals * fix(test): add session_mid_turn_message_mutation to expected features list * fix(webui): forward clientId on cross-session mid-turn removal (#8229) - Forward the session clientId in the cross-session removeMidTurnMessage branch so the bridge's exact-originator match can succeed; without it the removal resolved to an undefined originator and could never remove the message stamped at enqueue. - Strip a misaligned/malformed messageIds from mid_turn_message_injected in asKnownDaemonEvent instead of rejecting the whole event, mirroring the sidechannel parser so a buggy daemon can't silently lose the injection signal. - Log a mid-turn removal miss in the bridge like the enqueue/pending-removal siblings, to make removal races diagnosable from daemon logs. * fix(web-shell): exclude annotations from mid-turn path and harden idle cleanup (#8229) * fix(web-shell): add container-type to .queuedPrompts so @container query applies (#8229) * fix(web-shell): harden mid-turn dedupe and capability gate per review (#8229) - removeInjectedFromQueue now matches by id first (position-independent) and falls back to text only when no id match exists, so two same-text sends can't remove the wrong row and double-deliver. - Thread canMutateMidTurn into useQueuedPrompts and gate the mid-turn delete/edit mutation on it, so the keyboard path can't hit a DELETE route the daemon doesn't advertise. - asMidTurnMessageInjectedData omits a malformed messageIds key instead of leaving a present undefined, matching the sidechannel parser. - Narrow MidTurnQueueItem.midTurnState, document the load-bearing effect order, and make clearQueuedPrompts return false on a no-op clear. * fix: harden mid-turn removal per review (log escape, cross-session client id) (#8229) - Escape the caller-controlled messageId (and sessionId) in the mid-turn removal-miss stderr line to prevent log injection (CWE-117). - Forward the target session's persisted client id on cross-session mid-turn removal so the bridge's exact-originator match no longer rejects valid removals after a session switch with per-session client ids. - Strengthen tests: distinct-id independence for two queued messages, deferred removal proving the composer waits for daemon removal, and the active-turn delete failed-action flag. --------- Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com> Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
2.5 KiB
Web Shell default mid-turn insertion
Problem
Messages sent while a turn is running are currently admitted as ordinary pending prompts. The UI may then expose a separate insert action, even though the expected send behavior is to make the message available to the running turn automatically.
Behavior
- A plain-text model prompt sent during an active turn is offered to the daemon's mid-turn queue by default.
- The prompt remains visible in the Web Shell queue until the daemon reports that it was actually injected into the running turn.
- The prompt disappears only after that injection event. Acceptance of the enqueue request alone is not treated as insertion.
- If the daemon rejects the mid-turn request, or the active turn becomes idle before injection, the same prompt is submitted as an ordinary next turn.
- Commands and prompts with images continue through the ordinary pending-prompt path because they cannot be represented by the text-only mid-turn API.
- The queue no longer exposes a separate insert action.
State model
An eligible prompt moves through submitting and queued mid-turn states.
Both states keep the row visible. While admission is in flight its actions are
disabled. Once the daemon returns a stable message id, delete and edit operate
on the daemon queue rather than only changing local UI: delete removes the row
after server confirmation, while edit removes it and restores its contents to
the composer. If the message has already left the daemon queue, the action
leaves the row intact until the injection event or idle fallback establishes
its real outcome. An injection event removes the row. Once delete or edit has
been requested, that message is never resubmitted automatically: an idle
fallback removes it for delete or restores it to the composer for edit. A
failed admission or an idle transition atomically claims untouched rows for
ordinary submission so the two fallback paths cannot submit them twice.
The daemon injection event includes stable message ids in addition to the originating client id and message text. New clients reconcile by id; text-based matching remains as a compatibility fallback for older daemons. Reconciliation continues to match only messages from the current client and session, preserving independent queues in other Web Shell clients.
Delete and edit are shown only when the daemon advertises
session_mid_turn_message_mutation. This keeps clients compatible with older
daemons that can accept mid-turn messages but cannot remove them by id.