You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tracking issue for bringing the new workflow chat to production parity and decommissioning the legacy substrate, following the /api/chat/workflow → /api/chat cutover (chat#1767, shipped to prod 2026-06-05). The cutover is fully live; this issue captures the capabilities still stubbed/deferred and the legacy teardown. Inherited-gap detail lives in api#605.
Goal
/api/chat (durable Vercel Workflow + per-session sandbox) is the only chat path in prod. Make it feature-complete and production-grade: full streaming control, faithful tool-call UX, restored sandbox tools + artist context, correct telemetry/billing, docs in lockstep — then drop rooms/memories once no reader remains. Done = a user on chat.recoupable.com has everything they had pre-cutover, and the legacy tables are gone.
docs#229 — align the Sessions OpenAPI spec with the live api.recoupable.com contract.
✅ Shipped 2026-06-05 (squash-merged to main, commit 2b683d5). Closes the former "Docs in lockstep" item.
Renamed the PATCH request schema PatchSessionRequest→PatchSessionBody (matches api's validatePatchSessionBody.ts); added artistId to Session.required typed OAS 3.1 ["string","null"] (was deprecated nullable: true); clarified isNewBranch as always-present on responses; hyperlinked the POST/GET/PATCH endpoints in the Session description and trimmed redundant schema descriptions (KISS, mirroring the CreateSessionRequest sibling).
Verified: the "required" claims are accurate against api/lib/sessions/toSessionResponse.ts, which always emits isNewBranch and artistId — so the original "marked required but missing from responses" framing was a doc-clarity gap, not an API bug. An earlier patch.mdx frontmatter regression (dropped the OpenAPI file-path prefix → would break the PATCH page render) was caught in review and fixed in 05cd6a18. JSON valid; CI green (Mintlify/CodeRabbit/cubic); merged CLEAN.
Server — ✅ shipped 2026-06-06 (squash → test, then test → main via api#652; both synced). POST /api/chat/{chatId}/stop cancels the run, polls getRun().status every 150ms to trip an AbortController on the in-flight model loop, waits for terminal status (≤8s, else 504 with the slot held), then releases active_stream_id via CAS; runAgentWorkflow gates auto-commit on !result.aborted. Verified on preview: stop returned 200 {stopped:true} sub-second (~0.6–0.8s), the in-flight bash tool emitted tool-output-error: "Cancelled" (cancelled mid-execution), and active_stream_id cleared to null.
Remaining — client chat#1770: wire the Stop button to POST /api/chat/{chatId}/stop so the UI "clicking Stop" path is exercised end-to-end.
Done when: clicking Stop in the UI ends the stream within ~1s and wasAborted gates auto-commit.
Auto chat-title from first message.(net-new; api#605) — pairs with chat#1662 (new title not shown in sidebar). Done when: the first turn sets a generated (non-verbatim) title that shows in the sidebar.
Edit / regenerate-from-message deletes from the wrong store(missed rooms/memories reader). (api#636 + chat#1776)
Why:DELETE /api/chats/{id}/messages/trailing still resolves and deletes via the legacy memories substrate (selectMemories → fromTimestamp → deleteMemories) — an untracked rooms/memories reader the cutover missed. Post-cutover history lives in chat_messages, so editing or regenerating from a prior turn in a workflow chat doesn't remove the trailing messages the user actually sees.
Fix: api#636 migrates validation + deletion to chat_messages — boundary {id, createdAt} deleted via the stable (created_at, id) ordering, mirroring open-agents' deleteChatMessageAndFollowing. chat#1776 threads transportChatId so the editor calls the endpoint with the session-scoped chat id. Confirm two open-agents parity behaviors are kept or consciously deferred: restrict deletion to role === "user", and bump last_assistant_message_at after delete.
Done when: editing/regenerating from a prior user message in a workflow chat removes that message + all newer from chat_messages (verified in DB), the sidebar's last message updates, and no memories reader remains on this path.
MCP tools in the workflow sandbox — artist data, music-industry APIs, send_email.
Composio tools — Sheets / Drive / Docs / TikTok.
Artist context in the system prompt.
Telegram new-conversation notifications.
Done when: a workflow chat can invoke these tools and the system prompt carries artist context, matching pre-cutover behavior.
Open — Telemetry & billing correctness (net-new; api#605)
Persist sandbox state after workflow finish — lifecycle timers stay stale otherwise.
Sub-agent (task tool) credit attribution — one usage_events row per sub-agent model (collectTaskToolUsageEvents).
workflow_runs telemetry.
Persist ask_user_question tool results across device switch.
Open — Phase 4 decommission (LAST — only after the workflow tools above are restored and stable)
Remove remaining rooms/memories readers — getGeneralAgent / setupChatRequest / setupToolsForRequest / MCP-Composio plumbing, still reachable via /api/chat/generate + Slack + email-inbound. (Note: the legacy handleChatStream/handleChatCompletion/app/api/chat/route.ts were already deleted in api#632; the current app/api/chat/route.ts is the canonical endpoint — do not delete it.)
Drop legacy rooms + memories tables — migration in recoupable/database (+ FK-dependents room_reports / segment_rooms / memory_emails). Destructive + irreversible — snapshot first; confirm zero readers.
Architecture decisions
Restore-before-remove. Workflow MCP/Composio (Restore-sandbox-tools bucket) must land before Phase 4 deletes the legacy tool plumbing, or capability is lost in the gap.
/api/chat is the single canonical chat path./api/chat/generate + Slack + email-inbound are the remaining legacy rooms/memories readers Phase 4 targets.
Tracking issue for bringing the new workflow chat to production parity and decommissioning the legacy substrate, following the
/api/chat/workflow→/api/chatcutover (chat#1767, shipped to prod 2026-06-05). The cutover is fully live; this issue captures the capabilities still stubbed/deferred and the legacy teardown. Inherited-gap detail lives in api#605.Goal
/api/chat(durable Vercel Workflow + per-session sandbox) is the only chat path in prod. Make it feature-complete and production-grade: full streaming control, faithful tool-call UX, restored sandbox tools + artist context, correct telemetry/billing, docs in lockstep — then droprooms/memoriesonce no reader remains. Done = a user onchat.recoupable.comhas everything they had pre-cutover, and the legacy tables are gone.What shipped (context)
api.recoupable.com/api/chatstreams;/api/chat/workflow→ 404. chat + open-agents repointed. (Post-cutover cleanup + follow-up items #1767, api#645/#648, chat#1783/#1784, open-agents#47, docs#235)chats.model_idbefore send (chat#1781).Done
api.recoupable.comcontract.✅ Shipped 2026-06-05 (squash-merged to
main, commit2b683d5). Closes the former "Docs in lockstep" item.Renamed the PATCH request schema
PatchSessionRequest→PatchSessionBody(matches api'svalidatePatchSessionBody.ts); addedartistIdtoSession.requiredtyped OAS 3.1["string","null"](was deprecatednullable: true); clarifiedisNewBranchas always-present on responses; hyperlinked the POST/GET/PATCH endpoints in theSessiondescription and trimmed redundant schema descriptions (KISS, mirroring theCreateSessionRequestsibling).Verified: the "required" claims are accurate against
api/lib/sessions/toSessionResponse.ts, which always emitsisNewBranchandartistId— so the original "marked required but missing from responses" framing was a doc-clarity gap, not an API bug. An earlierpatch.mdxfrontmatter regression (dropped the OpenAPI file-path prefix → would break the PATCH page render) was caught in review and fixed in05cd6a18. JSON valid; CI green (Mintlify/CodeRabbit/cubic); merged CLEAN.Open — Streaming control & resilience
test, thentest→mainvia api#652; both synced).POST /api/chat/{chatId}/stopcancels the run, pollsgetRun().statusevery 150ms to trip an AbortController on the in-flight model loop, waits for terminal status (≤8s, else 504 with the slot held), then releasesactive_stream_idvia CAS;runAgentWorkflowgates auto-commit on!result.aborted. Verified on preview: stop returned200 {stopped:true}sub-second (~0.6–0.8s), the in-flightbashtool emittedtool-output-error: "Cancelled"(cancelled mid-execution), andactive_stream_idcleared to null.POST /api/chat/{chatId}/stopso the UI "clicking Stop" path is exercised end-to-end.wasAbortedgates auto-commit.GET /api/chat/[chatId]/stream+ chat#1771 + docs#225)transportChatId).Open — Agent UX parity
DELETE /api/chats/{id}/messages/trailingstill resolves and deletes via the legacymemoriessubstrate (selectMemories→fromTimestamp→deleteMemories) — an untracked rooms/memories reader the cutover missed. Post-cutover history lives inchat_messages, so editing or regenerating from a prior turn in a workflow chat doesn't remove the trailing messages the user actually sees.chat_messages— boundary{id, createdAt}deleted via the stable(created_at, id)ordering, mirroring open-agents'deleteChatMessageAndFollowing. chat#1776 threadstransportChatIdso the editor calls the endpoint with the session-scoped chat id. Confirm two open-agents parity behaviors are kept or consciously deferred: restrict deletion torole === "user", and bumplast_assistant_message_atafter delete.chat_messages(verified in DB), the sidebar's last message updates, and nomemoriesreader remains on this path.Open — Restore sandbox tools & context (net-new — biggest gap; "accepted regressions")
send_email.Open — Telemetry & billing correctness (net-new; api#605)
usage_eventsrow per sub-agent model (collectTaskToolUsageEvents).workflow_runstelemetry.ask_user_questiontool results across device switch.Open — Phase 4 decommission (LAST — only after the workflow tools above are restored and stable)
rooms/memoriesreaders —getGeneralAgent/setupChatRequest/setupToolsForRequest/ MCP-Composio plumbing, still reachable via/api/chat/generate+ Slack + email-inbound. (Note: the legacyhandleChatStream/handleChatCompletion/app/api/chat/route.tswere already deleted in api#632; the currentapp/api/chat/route.tsis the canonical endpoint — do not delete it.)rooms+memoriestables — migration in recoupable/database (+ FK-dependentsroom_reports/segment_rooms/memory_emails). Destructive + irreversible — snapshot first; confirm zero readers.Architecture decisions
/api/chatis the single canonical chat path./api/chat/generate+ Slack + email-inbound are the remaining legacyrooms/memoriesreaders Phase 4 targets.Out of scope (separate trackers)
agent:@U0AJM…auto-PRs (triage/close).