feat(web-shell): expose transcript event changes - #5193
Conversation
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
[Suggestion] Stale comment at DaemonSessionProvider.tsx:636 — the comment reads "If replay has events but no terminal signal..." but the code now checks hasReplayUserMessage (only user_message_chunk), not replayEvents.length > 0. Consider updating to "If replay has a user message but no terminal signal..." to match the narrowed condition.
— qwen3.7-max via Qwen Code /review
chiga0
left a comment
There was a problem hiding this comment.
Overview
Final Verdict: Approve — Focused, well-tested PR that adds a transcript change callback and tightens replay prompt-status recovery. The second commit (048ccd0a) addresses all suggestions from the earlier automated review.
Cross-Validation
| # | Finding | Reviewer | My Assessment |
|---|---|---|---|
| C1 | Stale comment at line 636 ("If replay has events…") | qwen-code-ci-bot | Fixed at HEAD — commit 048ccd0a updated to "If replay has a user message but no terminal signal" |
| C2 | Naming: onEventChange → onTranscriptChange |
qwen-code-ci-bot | Fixed at HEAD — prop is onTranscriptChange |
| C3 | Missing positive-branch test for replay user_message_chunk | qwen-code-ci-bot | Fixed at HEAD — test "marks replayed user turns without terminal events as waiting" present |
| C4 | JSDoc missing debounce/throttle warning | qwen-code-ci-bot | Fixed at HEAD — JSDoc includes "fires on every streaming delta during active generation, so consumers should debounce or throttle expensive work" |
No unique findings from my independent review.
Additional Audit Coverage
Areas I independently checked beyond existing findings:
- useEffect correctness: verified
[blocks, onTranscriptChange]deps are complete; effect firesonTranscriptChange?.(blocks)safely via optional chaining when prop is omitted isUserMessageEventtype narrowing:ascast withnull | undefinedunion + optional chaining is defensive and consistent with codebase patterns; discriminator fieldsessionUpdateis the canonical one used elsewhere- Replay recovery semantics: the change from
replayEvents.length > 0tohasReplayUserMessagecorrectly prevents false "waiting" state when replay contains only assistant messages without a terminal event — the old condition would have triggered a loading indicator flicker for completed conversations - Callback frequency design: confirmed
blocks(raw fromuseTranscriptBlocks()) is intentionally passed, notmessageBlocks(animation-frame throttled) — consumers get full-fidelity data for logging/sync, with the JSDoc warning them to debounce - Test quality: negative test uses
agent_message_chunk(the most likely false-positive trigger), positive test correctly assertspromptStatus === 'waiting'— together they bracket the condition inversion regression - Consistency with sibling callbacks:
onTranscriptChangefollows the same pattern asonStreamingStateChangeandonConnectionChange(prop declaration, destructure, useEffect dispatch)
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No review findings. Downgraded from Approve to Comment: CI still running.
The two changes are well-executed:
-
Replay status fix: Correctly narrows the prompt-status seeding from "any replay events" to "replay contains a user message". The
isUserMessageEventhelper follows established patterns in the file. Both branches (negative: agent-only replay stays idle, positive: user-message replay becomes waiting) are covered by the new tests. -
onTranscriptChangecallback: Follows the identicaluseEffectpattern as the siblingonStreamingStateChangeandonConnectionChangecallbacks. Dependencies are correct. The JSDoc appropriately warns consumers about streaming-frequency firing.
Builds (webui, web-shell) and all 75 tests in DaemonSessionProvider.test.tsx pass. ESLint and tsc clean on changed files. — qwen3.7-max via Qwen Code /review
yiliang114
left a comment
There was a problem hiding this comment.
Reviewed the transcript callback and replay-status changes, including resolved review threads and CI status. The scope is focused and the tests cover the relevant replay branches; no blocking issues found.
What this PR does
This PR adds a web-shell callback that lets host applications observe transcript block changes as the shell processes user, assistant, and tool events. It also tightens prompt-status recovery during daemon replay so replayed non-user events do not incorrectly mark a fresh prompt as waiting.
Why it's needed
Consumers embedding web-shell need a direct way to react to the transcript/event stream without reimplementing the shell's internal transcript reducer. Separately, replay recovery should only infer an in-progress prompt when replay contains a user message without a terminal event; otherwise a new session or non-turn replay can briefly look like a prompt is still running.
Reviewer Test Plan
How to verify
Use web-shell with an
onEventChangecallback and confirm it receives the full transcript blocks array whenever the displayed transcript changes after user, assistant, or tool activity. Resume or create a session whose replay snapshot contains only non-user session updates and confirm the prompt status stays idle instead of showing a waiting/in-progress state.Evidence (Before & After)
N/A for screenshots. Local verification passed for the focused daemon session test, the webui build, the web-shell build, and ESLint over the changed packages.
Tested on
Environment (optional)
cd packages/webui && npx vitest run src/daemon/session/DaemonSessionProvider.test.tsxnpm run build --workspace=@qwen-code/webuinpm run build --workspace=@qwen-code/web-shellnpx eslint packages/webui packages/web-shell --ext .ts,.tsx --max-warnings 0Risk & Scope
onEventChangereceives the full transcript blocks array on every transcript change, so consumers should treat the value as read-only and avoid expensive synchronous work in the callback.Linked Issues
N/A
中文说明
What this PR does
这个 PR 为 web-shell 增加了一个回调,让宿主应用可以在 shell 处理 user、assistant、tool 等事件并更新 transcript blocks 时得到通知。同时收紧了 daemon replay 阶段的 prompt 状态恢复逻辑,避免只有非用户事件的 replay 把新会话误判成 waiting。
Why it's needed
嵌入 web-shell 的消费方需要一种直接观察 transcript/event 变化的方式,而不需要重新实现 shell 内部的 transcript reducer。另一方面,replay 恢复只应该在 replay 中存在用户消息且没有终止事件时推断 prompt 仍在进行;否则新会话或非 turn replay 会短暂表现得像仍有 prompt 在运行。
Reviewer Test Plan
How to verify
在 web-shell 中传入
onEventChange回调,确认用户、助手或工具活动导致展示内容变化时,它会收到完整的 transcript blocks 数组。恢复或创建一个 replay snapshot 只包含非用户 session update 的会话,确认 prompt status 保持 idle,而不是显示 waiting 或进行中状态。Evidence (Before & After)
截图不适用。本地已通过聚焦的 daemon session 测试、webui build、web-shell build,以及对变更 package 的 ESLint 检查。
Tested on
Environment (optional)
cd packages/webui && npx vitest run src/daemon/session/DaemonSessionProvider.test.tsxnpm run build --workspace=@qwen-code/webuinpm run build --workspace=@qwen-code/web-shellnpx eslint packages/webui packages/web-shell --ext .ts,.tsx --max-warnings 0Risk & Scope
onEventChange会在每次 transcript 变化时收到完整的 transcript blocks 数组,因此消费方应把它当作只读数据,并避免在回调中执行昂贵的同步逻辑。Linked Issues
N/A