fix(agent): stream replay hardening#2771
Conversation
611153a to
d0d353d
Compare
2710c28 to
4bf4fb4
Compare
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4bf4fb48b6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
✅ No security or compliance issues detected. Reviewed everything up to cf6d67d. Security Overview
Detected Code Changes
|
4bf4fb4 to
f357691
Compare
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3576918a7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| start_id = requested | ||
| resume_from = last_event_id if cursor else None |
There was a problem hiding this comment.
Preserve stream context when resuming mid-part
When a browser reconnects with a Last-Event-ID from a later Redis entry inside an already-open text/reasoning/tool part, starting the Redis read at requested rebuilds sse_vercel with a fresh VercelStreamContext that never saw the earlier start event. The next deltas for that part are then treated as unknown and emit nothing, so a transient disconnect can drop the rest of the assistant output until a new part starts. For Vercel streams, replay from the buffer start while suppressing frames up to the cursor, or otherwise restore/deterministically derive the part state before consuming future deltas.
Useful? React with 👍 / 👎.
f357691 to
7a5dbe0
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7a5dbe0472
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
1 issue found
Confidence score: 4/5
- This PR looks safe to merge overall: the reported issue is low-to-moderate severity (4/10) with moderate confidence, suggesting limited blast radius rather than a likely blocker.
- In
tracecat/agent/session/router.py, synthesizing a VercelmessageIdfrom the session UUID when no current run exists can cause a stale reconnect to show a new empty bubble instead of ending the stream cleanly. - Pay close attention to
tracecat/agent/session/router.py- reconnect/message finalization logic should avoid generating synthetic IDs when there is no active run.
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
4377150 to
d7054ea
Compare
7a5dbe0 to
6481d9b
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6481d9b4ef
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
6481d9b to
9c7dca6
Compare
9c7dca6 to
cf6d67d
Compare
9c95128 to
dba556b
Compare

Summary by cubic
Hardens chat stream replay and reconnects. Adds cheap status polling, Temporal-driven turn state, stable assistant bubble ids, composite SSE ids, and safe gap handling so clients reattach mid-turn without synthetic bubbles and observers see the user prompt.
New Features
/statusreturningturn_status/curr_run_id/prompt. FrontenduseSessionStatuspolls anduseVercelChatpre-inserts the active user prompt viaupsertActivePromptMessage, then attaches to the live turn.Last-Event-ID(frontend scansid:lines from the SSE body and sets the header on reconnect); stable assistant bubble idsession_id:run_id; Vercel adapter emitsid:lines with composite frame ids (<redis-id>:<frame-index>), skips frames atresume_from, and omitsmessage.startuntil amessage_idis known.message_idandresume_from; gap detection via Redismin_entry_id(stale cursor → replay from0-0if running, else emit a finishing stream); terminal reconnects preserve the bubble id from the latest stamped run; readers never write stream cursors and only expire buffers on completion; resume may include the cursor entry; waiting/idle without a cursor returns 204.curr_run_id; service hides active-run rows whilerunning; addsget_active_run_promptandget_latest_history_run_id.Migration
curr_run_idtoagent_session_history.Written for commit cf6d67d. Summary will update on new commits.
Review in cubic