Skip to content

refactor(sessions): migrate /api/sessions/[sessionId]/chats/[chatId] to recoupable API#37

Open
arpitgupta1214 wants to merge 7 commits into
mainfrom
feat/cutover-get-session-chat-by-id
Open

refactor(sessions): migrate /api/sessions/[sessionId]/chats/[chatId] to recoupable API#37
arpitgupta1214 wants to merge 7 commits into
mainfrom
feat/cutover-get-session-chat-by-id

Conversation

@arpitgupta1214
Copy link
Copy Markdown
Collaborator

@arpitgupta1214 arpitgupta1214 commented May 13, 2026

Summary

The full chat-by-id route now lives at recoupable API (api#562, docs#209).

  • Deletes the local route + tests entirely (GET/PATCH/DELETE all gone)
  • New helpers under lib/recoupable/: get-recoup-session-chat, patch-recoup-session-chat, delete-recoup-session-chat (all Privy Bearer; cache: "no-store" on GET; surface server error text on non-2xx)
  • Rewires:
    • session-chat-content.refreshCurrentChatSnapshot → GET helper
    • useSessionChats.renameChat → PATCH helper
    • useSessionChats.deleteChat → DELETE helper
    • SessionChatProvider.updateChatModel → PATCH helper

Test plan

  • CI green
  • Preview: opening an existing chat hydrates messages from recoupable API
  • Renaming a chat via the chat tabs updates the sidebar
  • Switching the model via the model picker updates the chat
  • Deleting one of two chats removes it; deleting the last chat surfaces "Cannot delete the only chat in a session"
  • Tab-resume refresh repopulates messages without overwriting an in-flight stream

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor

    • Migrated chat operations (refresh, update, delete) to use authenticated service calls via a new backend API integration.
    • Replaced direct API route handlers with authenticated helper functions for improved security and scalability.
  • Tests

    • Removed test coverage for deprecated chat API routes.

Review Change Stack

…Id] to recoupable API

