feat: route new chats through recoup-api /api/chat/workflow
Merged
SW
5mo ago+471+471+012345678901234567890123456789-10-10-01234567890123456789
Summary
- New chats now provision a recoup-api session + sandbox before the first message, then stream through recoup-api's
/api/chat/workflow. - Existing chats opened from history keep using the legacy
/api/chatuntilsession_idis backfilled onto their rows. - api owns
cloneUrlconstruction. The client passesorganizationId(or omits it for a personal session); the api derives the canonical workspace repo viaensurePersonalRepo(recoupable/api#618, #620) and returnscloneUrlon the session row, which the client then hands tocreateSandbox.
What changed
| Layer | Change |
|---|---|
lib/sandboxes/{createSandbox,SandboxCreateRequestError}.ts | createSandbox() function added next to the existing Sandbox type (4 callers unchanged); uses getClientApiBaseUrl() to respect the API override |
lib/sessions/createSession.ts | New folder, POST /api/sessions. Body shrunk to { title?, organizationId? }; response type exposes session.cloneUrl |
hooks/useChatTransport.ts | Branches on sessionId — present → /api/chat/workflow with transport-injected body; absent → legacy /api/chat |
hooks/useVercelChat.ts, providers/VercelChatProvider.tsx, components/VercelChat/chat.tsx | Threaded optional sessionId through |
components/VercelChat/NewChatBootstrap.tsx | Client wrapper: reads selectedOrgId from OrganizationProvider, calls createSession({ organizationId }), reads session.cloneUrl off the response, then createSandbox(cloneUrl, sessionId) → renders <Chat sessionId>. startedRef guards against React StrictMode double-mount |
app/chat/page.tsx | Renders NewChatBootstrap instead of Chat |
app/chat/[roomId]/page.tsx | Untouched → existing chats stay on legacy /api/chat |
Test plan
- On the preview deployment, open
/chat→ confirm the bootstrap loader briefly shows, then the chat surface mounts - Send a first message → confirm
POST recoup-api.vercel.app/api/chat/workflowin DevTools Network (200, streaming response) - Confirm
POST /api/sessionsprecedes it, body is{}for personal or{ organizationId: "<uuid>" }for org; response includessession.cloneUrl - Confirm
POST /api/sandboxis called withrepoUrl== the api-returnedcloneUrl(canonicalrecoupable/<accountId>orrecoupable/<orgId>shape) - Refresh the resulting
/chat/[roomId]page → confirm it falls back to legacyPOST /api/chat(sessionId is lost on reload — expected; backfill not yet run) - Open an old chat from history → confirm it still works (legacy path)
- React StrictMode dev-mode: confirm only one session + one sandbox are created per new-chat mount
Out of scope
- Backfill
session_idonto existing chat rows + provision sandboxes on first open of a legacy chat - Delete the legacy
/api/chatroute on the chat side once all chats use the workflow path - MCP tools, Composio tools, artist context injection, title generation, email tool — intentionally not ported
🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
- New Features
- New session-based chat initialization that automatically provisions sandboxes and chat environments
- Session-aware chat request routing with fallback to legacy infrastructure
- Improved sandbox creation error handling with actionable error messages and reconnection guidance