feat(api): split chat-workflow resume into GET /api/chat/[chatId]/stream
Closed
AR
3d ago+618+618+012345678901234567890123456789-128-128-012345678901234567890123456789
Summary
POST /api/chat/workflow is now start-only — a genuinely live run returns 409 instead of silently resuming and dropping the incoming message; resume moves to a dedicated GET /api/chat/[chatId]/stream (live UIMessage stream, or 204 when there's nothing to resume). A terminal stale active_stream_id still self-heals so the next POST starts fresh.
Test plan
- POST while a run is live → 409, no new run started
- POST with a terminal/stale
active_stream_id→ starts a fresh run - GET
/api/chat/[chatId]/streamwith a live run → 200 stream +x-workflow-run-id - GET with no active or terminated run → 204
Summary by cubic
Split chat-workflow resume into GET /api/chat/[chatId]/stream and make POST /api/chat/workflow start-only. The resume stream is now wrapped for durability: it avoids orphaned readers, does not cancel runs on disconnect, and treats aborts/late 404s as clean closes; DB errors now surface as 500s.
-
New Features
GET /api/chat/[chatId]/streamto resume/reconnect.- 200 SSE with live UIMessage stream +
x-workflow-run-id; 204 when nothing to resume. - Auth via
x-api-keyor bearer; chat ownership enforced; UUIDchatIdvalidation; CORS preflight. - Stream is wrapped with
wrapWorkflowStreamWatcherto synthesize tool terminators, release inner reader on client cancel, avoid cancelling durable runs, and treat AbortError/late 404 as a clean close.
- 200 SSE with live UIMessage stream +
POST /api/chat/workflownever resumes.- 409 when a run is live (reconnect via GET); 503 when state is indeterminate (retry POST); terminal stale
active_stream_idself-heals for a fresh start. - Start gating extracted to
gateChatStreamStart.
- 409 when a run is live (reconnect via GET); 503 when state is indeterminate (retry POST); terminal stale
- DB handling tightened:
selectChatsreturnsnullon DB error and callers surface 500; hibernation defers on DB errors; chat creation surfaces 500.
-
Migration
- Do not use
POST /api/chat/workflowto resume; reconnect viaGET /api/chat/{chatId}/stream. - On
POST, handle 409 by reconnecting via GET; handle 503 by retrying the POST shortly. - Treat
GET204 as “no active stream”; on 200, consume SSE and readx-workflow-run-idfor telemetry. - Client disconnects no longer cancel runs; use the stop endpoint to cancel explicitly.
- Do not use
Summary by CodeRabbit
-
New Features
- Resume interrupted chat streams and reconnect to ongoing conversations via a dedicated resume endpoint.
-
Bug Fixes
- Clearer reconnect/retry signals when streams conflict or are indeterminate.
- More robust error handling for chat/session loading, permission checks, and DB failure cases to avoid silent failures.
- Cleaner stream shutdown behavior on client disconnects (avoids mid-stream errors).
-
Refactor
- Separation of resume (resume-only endpoint) from new-stream start flow for more predictable behavior.