feat: improve codex web chat feedback - #258
Conversation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Claude finished @centdix's task in 5m 39s —— View job Code Review — PR #258: improve codex web chat feedbackThorough review done. The streaming architecture (server-assigned monotonic Findings1. Duplicate tool bubbles if app-server item id ≠ rollout 2. Optimistic user bubble vanishes on duplicate text (inline on 3. Minor / nits
Things that look correct
|
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
webmux | 26ae08b | Commit Preview URL Branch Preview URL |
May 28 2026, 04:01 PM |
| && ( | ||
| pendingMessage.turnId === incomingMessage.turnId | ||
| || normalizedMessageText(pendingMessage) === normalizedMessageText(incomingMessage) | ||
| ); |
There was a problem hiding this comment.
Optimistic bubble can vanish when re-sending identical text. The text fallback matches the pending message against any prior user message with equal text, not just the one for the current turn. If a user sends a message identical to an earlier one, mergeConversationSnapshot sees the older server message satisfy isSameServerUserMessage, drops the freshly-added optimistic bubble (whose real server message hasn't landed yet), and the just-sent prompt disappears until the next snapshot includes it.
Consider scoping the text fallback to messages that aren't already present in the prior conversation (e.g. only match incoming user messages whose id wasn't already in the current state), so a duplicate prompt doesn't collapse onto a stale one.
| for (const message of [...baseMessages, ...additionalMessages]) { | ||
| if (seen.has(message.id)) continue; | ||
| seen.add(message.id); | ||
| merged.push(message); | ||
| } |
There was a problem hiding this comment.
Cross-source tool-call dedup relies on identical ids. This merge dedupes only by exact message.id. buildConversationMessages now emits commandExecution tool messages keyed by the app-server item id (item.id / ${item.id}:result), while readCodexSessionMessages emits tool messages keyed by the rollout call_id (call_id / ${call_id}:result). If a persisted thread ever contains a commandExecution item for the same command that also appears in the session log, and item.id !== call_id, the same shell command renders twice.
The same assumption underpins the live path: isSameLogicalConversationMessage matches tool calls by toolCallId, so a live commandExecution (toolCallId = item.id, toolName shell) and the session-log entry (toolCallId = call_id, toolName exec_command) won't be recognized as the same call — leaving a duplicate bubble and a never-evicted entry in liveMessages.
Could you confirm commandExecution.id and the rollout call_id are guaranteed equal? If not, dedupe tool calls across sources by a stable key rather than the raw id.
| ...snapshot, | ||
| conversation: { | ||
| ...snapshot.conversation, | ||
| running: snapshot.conversation.running || inProgress !== null, |
There was a problem hiding this comment.
running can get stuck on. If a live message goes inProgress (via a delta or item/started) but never receives a terminal item/completed notification — e.g. the turn is aborted or the completion is dropped — shouldKeepLiveMessage keeps it (no matching completed snapshot message), so every subsequent snapshot re-asserts running: true indefinitely and the UI shows the conversation as perpetually running. Worth a guard that evicts/clears live in-progress messages once the snapshot reports the turn is no longer active.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Claude finished @centdix's task in 5m 48s —— View job Code Review — PR #258: improve codex web chat feedbackReviewed the full diff against This is a re‑review, so below I confirm/refine the three earlier findings (with corrected mechanics) and add a few observations the first pass didn't surface. Confirmed findings (refined)1. Cross‑source tool dedup is fragile — but the real hinge is
Worth confirming whether app‑server and rollout share turn/call identifiers. If not, dedupe across sources by a stable key. (Related: thread 2. Optimistic user bubble can vanish — but only on rapid/concurrent identical sends, not simple resends. (
The suggested fix (scope the fallback to genuinely‑new server messages / match by reconciled turn id rather than raw text) is right, and a test for the double‑identical‑send would lock it in. Fix this → 3. Minor / nits
Looks correct
Overall: well‑structured, well‑tested change. Findings #1 and #2 are the ones I'd prioritize chasing down; #3 is a narrow edge with existing self‑heal.
|
Summary
Improve Codex web chat feedback and make the streaming path reliable enough for live use. This adds richer streamed conversation events, preserves correct ordering with revisions, and fixes duplicate/stale message behavior seen during WebUI testing.
Changes
messageUpsertupdates.typinglabel under plain assistant messages while keeping internal in-progress state.Test plan
bun run --cwd backend checkbun run --cwd frontend checkbun run testGenerated with Claude Code