The chat-snapshot read now lives at recoupable api (api#562, docs#209).
Drops the local GET handler on the route and rewires the only caller
(session-chat-content's `refreshCurrentChatSnapshot`) to a new
`getRecoupSessionChat` helper that authenticates with a Privy bearer
token. PATCH/DELETE on the same path stay in place.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
open-agents Ready Ready Preview May 15, 2026 6:33pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

Warning

Rate limit exceeded

@arpitgupta1214 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 52 minutes and 40 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2e631249-2d33-4af8-a4fb-42d79c943305

📥 Commits

Reviewing files that changed from the base of the PR and between 70781a0 and e5b5b83.

📒 Files selected for processing (5)
  • apps/web/app/sessions/[sessionId]/chats/[chatId]/page.tsx
  • apps/web/app/sessions/[sessionId]/chats/[chatId]/session-chat-context.tsx
  • apps/web/hooks/use-session-chats.ts
  • apps/web/lib/recoupable/get-recoup-session-chat.ts
  • apps/web/lib/recoupable/patch-recoup-session-chat.ts
📝 Walkthrough

Walkthrough

This PR removes the legacy session chat API route handlers (GET, PATCH, DELETE) and replaces them with authenticated recoupable API client helpers. UI components and hooks are updated to use Privy Bearer tokens instead of direct fetch calls.

Changes

Session chat API migration to recoupable

Layer / File(s) Summary
Recoupable API client helpers
apps/web/lib/recoupable/patch-recoup-session-chat.ts, apps/web/lib/recoupable/get-recoup-session-chat.ts, apps/web/lib/recoupable/delete-recoup-session-chat.ts
New exported functions patchRecoupSessionChat, getRecoupSessionChat, and deleteRecoupSessionChat issue Bearer-authenticated requests to the recoup API, with request/response types for PATCH and GET operations, and error handling via optional server JSON error fields.
Chat refresh with authenticated recoup API
apps/web/app/sessions/[sessionId]/chats/[chatId]/session-chat-content.tsx
Imports usePrivy and getRecoupSessionChat; updates refreshCurrentChatSnapshot to retrieve getAccessToken, call getRecoupSessionChat(session.id, chatInfo.id, accessToken), and update messages only when not streaming, replacing the prior unauthenticated fetch-based refresh.
Chat model update with authenticated recoup API
apps/web/app/sessions/[sessionId]/chats/[chatId]/session-chat-context.tsx
Imports usePrivy and patchRecoupSessionChat; updates updateChatModel to obtain getAccessToken from Privy, throw on missing auth, and call patchRecoupSessionChat with session/chat IDs and access token, replacing the fetch PATCH to the old API route.
Chat rename and delete with authenticated recoup API
apps/web/hooks/use-session-chats.ts
Imports patchRecoupSessionChat and deleteRecoupSessionChat; updates renameChat and deleteChat to acquire getAccessToken and call the recoupable helpers instead of parsing fetch responses.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • recoupable/open-agents#35: Both PRs migrate session chat operations to the recoupable API with Privy Bearer tokens and overlap on hook-level authenticated wiring in use-session-chats.ts.

Suggested reviewers

  • sweetmantech

Poem

🐰 We hop from routes so old and stale,
To recoup helpers, Bear tokens, all hail!
From fetch to Privy, auth flows so clean,
Chat refresh, updates, delete scenes—
A migration complete, resilient and lean! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: migrating the chat endpoint from a local API route to the recoupable API, which aligns with the file deletions, test removals, and new helper functions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cutover-get-session-chat-by-id

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 4 files

You're on the cubic free plan with 19 free PR reviews remaining this month. Upgrade for unlimited reviews.

…nId]/chats/[chatId] to recoupable API

The full chat-by-id route now lives at recoupable api (api#562, docs#209):
GET, PATCH, and DELETE.

- Deletes the local route + tests entirely (was the last remaining
  caller of in-process `requireOwnedSessionChat` for this path)
- New helpers `lib/recoupable/{patch,delete}-recoup-session-chat.ts`
  (Privy Bearer; surface server `error` text on non-2xx)
- Rewires `useSessionChats.{renameChat,deleteChat}` and
  `SessionChatProvider.updateChatModel` through the new helpers

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@arpitgupta1214 arpitgupta1214 changed the title refactor(sessions): migrate GET /api/sessions/[sessionId]/chats/[chatId] to recoupable API refactor(sessions): migrate GET/PATCH/DELETE /api/sessions/[sessionId]/chats/[chatId] to recoupable API May 13, 2026
@arpitgupta1214 arpitgupta1214 changed the title refactor(sessions): migrate GET/PATCH/DELETE /api/sessions/[sessionId]/chats/[chatId] to recoupable API refactor(sessions): migrate /api/sessions/[sessionId]/chats/[chatId] to recoupable API May 15, 2026
…ion-chat-by-id

# Conflicts:
#	apps/web/hooks/use-session-chats.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/lib/recoupable/delete-recoup-session-chat.ts`:
- Around line 26-30: Replace the bare type assertion for the error payload in
deleteRecoupSessionChat with a Zod-validated parse: import z from "zod", define
an errorSchema (e.g., z.object({ error: z.string().optional() })), call
errorSchema.safeParse(await res.json().catch(() => ({}))) to get a parsed
result, extract the error string only when parsed.success is true (e.g.,
errorMessage = parsed.success ? parsed.data.error : undefined), and use that
errorMessage in the thrown Error instead of the current payload.error.

In `@apps/web/lib/recoupable/get-recoup-session-chat.ts`:
- Around line 36-38: The GET error branch in getRecoupSessionChat currently
throws only status and statusText, losing the server-provided JSON error; update
the error handling for the response object (res) so that when !res.ok you parse
the response body (await res.json() or res.text() as appropriate) and include
the parsed error message/details in the thrown Error (e.g., include the parsed
error payload alongside res.status and res.statusText) so callers/UI can surface
the server error payload.
- Line 40: The return currently does an unsafe cast in getRecoupSessionChat
(return res.json() as Promise<GetRecoupSessionChatResponse>) — replace it by
defining a Zod schema (e.g., RecoupSessionChatSchema) that matches the expected
response, use await res.json() then validate with
RecoupSessionChatSchema.safeParse(parsed) and if valid return the parsed data
typed via z.infer<typeof RecoupSessionChatSchema>, otherwise throw or handle an
error (keep the same error-handling pattern used in fetch-or-create-account.ts /
fetch-account-subscription.ts). Ensure the new schema and inferred type replace
GetRecoupSessionChatResponse usage for type safety.

In `@apps/web/lib/recoupable/patch-recoup-session-chat.ts`:
- Around line 40-47: The current code casts res.json() responses unchecked in
patchRecoupSessionChat (the error payload cast to {error?: string} and the final
return cast to PatchRecoupSessionChatResponse); replace those casts with Zod
validation: define a zod schema for the error shape and another for the
success/PatchRecoupSessionChatResponse shape, derive types with z.infer, parse
the JSON from res.json() with schema.safeParse or schema.parse, and when parsing
fails throw a descriptive Error including the validation errors (or the original
HTTP status) so only validated data is returned from patchRecoupSessionChat.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b943ae8f-32e5-44b8-a954-e7e3220469b8

📥 Commits

Reviewing files that changed from the base of the PR and between 7f027ff and 70781a0.

📒 Files selected for processing (8)
  • apps/web/app/api/sessions/[sessionId]/chats/[chatId]/route.test.ts
  • apps/web/app/api/sessions/[sessionId]/chats/[chatId]/route.ts
  • apps/web/app/sessions/[sessionId]/chats/[chatId]/session-chat-content.tsx
  • apps/web/app/sessions/[sessionId]/chats/[chatId]/session-chat-context.tsx
  • apps/web/hooks/use-session-chats.ts
  • apps/web/lib/recoupable/delete-recoup-session-chat.ts
  • apps/web/lib/recoupable/get-recoup-session-chat.ts
  • apps/web/lib/recoupable/patch-recoup-session-chat.ts
💤 Files with no reviewable changes (2)
  • apps/web/app/api/sessions/[sessionId]/chats/[chatId]/route.ts
  • apps/web/app/api/sessions/[sessionId]/chats/[chatId]/route.test.ts

Comment on lines +26 to +30
const payload = (await res.json().catch(() => ({}))) as { error?: string };
throw new Error(
payload.error ??
`deleteRecoupSessionChat: ${res.status} ${res.statusText}`,
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the target file to understand the full context
head -50 apps/web/lib/recoupable/delete-recoup-session-chat.ts

Repository: recoupable/open-agents

Length of output: 1059


🏁 Script executed:

# Check if Zod is used in this project and in similar contexts
rg -i "zod" --type ts --type tsx -l | head -20

Repository: recoupable/open-agents

Length of output: 94


🏁 Script executed:

# Search for error handling patterns with JSON responses in the codebase
rg "res\.json\(\)" --type ts --type tsx -A 3 -B 1 | head -60

Repository: recoupable/open-agents

Length of output: 94


🏁 Script executed:

# Look for z.object or z.infer patterns to see how validation is done
rg "z\.object|z\.infer" --type ts --type tsx -B 2 -A 2 | head -80

Repository: recoupable/open-agents

Length of output: 94


🏁 Script executed:

# Try searching for Zod without file type specification
rg "from.*zod|import.*zod" -i | head -20

Repository: recoupable/open-agents

Length of output: 1245


🏁 Script executed:

# Look for error handling patterns more broadly
rg "res\.json\(\)" -A 3 -B 1 | head -100

Repository: recoupable/open-agents

Length of output: 6121


🏁 Script executed:

# Check if this codebase uses Zod at all
rg "z\." --type ts | head -30

Repository: recoupable/open-agents

Length of output: 2391


🏁 Script executed:

# Look at similar API boundary calls in the codebase
find apps/web/lib/recoupable -name "*.ts" -type f | xargs -I {} bash -c 'echo "=== {} ===" && head -5 {}'

Repository: recoupable/open-agents

Length of output: 6173


🏁 Script executed:

cat -n apps/web/lib/recoupable/fetch-account-credits.ts

Repository: recoupable/open-agents

Length of output: 1228


🏁 Script executed:

cat -n apps/web/lib/recoupable/fetch-account-subscription.ts

Repository: recoupable/open-agents

Length of output: 989


Use a Zod schema to validate the error response payload, consistent with other Recoupable API calls.

The error payload should be validated with a Zod schema and .safeParse() rather than a bare type assertion. Other similar calls in this directory (fetch-account-credits.ts, fetch-account-subscription.ts) follow this pattern. Define a simple schema like:

Example pattern
const errorSchema = z.object({ error: z.string().optional() });
const parsed = errorSchema.safeParse(await res.json().catch(() => ({})));
const errorMessage = parsed.success ? parsed.data.error : undefined;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/lib/recoupable/delete-recoup-session-chat.ts` around lines 26 - 30,
Replace the bare type assertion for the error payload in deleteRecoupSessionChat
with a Zod-validated parse: import z from "zod", define an errorSchema (e.g.,
z.object({ error: z.string().optional() })), call errorSchema.safeParse(await
res.json().catch(() => ({}))) to get a parsed result, extract the error string
only when parsed.success is true (e.g., errorMessage = parsed.success ?
parsed.data.error : undefined), and use that errorMessage in the thrown Error
instead of the current payload.error.

Comment on lines +36 to +38
if (!res.ok) {
throw new Error(`getRecoupSessionChat: ${res.status} ${res.statusText}`);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Surface server error text on non-2xx GET responses.

This currently drops the JSON error payload and only throws status text, which makes diagnostics/UI messaging less actionable than PATCH/DELETE.

💡 Suggested fix
   if (!res.ok) {
-    throw new Error(`getRecoupSessionChat: ${res.status} ${res.statusText}`);
+    const payload = (await res.json().catch(() => ({}))) as { error?: string };
+    throw new Error(
+      payload.error ??
+        `getRecoupSessionChat: ${res.status} ${res.statusText}`,
+    );
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!res.ok) {
throw new Error(`getRecoupSessionChat: ${res.status} ${res.statusText}`);
}
if (!res.ok) {
const payload = (await res.json().catch(() => ({}))) as { error?: string };
throw new Error(
payload.error ??
`getRecoupSessionChat: ${res.status} ${res.statusText}`,
);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/lib/recoupable/get-recoup-session-chat.ts` around lines 36 - 38, The
GET error branch in getRecoupSessionChat currently throws only status and
statusText, losing the server-provided JSON error; update the error handling for
the response object (res) so that when !res.ok you parse the response body
(await res.json() or res.text() as appropriate) and include the parsed error
message/details in the thrown Error (e.g., include the parsed error payload
alongside res.status and res.statusText) so callers/UI can surface the server
error payload.

throw new Error(`getRecoupSessionChat: ${res.status} ${res.statusText}`);
}

return res.json() as Promise<GetRecoupSessionChatResponse>;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and examine it
find . -name "get-recoup-session-chat.ts" -type f

Repository: recoupable/open-agents

Length of output: 119


🏁 Script executed:

# If found, read the file to see the context around line 40
cat -n apps/web/lib/recoupable/get-recoup-session-chat.ts

Repository: recoupable/open-agents

Length of output: 1518


🏁 Script executed:

# Search for GetRecoupSessionChatResponse type definition
rg "GetRecoupSessionChatResponse" -A 5 -B 2

Repository: recoupable/open-agents

Length of output: 1605


🏁 Script executed:

# Look for Zod schemas in the same directory
fd -e ts -e tsx apps/web/lib/recoupable/ | head -20

Repository: recoupable/open-agents

Length of output: 468


🏁 Script executed:

# Check if there are any existing Zod schemas in the recoupable directory
rg "z\\..*\\(" apps/web/lib/recoupable/ | head -20

Repository: recoupable/open-agents

Length of output: 1763


🏁 Script executed:

# Check how Zod schemas are implemented in a similar file
head -50 apps/web/lib/recoupable/fetch-or-create-account.ts

Repository: recoupable/open-agents

Length of output: 1481


🏁 Script executed:

# See the complete pattern for how Zod is used
head -70 apps/web/lib/recoupable/fetch-or-create-account.ts | tail -25

Repository: recoupable/open-agents

Length of output: 775


Replace unchecked response casting with Zod schema validation.

Line 40 uses unsafe type assertion (res.json() as Promise<GetRecoupSessionChatResponse>) which skips runtime validation. Per coding guidelines and the pattern throughout this directory (see fetch-or-create-account.ts, fetch-account-subscription.ts, etc.), create a Zod schema, validate with safeParse(), and derive the TypeScript type with z.infer<typeof schema>.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/lib/recoupable/get-recoup-session-chat.ts` at line 40, The return
currently does an unsafe cast in getRecoupSessionChat (return res.json() as
Promise<GetRecoupSessionChatResponse>) — replace it by defining a Zod schema
(e.g., RecoupSessionChatSchema) that matches the expected response, use await
res.json() then validate with RecoupSessionChatSchema.safeParse(parsed) and if
valid return the parsed data typed via z.infer<typeof RecoupSessionChatSchema>,
otherwise throw or handle an error (keep the same error-handling pattern used in
fetch-or-create-account.ts / fetch-account-subscription.ts). Ensure the new
schema and inferred type replace GetRecoupSessionChatResponse usage for type
safety.

Comment on lines +40 to +47
const payload = (await res.json().catch(() => ({}))) as { error?: string };
throw new Error(
payload.error ??
`patchRecoupSessionChat: ${res.status} ${res.statusText}`,
);
}

return res.json() as Promise<PatchRecoupSessionChatResponse>;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

cat -n apps/web/lib/recoupable/patch-recoup-session-chat.ts

Repository: recoupable/open-agents

Length of output: 1714


Replace unchecked type assertions with Zod schema validation at the API boundary.

Both error and success responses from res.json() are cast without validation. At runtime, malformed payloads can propagate silently into chat state. Define Zod schemas for both error and success responses, parse payloads with these schemas, and derive types using z.infer instead of casting.

Lines 40, 47 — unchecked assertions
    const payload = (await res.json().catch(() => ({}))) as { error?: string };
    throw new Error(
      payload.error ??
        `patchRecoupSessionChat: ${res.status} ${res.statusText}`,
    );
  }

  return res.json() as Promise<PatchRecoupSessionChatResponse>;

Per coding guidelines: "Use Zod schemas for validation and derive types with z.infer".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/lib/recoupable/patch-recoup-session-chat.ts` around lines 40 - 47,
The current code casts res.json() responses unchecked in patchRecoupSessionChat
(the error payload cast to {error?: string} and the final return cast to
PatchRecoupSessionChatResponse); replace those casts with Zod validation: define
a zod schema for the error shape and another for the
success/PatchRecoupSessionChatResponse shape, derive types with z.infer, parse
the JSON from res.json() with schema.safeParse or schema.parse, and when parsing
fails throw a descriptive Error including the validation errors (or the original
HTTP status) so only validated data is returned from patchRecoupSessionChat.

Drops the `import type { Chat } from "@/lib/db/schema"` from the new
patch helper. Defines `RecoupChat` inline matching what the recoupable
API actually returns (camelCase keys, ISO-string timestamps), so the
helper is self-contained and doesn't depend on the local Drizzle
declaration.

Drizzle's inferred `Chat` claims `Date` for timestamps but the wire
data is strings — so this also catches a long-standing latent type
lie at the boundary. Casts at the two consumer call sites keep the
diff surgical until the rest of the chat state is typed against the
wire format.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hat export

The patch helper exported `RecoupChat` but nothing imported it — and
a per-action helper isn't the natural place to own the wire-format
type anyway. Inline the shape in `PatchRecoupSessionChatResponse`
where it's actually used.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
arpitgupta1214 and others added 2 commits May 15, 2026 21:29
…format casts

Reverts the wire-format experiment in favor of the existing
convention from the list/create helpers — `import type { Chat } from
"@/lib/db/schema"`. Removes the `as unknown as` casts at the two
consumer call sites since the types now line up natively.

The Drizzle Chat type claims `Date` for timestamps while runtime
values are ISO strings (Next.js serializes at the server/client
boundary), but nothing calls Date methods on these fields so the lie
is harmless. Fixing it is a separate cleanup, not in scope here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The chat-by-id page no longer reaches into the local Drizzle schema
for the chat row. Instead it calls getRecoupSessionChat with the
Privy access token from the session cookie — same auth pattern
already used by resolveAccountIdFromPrivyToken on the server side.

This drops the cast in setChatInfo: chatInfo state and the
SessionChatProvider chat prop are now typed as RecoupSessionChat
end-to-end (matches the api wire format that toChatResponse
returns).

dbMessages still come from Drizzle for now (used for assistant
message duration calcs); that's a follow-up when message rows are
also migrated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/web/app/sessions/[sessionId]/chats/[chatId]/page.tsx">

<violation number="1" location="apps/web/app/sessions/[sessionId]/chats/[chatId]/page.tsx:67">
P1: Do not swallow all `getRecoupSessionChat` errors here; for non-retry paths this turns real API/auth failures into false 404s.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.
You're on the cubic free plan with 19 free PR reviews remaining this month. Upgrade for unlimited reviews.
Re-trigger cubic

Comment on lines +67 to 69
} catch {
// Likely 404 while the optimistic chat hasn't persisted yet.
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Do not swallow all getRecoupSessionChat errors here; for non-retry paths this turns real API/auth failures into false 404s.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/app/sessions/[sessionId]/chats/[chatId]/page.tsx, line 67:

<comment>Do not swallow all `getRecoupSessionChat` errors here; for non-retry paths this turns real API/auth failures into false 404s.</comment>

<file context>
@@ -51,14 +55,17 @@ const OPTIMISTIC_CHAT_RETRY_ATTEMPTS = 50;
+    try {
+      const data = await getRecoupSessionChat(sessionId, chatId, accessToken);
+      return data.chat;
+    } catch {
+      // Likely 404 while the optimistic chat hasn't persisted yet.
     }
</file context>
Suggested change
} catch {
// Likely 404 while the optimistic chat hasn't persisted yet.
}
} catch (error) {
if (maxAttempts === 1) {
throw error;
}
// Likely 404 while the optimistic chat hasn't persisted yet.
}

Tip: Review your code locally with the cubic CLI to iterate faster.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant