Skip to content

Conversation

@sweetmantech
Copy link
Collaborator

@sweetmantech sweetmantech commented Jan 16, 2026

Summary

  • Update useCreateChat hook to call recoup-api /api/chats endpoint directly
  • Use Bearer token auth with Privy access token for authentication
  • Add RFC 8594 deprecation headers to old /api/chat/create endpoint
  • Set 90-day sunset period for deprecated endpoint

Test plan

  • Verify new chat creation works via recoup-api
  • Verify deprecated endpoint still returns correct responses with deprecation headers
  • Verify chat title generation works correctly

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Deprecations

    • Several chat, agent and template endpoints now include sunset/deprecation headers and guidance.
  • Updates

    • Chat/agent flows and template fetching now require an access token and call the new API base URL.
  • Removals

    • Multiple browser automation endpoints, funnel analytics comments, fans-profiles endpoint, and related helper modules were removed.

✏️ Tip: You can customize this high-level summary in your review settings.

sweetmantech and others added 4 commits January 16, 2026 10:33
Remove 4 unused browser automation API endpoints that have no usages
in the codebase:
- /api/browser/act
- /api/browser/agent
- /api/browser/extract
- /api/browser/observe

Also delete orphaned files that were only used by these endpoints:
- lib/browser/hasBooleanSuccess.ts (type guard for agent route)
- types/browser.types.ts (types for all browser routes)

All tests pass and build succeeds.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Remove unused funnel_analysis/comments API endpoint and its orphaned
helper function. Grep confirmed no usages in codebase.

Files deleted:
- app/api/funnel_analysis/comments/route.ts
- lib/supabase/getFunnelAnalyticsComments.tsx

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Update useCreateChat hook to call recoup-api /api/chats endpoint directly
- Use Bearer token auth with Privy access token
- Add RFC 8594 deprecation headers to old /api/chat/create endpoint
- Set 90-day sunset period for deprecated endpoint

This completes the client-side migration. The old endpoint remains
functional during the sunset period but clients should use recoup-api.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@vercel
Copy link

vercel bot commented Jan 16, 2026

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

Project Deployment Review Updated (UTC)
recoup-chat Ready Ready Preview Jan 16, 2026 8:35pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 16, 2026

📝 Walkthrough

Walkthrough

Multiple legacy Next.js API routes and a few helper modules were removed; several endpoints and client hooks were migrated to use NEW_API_BASE_URL with Bearer token auth; multiple routes gained deprecation headers and new route metadata exports.

Changes

Cohort / File(s) Summary
Browser automation routes (removed)
app/api/browser/act/route.ts, app/api/browser/agent/route.ts, app/api/browser/extract/route.ts, app/api/browser/observe/route.ts
Entire route handlers deleted: POST handlers, JSON parsing and Zod validation, isBlockedStartUrl checks, withBrowser automation/extraction/observe logic, hasBooleanSuccess usage, and route metadata exports (runtime, dynamic, revalidate, fetchCache, maxDuration).
Analytics & fan-profiles routes (removed)
app/api/funnel_analysis/comments/route.ts, app/api/get_fans_profiles/route.ts
Route handlers removed (POST/GET) along with their dynamic/cache/revalidate exports and associated caller surface.
Removed helpers / supabase utilities
lib/browser/hasBooleanSuccess.ts, lib/supabase/getFunnelAnalyticsComments.tsx
Deleted a boolean-success type guard and a Supabase helper that fetched funnel analytics comments; callers must be updated or removed.
Chat create — deprecation headers
app/api/chat/create/route.ts
Added deprecation metadata: import NEW_API_BASE_URL, SUNSET_DAYS, getDeprecationHeaders() and attached Deprecation/Sunset/Link headers to all responses; JSDoc @deprecated added. No signature changes.
Agent templates / agents — deprecation + route metadata
app/api/agent-templates/favorites/route.ts, app/api/agent-templates/route.ts, app/api/agents/route.ts
Added deprecation header logic (same pattern) and, where noted, exported dynamic = "force-dynamic" and revalidate = 0. GET responses now include deprecation headers.
Agent-creator & AI models — deprecation + route metadata
app/api/agent-creator/route.ts, app/api/ai/models/route.ts
Added deprecation headers on responses (Deprecation/Sunset/Link using NEW_API_BASE_URL) and exported route metadata (dynamic, fetchCache, revalidate) where added.
Hooks and components — migrate to NEW_API_BASE_URL + token auth
hooks/useCreateChat.tsx, hooks/useArtistAgents.ts, hooks/useAvailableModels.ts, components/Agents/AgentCreator.tsx
Switched client calls to ${NEW_API_BASE_URL} paths, introduced useAccessToken and Authorization Bearer headers, updated request/response shapes and guards for token presence.
Agent templates client-side changes
components/Agents/useAgentData.ts, components/Agents/useAgentToggleFavorite.ts, lib/agent-templates/fetchAgentTemplates.ts
Added useAccessToken propagation; fetchAgentTemplates signature changed to accept accessToken; requests now call external API with Authorization and validate structured responses; payloads trimmed (removed userId/email).
Misc — removed duplicate mentions
app/api/funnel_analysis/comments/route.ts
Duplicate removal noted in Analytics cohort.

Sequence Diagram(s)

(Skipped)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

Routes take their bows at dusk, new tokens hum the tune,
Sunset headers mark the change beneath a migrating moon.
Base URLs march to distant drums, old helpers fade away,
Clean calls, small tokens, steady paths — a tidier day. 🌙

🚥 Pre-merge checks | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Solid & Clean Code ⚠️ Warning PR violates DRY principle with deprecation header logic duplicated across 7 files; recomputes sunset date on every request instead of using fixed deadline. Extract deprecation logic into reusable utility at lib/deprecation/getDeprecationHeaders.ts with fixed DEPRECATION_DATE constant; create URL encoding helper for parameter safety.

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

✨ Finishing touches
  • 📝 Generate docstrings

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
Contributor

@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: 2

🤖 Fix all issues with AI agents
In `@app/api/chat/create/route.ts`:
- Around line 10-19: getDeprecationHeaders currently recalculates the sunset
date per request using SUNSET_DAYS; change it to use a fixed sunset date source
(e.g., a new constant or environment variable like SUNSET_DATE or
DEPRECATION_SUNSET) so the Sunset header is a fixed RFC-8594 date instead of a
rolling window; update getDeprecationHeaders to read and format that fixed date
(keep Deprecation and Link as-is using NEW_API_BASE_URL) and remove the runtime
date arithmetic based on SUNSET_DAYS.

In `@hooks/useCreateChat.tsx`:
- Around line 85-106: Before calling response.json(), check the HTTP status on
the Response object (response.ok or response.status) returned by the fetch in
useCreateChat.tsx; if the response is not ok, handle it (e.g., read
response.text() or json() safely, log/throw a descriptive error including status
and body, and avoid treating the payload as CreateChatApiResponse). Update the
code around the fetch/response variable so non-2xx responses short-circuit error
handling (instead of relying only on data.status), and ensure downstream logic
that calls setDisplayName and await refetchConversations only runs for valid
successful responses.
🧹 Nitpick comments (1)
hooks/useCreateChat.tsx (1)

114-122: Remove unused userData?.account_id from dependency array.

userData is destructured from useUserProvider() (line 36) and userData?.account_id appears in the dependency array, but it's never referenced inside the effect body. This appears to be leftover from the previous implementation and should be removed to avoid misleading readers and unnecessary re-executions.

♻️ Suggested fix
   }, [
     isOptimisticChatItem,
     chatRoom,
-    userData?.account_id,
     selectedArtist?.account_id,
     setDisplayName,
     accessToken,
     refetchConversations,
   ]);

If userData is no longer needed anywhere in the hook, consider removing the destructuring on line 36 as well.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4e5eee9 and e22ac12.

⛔ Files ignored due to path filters (1)
  • types/browser.types.ts is excluded by none and included by none
📒 Files selected for processing (10)
  • app/api/browser/act/route.ts
  • app/api/browser/agent/route.ts
  • app/api/browser/extract/route.ts
  • app/api/browser/observe/route.ts
  • app/api/chat/create/route.ts
  • app/api/funnel_analysis/comments/route.ts
  • app/api/get_fans_profiles/route.ts
  • hooks/useCreateChat.tsx
  • lib/browser/hasBooleanSuccess.ts
  • lib/supabase/getFunnelAnalyticsComments.tsx
💤 Files with no reviewable changes (8)
  • lib/supabase/getFunnelAnalyticsComments.tsx
  • app/api/get_fans_profiles/route.ts
  • app/api/browser/agent/route.ts
  • app/api/browser/observe/route.ts
  • app/api/funnel_analysis/comments/route.ts
  • app/api/browser/extract/route.ts
  • app/api/browser/act/route.ts
  • lib/browser/hasBooleanSuccess.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{tsx,ts,jsx,js}

📄 CodeRabbit inference engine (.cursor/rules/component-design.mdc)

**/*.{tsx,ts,jsx,js}: Use semantic HTML elements appropriate to the component's role
Ensure keyboard navigation and focus management in UI components
Provide proper ARIA roles/states and test with screen readers
Start with semantic HTML first, then augment with ARIA if needed
Support both controlled and uncontrolled state in components
Wrap a single HTML element per component (no multiple root elements)
Favor composition over inheritance in component design
Expose clear APIs via props/slots for component customization
Use asChild pattern for flexible element types in components
Support polymorphism with as prop when appropriate
Use @radix-ui/react-* primitives for behavior and accessibility
Use class-variance-authority (CVA) for component variants
Use @radix-ui/react-slot for implementing asChild pattern
Use @radix-ui/react-use-controllable-state for state management
Follow shadcn/ui component structure and naming conventions
Use cn() utility combining clsx and tailwind-merge for class merging
Export both component and variant functions (e.g., Button, buttonVariants)
Use @radix-ui/react-icons for UI component icons (not Lucide React)
Use lucide-react for application icons and illustrations
Use framer-motion for animations and transitions
Use next-themes for theme management
Use tailwindcss-animate for CSS animations
Use sonner for toast notifications
Use embla-carousel-react for carousels
Use react-resizable-panels for resizable layouts
Provide defaultValue and onValueChange props for state management
Use data-state attribute for visual component states (open/closed, loading, etc.)
Use data-slot attribute for component identification
Use kebab-case naming for data attributes (e.g., data-slot="form-field")
Follow class order in Tailwind: base → variants → conditionals → user overrides
Define component variants outside components to avoid recreation on re-render
Implement focus trapping in modal/dialog components
Store...

Files:

  • hooks/useCreateChat.tsx
  • app/api/chat/create/route.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/component-design.mdc)

**/*.{tsx,ts}: Extend native HTML attributes using React.ComponentProps<"element"> pattern
Export component prop types with explicit ComponentNameProps naming convention

Files:

  • hooks/useCreateChat.tsx
  • app/api/chat/create/route.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/stagehand.mdc)

**/*.{ts,tsx}: Plan instructions using Stagehand observe method before executing actions (e.g., const results = await page.observe("Click the sign in button");)
Cache the results of observe to avoid unexpected DOM changes
Keep act actions atomic and specific (e.g., "Click the sign in button" not "Sign in to the website"). Avoid actions that are more than one step.
Use variable substitution with the variables parameter in act for dynamic form filling (e.g., action: "Enter Name: %name%", variables: { name: "John Doe" })
Always use Zod schemas for structured data extraction with the extract method (e.g., schema: z.object({ text: z.string() }))
Wrap array extractions in a single object when extracting multiple items using extract (e.g., schema: z.object({ buttons: z.array(z.string()) }))
Use explicit instruction and schema parameters when calling extract method
Import Stagehand types from @browserbasehq/stagehand package (e.g., import { Stagehand, Page, BrowserContext } from "@browserbasehq/stagehand";)
Initialize Stagehand with new Stagehand() constructor and call await stagehand.init() before using page automation methods
Implement main automation logic in functions that accept { page, context, stagehand } parameters
Provide specific instructions to agents instead of vague ones (e.g., "Navigate to products page and filter by 'Electronics'" not "Do some stuff on this page")
Break down complex agent tasks into smaller steps for better execution
Use error handling with try/catch blocks when executing agent tasks
Combine agents for navigation with traditional methods for precise data extraction

**/*.{ts,tsx}: Create single-responsibility components with obvious data flow
Use strict TypeScript types with zero 'any' types
Follow Next.js optimization guides for performance

Files:

  • hooks/useCreateChat.tsx
  • app/api/chat/create/route.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx,js}: Write minimal code - use only the absolute minimum code needed
Ensure code is self-documenting through precise naming with verbs for functions and nouns for variables
Add short comments only when necessary to clarify non-obvious logic
Implement built-in security practices for authentication and data handling
Consider if code can be split into smaller functions before implementing
Avoid unnecessary abstractions during implementation
Ensure code clarity is suitable for understanding by junior developers

Files:

  • hooks/useCreateChat.tsx
  • app/api/chat/create/route.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use Single Responsibility Principle: One function per file with clear naming
Remove all console.log statements before merging to production
Write comments to explain 'why', not 'what'; prefer self-documenting code

Files:

  • hooks/useCreateChat.tsx
  • app/api/chat/create/route.ts
app/api/**/*.ts

⚙️ CodeRabbit configuration file

app/api/**/*.ts: For API routes, ensure:

  • Single responsibility per route handler
  • Proper error handling and validation
  • Use dependency injection for services
  • Follow RESTful principles
  • Validate input parameters
  • Return consistent response formats
  • DRY: Extract common validation and error handling logic
  • KISS: Use simple, straightforward request/response patterns

Files:

  • app/api/chat/create/route.ts
🧬 Code graph analysis (1)
hooks/useCreateChat.tsx (2)
hooks/useAccessToken.ts (1)
  • useAccessToken (9-38)
lib/consts.ts (1)
  • NEW_API_BASE_URL (4-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: Run evaluations
🔇 Additional comments (5)
app/api/chat/create/route.ts (2)

21-25: LGTM — Clear deprecation signaling.

The JSDoc @deprecated annotation clearly communicates the endpoint's status to developers, and initializing deprecationHeaders at the start of the handler ensures consistent header attachment across all response paths. This follows the Single Responsibility Principle by centralizing header generation.


32-43: LGTM — Consistent deprecation headers on all response paths.

All four response paths (validation error, room creation error, success, and catch-all error) correctly include the deprecation headers. This ensures clients receive migration guidance regardless of the outcome.

Also applies to: 56-68, 84-93, 94-106

hooks/useCreateChat.tsx (3)

10-25: LGTM — Well-defined local interfaces.

The CreateChatApiRequest and CreateChatApiResponse interfaces provide clear type contracts for the new API. Defining them locally in the hook is appropriate given their single-use scope, keeping the code self-contained.


41-43: LGTM — Proper guard for authentication.

The early return when accessToken is falsy prevents unauthorized requests from being sent. This is clean and defensive.


79-92: LGTM — Clean request construction with Bearer auth.

The request body construction is straightforward, and the Authorization header correctly uses the Bearer token pattern. The use of NEW_API_BASE_URL ensures environment-appropriate routing (prod vs. test).

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +10 to +19
function getDeprecationHeaders(): Record<string, string> {
const sunsetDate = new Date();
sunsetDate.setDate(sunsetDate.getDate() + SUNSET_DAYS);

return {
Deprecation: "true",
Sunset: sunsetDate.toUTCString(),
Link: `<${NEW_API_BASE_URL}/api/chats>; rel="deprecation"`,
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Sunset date should be fixed, not recalculated on every request.

The current implementation recalculates the sunset date on each request, creating a perpetually rolling 90-day window. Per RFC 8594, the Sunset header should indicate a specific fixed date when the API will be decommissioned—this gives clients a concrete deadline to migrate.

Consider computing the sunset date once (e.g., from a constant or environment variable representing the actual sunset date) rather than dynamically:

🛠️ Suggested fix
-const SUNSET_DAYS = 90;
+// Fixed sunset date: 90 days from initial deprecation (2026-01-16)
+const SUNSET_DATE = new Date("2026-04-16T00:00:00Z");

 function getDeprecationHeaders(): Record<string, string> {
-  const sunsetDate = new Date();
-  sunsetDate.setDate(sunsetDate.getDate() + SUNSET_DAYS);
-
   return {
     Deprecation: "true",
-    Sunset: sunsetDate.toUTCString(),
+    Sunset: SUNSET_DATE.toUTCString(),
     Link: `<${NEW_API_BASE_URL}/api/chats>; rel="deprecation"`,
   };
 }
🤖 Prompt for AI Agents
In `@app/api/chat/create/route.ts` around lines 10 - 19, getDeprecationHeaders
currently recalculates the sunset date per request using SUNSET_DAYS; change it
to use a fixed sunset date source (e.g., a new constant or environment variable
like SUNSET_DATE or DEPRECATION_SUNSET) so the Sunset header is a fixed RFC-8594
date instead of a rolling window; update getDeprecationHeaders to read and
format that fixed date (keep Deprecation and Link as-is using NEW_API_BASE_URL)
and remove the runtime date arithmetic based on SUNSET_DAYS.

Comment on lines +85 to +106
const response = await fetch(`${NEW_API_BASE_URL}/api/chats`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify(requestBody),
});

const data: CreateChatResponse = await response.json();
const data: CreateChatApiResponse = await response.json();

if (data.success && data.room) {
if (data.status === "success" && data.chat) {
// Update display name with the room topic
setDisplayName(data.room.topic);
if (data.chat.topic) {
setDisplayName(data.chat.topic);
}

// Remove optimistic flag from memory and treat it as a normal memory.
// It will re-enable 3 dots on the chat item.
await refetchConversations();
} else {
console.error("Failed to create chat:", data.error);
console.error("Failed to create chat:", data.message);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing HTTP status check before parsing JSON response.

If the server returns a non-2xx status (e.g., 401, 500), the response body might not match CreateChatApiResponse or might not be valid JSON. Relying solely on data.status assumes the response always parses successfully.

🛠️ Suggested fix
         const response = await fetch(`${NEW_API_BASE_URL}/api/chats`, {
           method: "POST",
           headers: {
             "Content-Type": "application/json",
             Authorization: `Bearer ${accessToken}`,
           },
           body: JSON.stringify(requestBody),
         });

+        if (!response.ok) {
+          console.error("Chat creation failed with status:", response.status);
+          return;
+        }
+
         const data: CreateChatApiResponse = await response.json();
🤖 Prompt for AI Agents
In `@hooks/useCreateChat.tsx` around lines 85 - 106, Before calling
response.json(), check the HTTP status on the Response object (response.ok or
response.status) returned by the fetch in useCreateChat.tsx; if the response is
not ok, handle it (e.g., read response.text() or json() safely, log/throw a
descriptive error including status and body, and avoid treating the payload as
CreateChatApiResponse). Update the code around the fetch/response variable so
non-2xx responses short-circuit error handling (instead of relying only on
data.status), and ensure downstream logic that calls setDisplayName and await
refetchConversations only runs for valid successful responses.

Update useArtistAgents hook to call recoup-api's /api/artist-agents
endpoint directly with Bearer token authentication.

- Updated hook to use NEW_API_BASE_URL and Bearer token auth
- Added deprecation headers to legacy /api/agents endpoint (RFC 8594)
- Legacy endpoint still functional during 90-day sunset period

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Update fetchAgentTemplates to call recoup-api with Bearer token
- Add accessToken to useAgentData hook
- Add RFC 8594 deprecation headers to legacy GET endpoint

Co-Authored-By: Claude Opus 4.5 <[email protected]>
const queryString = socialIds?.map((id) => `socialId=${id}`).join("&");
const response = await fetch(`/api/agents?${queryString}`);
const data = await response.json();
if (data.error) return;
Copy link

Choose a reason for hiding this comment

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

The getAgents async function is missing error handling, which will cause unhandled promise rejections if the fetch or JSON parsing fails. This could manifest as uncaught errors in the browser console.

View Details
📝 Patch Details
diff --git a/hooks/useArtistAgents.ts b/hooks/useArtistAgents.ts
index 723074c7..93f06a15 100644
--- a/hooks/useArtistAgents.ts
+++ b/hooks/useArtistAgents.ts
@@ -18,35 +18,39 @@ const useArtistAgents = () => {
 
   useEffect(() => {
     const getAgents = async () => {
-      if (!selectedArtist) return;
-      if (!accessToken) return;
+      try {
+        if (!selectedArtist) return;
+        if (!accessToken) return;
 
-      const socialIds = selectedArtist.account_socials?.map(
-        (social: SOCIAL) => social.id
-      );
+        const socialIds = selectedArtist.account_socials?.map(
+          (social: SOCIAL) => social.id
+        );
 
-      if (!socialIds?.length) return;
+        if (!socialIds?.length) return;
 
-      const queryString = socialIds.map((id) => `socialId=${id}`).join("&");
+        const queryString = socialIds.map((id) => `socialId=${id}`).join("&");
 
-      const response = await fetch(
-        `${NEW_API_BASE_URL}/api/artist-agents?${queryString}`,
-        {
-          headers: {
-            Authorization: `Bearer ${accessToken}`,
-          },
-        }
-      );
+        const response = await fetch(
+          `${NEW_API_BASE_URL}/api/artist-agents?${queryString}`,
+          {
+            headers: {
+              Authorization: `Bearer ${accessToken}`,
+            },
+          }
+        );
 
-      const data: ArtistAgentsApiResponse = await response.json();
+        const data: ArtistAgentsApiResponse = await response.json();
 
-      if (data.status === "error") {
-        console.error("Failed to fetch artist agents:", data.message);
-        return;
-      }
+        if (data.status === "error") {
+          console.error("Failed to fetch artist agents:", data.message);
+          return;
+        }
 
-      if (data.agents) {
-        setAgents(data.agents);
+        if (data.agents) {
+          setAgents(data.agents);
+        }
+      } catch (error) {
+        console.error("Failed to fetch artist agents:", error);
       }
     };
     getAgents();

Analysis

Missing error handling in useArtistAgents hook causes unhandled promise rejections

What fails: The getAgents async function in useArtistAgents.ts (lines 19-52) lacks try-catch error handling for the fetch() call (line 32) and response.json() call (line 37). When the API request fails due to network errors or invalid JSON responses, the error is not caught and propagates as an unhandled promise rejection.

How to reproduce:

  1. In a browser with this hook active, trigger a network error (e.g., disable network in DevTools or use a mock server that returns an error)
  2. OR trigger a JSON parsing error (e.g., mock the API to return HTML instead of JSON)
  3. Observe the browser console - an unhandled promise rejection error appears

Result: Browser console displays: Uncaught (in promise) <error details>. This indicates unhandled async errors that violate React best practices per React error handling documentation which states: "In order for errors inside useEffect to be caught, try/catch should be placed inside as well."

Expected behavior: Errors from network requests or JSON parsing should be caught with a try-catch block inside the async function, preventing unhandled promise rejections and allowing proper error logging. This matches the pattern used in useCreateChat.tsx (lines 43-110).

Implementation: Added try-catch wrapper around all async operations in the getAgents function to catch fetch and JSON parsing errors, with error logging to console.

- Update useAgentToggleFavorite.ts to call recoup-api with Bearer token
- Add RFC 8594 deprecation headers to old favorites endpoint

Co-Authored-By: Claude Opus 4.5 <[email protected]>
};

const response = await fetch("/api/chat/create", {
const response = await fetch(`${NEW_API_BASE_URL}/api/chats`, {
Copy link

Choose a reason for hiding this comment

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

Missing HTTP status check before parsing JSON response, deviating from the established codebase pattern. If the external API returns an error response, the code attempts to parse it without first validating the HTTP status.

View Details
📝 Patch Details
diff --git a/hooks/useCreateChat.tsx b/hooks/useCreateChat.tsx
index 1f746ebd..bf715f57 100644
--- a/hooks/useCreateChat.tsx
+++ b/hooks/useCreateChat.tsx
@@ -91,6 +91,10 @@ const useCreateChat = ({
           body: JSON.stringify(requestBody),
         });
 
+        if (!response.ok) {
+          throw new Error(`Failed to create chat: HTTP ${response.status}`);
+        }
+
         const data: CreateChatApiResponse = await response.json();
 
         if (data.status === "success" && data.chat) {

Analysis

Missing HTTP status check in useCreateChat before parsing JSON response

What fails: useCreateChat.tsx calls response.json() without checking response.ok first. When the API returns an error response (e.g., HTTP 400, 500), the JSON parsing may fail or succeed with an error JSON structure, but the HTTP status code is not validated. This deviates from the established pattern used throughout the codebase.

How to reproduce: Mock the API to return an HTTP error status (e.g., 500 or 404) with any response body. The code will either:

  1. Throw an unhandled JSON parsing error if the response body is not valid JSON
  2. Continue and attempt to process error JSON as if it were success, silently ignoring the HTTP error
// Example: API returns 500 with HTML error page
const response = await fetch(...); // Returns 500 status
const data = await response.json(); // Throws because HTML is not valid JSON

Result: Error handling is inconsistent with HTTP semantics. The HTTP status code is lost, making debugging difficult.

Expected: Check response.ok immediately after fetch and before calling response.json(), as implemented in fetchAgentTemplates.ts (line 28) and useAgentToggleFavorite.ts (line 24). This is the established pattern throughout the codebase for all API calls.

Fix applied: Added HTTP status validation:

if (!response.ok) {
  throw new Error(`Failed to create chat: HTTP  

This matches the pattern used consistently in: fetchAgentTemplates.ts, useAgentToggleFavorite.ts, AgentCreator.tsx, AgentDeleteButton.tsx, CreateAgentDialog.tsx, and many other files in the codebase.

Comment on lines +32 to +41
const response = await fetch(
`${NEW_API_BASE_URL}/api/artist-agents?${queryString}`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
);

const data: ArtistAgentsApiResponse = await response.json();
Copy link

Choose a reason for hiding this comment

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

Missing HTTP status check before parsing JSON response. If the external API returns an error, the code silently fails without proper error handling or user notification.

View Details
📝 Patch Details
diff --git a/hooks/useArtistAgents.ts b/hooks/useArtistAgents.ts
index 723074c7..9f6b4ba0 100644
--- a/hooks/useArtistAgents.ts
+++ b/hooks/useArtistAgents.ts
@@ -38,6 +38,13 @@ const useArtistAgents = () => {
         }
       );
 
+      if (!response.ok) {
+        console.error(
+          `Failed to fetch artist agents: HTTP ${response.status}`
+        );
+        return;
+      }
+
       const data: ArtistAgentsApiResponse = await response.json();
 
       if (data.status === "error") {

Analysis

Missing HTTP status check in useArtistAgents hook causes unhandled errors on API failures

What fails: useArtistAgents() hook does not check response.ok before parsing JSON, causing unhandled promise rejections when the API returns HTTP error status codes.

How to reproduce:

# Simulate API returning HTTP 500 with invalid JSON (HTML error page)
# The hook will call response.json() which throws, creating an unhandled promise rejection
# Users see console error but no UI feedback

What happens vs expected:

  • Current behavior: When external API returns HTTP 500+ with non-JSON response body (e.g., HTML error page), response.json() throws an exception. This becomes an unhandled promise rejection in the useEffect, logged to console but not surfaced to users. No indication that the fetch failed.
  • Expected behavior: Check response.ok immediately after fetch (per MDN best practice) before attempting to parse the response. Log a clear error message and return early.

Note: This pattern deviates from the established codebase practice seen in:

  • fetchAgentTemplates.ts (line 28)
  • useAgentToggleFavorite.ts (line 35)
  • useAccountOrganizations.ts
  • useArtistFans.ts

All of these files check response.ok immediately after fetching, before calling response.json().

Update AgentCreator.tsx to fetch from recoup-api directly.
Add RFC 8594 deprecation headers to the old /api/agent-creator endpoint.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link
Contributor

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/api/agent-templates/favorites/route.ts (1)

9-53: Sunset header should be fixed, not recalculated per request.

As written, the Sunset header always lands 90 days in the future, so the deprecation window never closes. Use a fixed sunset date (constant or config) aligned with the planned cutoff.

🤖 Fix all issues with AI agents
In `@app/api/agent-templates/route.ts`:
- Around line 13-23: The Sunset header is being recalculated on every request
inside getDeprecationHeaders using new Date(), producing a rolling 90-day
window; instead compute a single fixed sunset date once (at module
initialization or from configuration/env) and reuse it for every response.
Replace the per-request calculation in getDeprecationHeaders with a constant
(e.g., SUNSET_DATE or DEPRECATION_SUNSET) derived from SUNSET_DAYS at module
load or read a fixed date from config, and return sunsetDate.toUTCString() from
that constant while keeping Deprecation and Link as-is (referencing
getDeprecationHeaders, SUNSET_DAYS, and NEW_API_BASE_URL).

In `@app/api/agents/route.ts`:
- Around line 5-41: The helper getDeprecationHeaders currently computes a
rolling sunset date using SUNSET_DAYS and new Date() which makes the Sunset
header always 90 days in the future; instead define a fixed sunset constant
(e.g., DEPRECATION_SUNSET or FIXED_SUNSET_ISO) representing the planned removal
date and use that constant in getDeprecationHeaders (replace the dynamic
sunsetDate logic), keeping the other headers (Deprecation, Link with
NEW_API_BASE_URL) intact so the Sunset header is stable across requests.

In `@components/Agents/useAgentToggleFavorite.ts`:
- Around line 10-17: Remove the local userData?.id guard inside
handleToggleFavorite and let the backend authenticate via the Bearer token;
specifically, in handleToggleFavorite (which currently checks userData?.id,
templateId and accessToken) delete the userData?.id check so the request can
proceed when templateId exists and rely on accessToken for auth. Also replace
the silent return when accessToken is missing with a user-facing error path
(e.g., surface a toast/error message or throw a handled error) so missing token
is reported to the user; keep the existing payload using templateId and
isFavourite and preserve the templateId truthiness check.
♻️ Duplicate comments (1)
hooks/useArtistAgents.ts (1)

20-41: Add error handling around fetch/JSON to avoid unhandled rejections.

A failed network request or non-JSON response will currently throw and escape the effect. Wrap the async block in try/catch and check response.ok before parsing.

Suggested fix
     const getAgents = async () => {
       if (!selectedArtist) return;
       if (!accessToken) return;

       const socialIds = selectedArtist.account_socials?.map(
         (social: SOCIAL) => social.id
       );

       if (!socialIds?.length) return;

       const queryString = socialIds.map((id) => `socialId=${id}`).join("&");

-      const response = await fetch(
-        `${NEW_API_BASE_URL}/api/artist-agents?${queryString}`,
-        {
-          headers: {
-            Authorization: `Bearer ${accessToken}`,
-          },
-        }
-      );
-
-      const data: ArtistAgentsApiResponse = await response.json();
-
-      if (data.status === "error") {
-        console.error("Failed to fetch artist agents:", data.message);
-        return;
-      }
-
-      if (data.agents) {
-        setAgents(data.agents);
-      }
+      try {
+        const response = await fetch(
+          `${NEW_API_BASE_URL}/api/artist-agents?${queryString}`,
+          {
+            headers: {
+              Authorization: `Bearer ${accessToken}`,
+            },
+          }
+        );
+
+        if (!response.ok) {
+          console.error("Failed to fetch artist agents:", response.status);
+          return;
+        }
+
+        const data: ArtistAgentsApiResponse = await response.json();
+
+        if (data.status === "error") {
+          console.error("Failed to fetch artist agents:", data.message);
+          return;
+        }
+
+        if (data.agents) {
+          setAgents(data.agents);
+        }
+      } catch (error) {
+        console.error("Failed to fetch artist agents:", error);
+      }
     };

As per coding guidelines, handle errors in hooks.

Also applies to: 43-49

🧹 Nitpick comments (1)
lib/agent-templates/fetchAgentTemplates.ts (1)

11-38: URL-encoding the query parameter is recommended, but call sites are correct.

All call sites properly pass accessToken as the second argument, and the query is properly guarded with enabled: !!userData?.id && !!accessToken. The function's runtime check also validates the token presence.

Consider adding encodeURIComponent() around userData.id for consistent URL safety as a minor security hardening measure:

const res = await fetch(
-  `${NEW_API_BASE_URL}/api/agent-templates?userId=${userData?.id}`,
+  `${NEW_API_BASE_URL}/api/agent-templates?userId=${encodeURIComponent(userData.id)}`,
   {
     headers: {
       Authorization: `Bearer ${accessToken}`,
     },
   }
);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e22ac12 and ce8e8df.

📒 Files selected for processing (7)
  • app/api/agent-templates/favorites/route.ts
  • app/api/agent-templates/route.ts
  • app/api/agents/route.ts
  • components/Agents/useAgentData.ts
  • components/Agents/useAgentToggleFavorite.ts
  • hooks/useArtistAgents.ts
  • lib/agent-templates/fetchAgentTemplates.ts
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{tsx,ts,jsx,js}

📄 CodeRabbit inference engine (.cursor/rules/component-design.mdc)

**/*.{tsx,ts,jsx,js}: Use semantic HTML elements appropriate to the component's role
Ensure keyboard navigation and focus management in UI components
Provide proper ARIA roles/states and test with screen readers
Start with semantic HTML first, then augment with ARIA if needed
Support both controlled and uncontrolled state in components
Wrap a single HTML element per component (no multiple root elements)
Favor composition over inheritance in component design
Expose clear APIs via props/slots for component customization
Use asChild pattern for flexible element types in components
Support polymorphism with as prop when appropriate
Use @radix-ui/react-* primitives for behavior and accessibility
Use class-variance-authority (CVA) for component variants
Use @radix-ui/react-slot for implementing asChild pattern
Use @radix-ui/react-use-controllable-state for state management
Follow shadcn/ui component structure and naming conventions
Use cn() utility combining clsx and tailwind-merge for class merging
Export both component and variant functions (e.g., Button, buttonVariants)
Use @radix-ui/react-icons for UI component icons (not Lucide React)
Use lucide-react for application icons and illustrations
Use framer-motion for animations and transitions
Use next-themes for theme management
Use tailwindcss-animate for CSS animations
Use sonner for toast notifications
Use embla-carousel-react for carousels
Use react-resizable-panels for resizable layouts
Provide defaultValue and onValueChange props for state management
Use data-state attribute for visual component states (open/closed, loading, etc.)
Use data-slot attribute for component identification
Use kebab-case naming for data attributes (e.g., data-slot="form-field")
Follow class order in Tailwind: base → variants → conditionals → user overrides
Define component variants outside components to avoid recreation on re-render
Implement focus trapping in modal/dialog components
Store...

Files:

  • app/api/agent-templates/route.ts
  • lib/agent-templates/fetchAgentTemplates.ts
  • components/Agents/useAgentToggleFavorite.ts
  • components/Agents/useAgentData.ts
  • hooks/useArtistAgents.ts
  • app/api/agent-templates/favorites/route.ts
  • app/api/agents/route.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/component-design.mdc)

**/*.{tsx,ts}: Extend native HTML attributes using React.ComponentProps<"element"> pattern
Export component prop types with explicit ComponentNameProps naming convention

Files:

  • app/api/agent-templates/route.ts
  • lib/agent-templates/fetchAgentTemplates.ts
  • components/Agents/useAgentToggleFavorite.ts
  • components/Agents/useAgentData.ts
  • hooks/useArtistAgents.ts
  • app/api/agent-templates/favorites/route.ts
  • app/api/agents/route.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/stagehand.mdc)

**/*.{ts,tsx}: Plan instructions using Stagehand observe method before executing actions (e.g., const results = await page.observe("Click the sign in button");)
Cache the results of observe to avoid unexpected DOM changes
Keep act actions atomic and specific (e.g., "Click the sign in button" not "Sign in to the website"). Avoid actions that are more than one step.
Use variable substitution with the variables parameter in act for dynamic form filling (e.g., action: "Enter Name: %name%", variables: { name: "John Doe" })
Always use Zod schemas for structured data extraction with the extract method (e.g., schema: z.object({ text: z.string() }))
Wrap array extractions in a single object when extracting multiple items using extract (e.g., schema: z.object({ buttons: z.array(z.string()) }))
Use explicit instruction and schema parameters when calling extract method
Import Stagehand types from @browserbasehq/stagehand package (e.g., import { Stagehand, Page, BrowserContext } from "@browserbasehq/stagehand";)
Initialize Stagehand with new Stagehand() constructor and call await stagehand.init() before using page automation methods
Implement main automation logic in functions that accept { page, context, stagehand } parameters
Provide specific instructions to agents instead of vague ones (e.g., "Navigate to products page and filter by 'Electronics'" not "Do some stuff on this page")
Break down complex agent tasks into smaller steps for better execution
Use error handling with try/catch blocks when executing agent tasks
Combine agents for navigation with traditional methods for precise data extraction

**/*.{ts,tsx}: Create single-responsibility components with obvious data flow
Use strict TypeScript types with zero 'any' types
Follow Next.js optimization guides for performance

Files:

  • app/api/agent-templates/route.ts
  • lib/agent-templates/fetchAgentTemplates.ts
  • components/Agents/useAgentToggleFavorite.ts
  • components/Agents/useAgentData.ts
  • hooks/useArtistAgents.ts
  • app/api/agent-templates/favorites/route.ts
  • app/api/agents/route.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx,js}: Write minimal code - use only the absolute minimum code needed
Ensure code is self-documenting through precise naming with verbs for functions and nouns for variables
Add short comments only when necessary to clarify non-obvious logic
Implement built-in security practices for authentication and data handling
Consider if code can be split into smaller functions before implementing
Avoid unnecessary abstractions during implementation
Ensure code clarity is suitable for understanding by junior developers

Files:

  • app/api/agent-templates/route.ts
  • lib/agent-templates/fetchAgentTemplates.ts
  • components/Agents/useAgentToggleFavorite.ts
  • components/Agents/useAgentData.ts
  • hooks/useArtistAgents.ts
  • app/api/agent-templates/favorites/route.ts
  • app/api/agents/route.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use Single Responsibility Principle: One function per file with clear naming
Remove all console.log statements before merging to production
Write comments to explain 'why', not 'what'; prefer self-documenting code

Files:

  • app/api/agent-templates/route.ts
  • lib/agent-templates/fetchAgentTemplates.ts
  • components/Agents/useAgentToggleFavorite.ts
  • components/Agents/useAgentData.ts
  • hooks/useArtistAgents.ts
  • app/api/agent-templates/favorites/route.ts
  • app/api/agents/route.ts
app/api/**/*.ts

⚙️ CodeRabbit configuration file

app/api/**/*.ts: For API routes, ensure:

  • Single responsibility per route handler
  • Proper error handling and validation
  • Use dependency injection for services
  • Follow RESTful principles
  • Validate input parameters
  • Return consistent response formats
  • DRY: Extract common validation and error handling logic
  • KISS: Use simple, straightforward request/response patterns

Files:

  • app/api/agent-templates/route.ts
  • app/api/agent-templates/favorites/route.ts
  • app/api/agents/route.ts
lib/**/*.ts

⚙️ CodeRabbit configuration file

lib/**/*.ts: For utility functions, ensure:

  • Pure functions when possible
  • Single responsibility per function
  • Proper error handling
  • Use TypeScript for type safety
  • Avoid side effects
  • Keep functions under 50 lines
  • DRY: Consolidate similar logic into shared utilities
  • KISS: Prefer simple, readable implementations over clever optimizations

Files:

  • lib/agent-templates/fetchAgentTemplates.ts
**/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/components/**/*.{ts,tsx}: Use @radix-ui/react-* primitives with class-variance-authority (CVA) for component styling
Use cn() utility for class merging in components
Always include accessibility in components: use semantic HTML, ARIA attributes, and keyboard navigation

Files:

  • components/Agents/useAgentToggleFavorite.ts
  • components/Agents/useAgentData.ts
hooks/**/*.ts

⚙️ CodeRabbit configuration file

hooks/**/*.ts: For custom hooks, ensure:

  • Single responsibility per hook
  • Return consistent interface
  • Handle edge cases and errors
  • Use proper dependency arrays
  • Keep hooks focused and reusable
  • Follow naming convention (use prefix)
  • DRY: Extract common hook logic into shared utilities
  • KISS: Avoid complex hook compositions, prefer simple state management

Files:

  • hooks/useArtistAgents.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: Recoupable-com/Recoup-Chat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-07T17:34:21.923Z
Learning: Use Next.js 16 with App Router and React 19
Learnt from: CR
Repo: Recoupable-com/Recoup-Chat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-07T17:34:21.923Z
Learning: Use Supabase for database operations with types generated via `pnpm update-types` command
📚 Learning: 2025-11-29T16:42:42.954Z
Learnt from: CR
Repo: Recoupable-com/Recoup-Chat PR: 0
File: .cursor/rules/stagehand.mdc:0-0
Timestamp: 2025-11-29T16:42:42.954Z
Learning: Applies to **/*.{ts,tsx} : Break down complex agent tasks into smaller steps for better execution

Applied to files:

  • lib/agent-templates/fetchAgentTemplates.ts
  • components/Agents/useAgentData.ts
📚 Learning: 2025-11-29T16:42:42.954Z
Learnt from: CR
Repo: Recoupable-com/Recoup-Chat PR: 0
File: .cursor/rules/stagehand.mdc:0-0
Timestamp: 2025-11-29T16:42:42.954Z
Learning: Applies to **/*.{ts,tsx} : Use error handling with try/catch blocks when executing agent tasks

Applied to files:

  • hooks/useArtistAgents.ts
🧬 Code graph analysis (5)
lib/agent-templates/fetchAgentTemplates.ts (2)
lib/supabase/accounts/getAccountWithDetails.ts (1)
  • AccountWithDetails (9-12)
lib/consts.ts (1)
  • NEW_API_BASE_URL (4-6)
components/Agents/useAgentToggleFavorite.ts (2)
hooks/useAccessToken.ts (1)
  • useAccessToken (9-38)
lib/consts.ts (1)
  • NEW_API_BASE_URL (4-6)
components/Agents/useAgentData.ts (1)
hooks/useAccessToken.ts (1)
  • useAccessToken (9-38)
hooks/useArtistAgents.ts (2)
hooks/useAccessToken.ts (1)
  • useAccessToken (9-38)
lib/consts.ts (1)
  • NEW_API_BASE_URL (4-6)
app/api/agents/route.ts (1)
lib/consts.ts (1)
  • NEW_API_BASE_URL (4-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: Run evaluations
🔇 Additional comments (4)
app/api/agent-templates/route.ts (1)

30-57: Deprecation headers are returned on both success and error paths.

This keeps deprecation metadata visible to clients regardless of response outcome.

components/Agents/useAgentData.ts (1)

6-25: Access token is now threaded through agent template fetch and prefetch.

Good to ensure authenticated requests once a token is available.

Also applies to: 69-73

components/Agents/useAgentToggleFavorite.ts (1)

4-5: Auth + base URL wiring looks solid.

Clear, maintainable request setup with explicit Authorization and Content-Type headers.

Also applies to: 20-33

hooks/useArtistAgents.ts (1)

5-12: Nice addition of a typed API response.

The explicit response shape improves clarity and future-proofing.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +13 to +23
const SUNSET_DAYS = 90;

function getDeprecationHeaders(): Record<string, string> {
const sunsetDate = new Date();
sunsetDate.setDate(sunsetDate.getDate() + SUNSET_DAYS);

return {
Deprecation: "true",
Sunset: sunsetDate.toUTCString(),
Link: `<${NEW_API_BASE_URL}/api/agent-templates>; rel="deprecation"`,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Sunset date is recalculated per request (rolling window).

Sunset is derived from new Date() on every request, so the header always stays ~90 days ahead and never reaches a fixed deprecation deadline. If the intent is a real 90‑day window, freeze the sunset date (constant or config) and reuse it for every response.

🧭 Suggested fix (use a fixed sunset date)
-const SUNSET_DAYS = 90;
+const SUNSET_DATE = new Date("2026-04-16T00:00:00Z"); // set to planned sunset date

 function getDeprecationHeaders(): Record<string, string> {
-  const sunsetDate = new Date();
-  sunsetDate.setDate(sunsetDate.getDate() + SUNSET_DAYS);
-
   return {
     Deprecation: "true",
-    Sunset: sunsetDate.toUTCString(),
+    Sunset: SUNSET_DATE.toUTCString(),
     Link: `<${NEW_API_BASE_URL}/api/agent-templates>; rel="deprecation"`,
   };
 }
🤖 Prompt for AI Agents
In `@app/api/agent-templates/route.ts` around lines 13 - 23, The Sunset header is
being recalculated on every request inside getDeprecationHeaders using new
Date(), producing a rolling 90-day window; instead compute a single fixed sunset
date once (at module initialization or from configuration/env) and reuse it for
every response. Replace the per-request calculation in getDeprecationHeaders
with a constant (e.g., SUNSET_DATE or DEPRECATION_SUNSET) derived from
SUNSET_DAYS at module load or read a fixed date from config, and return
sunsetDate.toUTCString() from that constant while keeping Deprecation and Link
as-is (referencing getDeprecationHeaders, SUNSET_DAYS, and NEW_API_BASE_URL).

Comment on lines +5 to +41
const SUNSET_DAYS = 90;

function getDeprecationHeaders(): Record<string, string> {
const sunsetDate = new Date();
sunsetDate.setDate(sunsetDate.getDate() + SUNSET_DAYS);

return {
Deprecation: "true",
Sunset: sunsetDate.toUTCString(),
Link: `<${NEW_API_BASE_URL}/api/artist-agents>; rel="deprecation"`,
};
}

/**
* @deprecated This endpoint is deprecated. Use recoup-api directly at recoup-api.vercel.app/api/artist-agents
*/
export async function GET(request: NextRequest) {
const deprecationHeaders = getDeprecationHeaders();

const { searchParams } = new URL(request.url);
const socialIds = searchParams.getAll("socialId");

if (!socialIds.length) {
return NextResponse.json(
{ error: "At least one Social ID is required" },
{ status: 400 },
{ status: 400, headers: deprecationHeaders },
);
}

try {
const agents = await getArtistAgents(socialIds);
return NextResponse.json(agents);
return NextResponse.json(agents, { headers: deprecationHeaders });
} catch (error) {
console.error("Error fetching segments:", error);
return NextResponse.json(
{ error: "Failed to fetch segments" },
{ status: 500 },
{ status: 500, headers: deprecationHeaders },
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Sunset date is recalculated per request (rolling window).

Same issue here: computing new Date() inside the helper keeps the Sunset header perpetually 90 days out. Use a fixed sunset date (constant or config) that reflects the planned removal date.

🤖 Prompt for AI Agents
In `@app/api/agents/route.ts` around lines 5 - 41, The helper
getDeprecationHeaders currently computes a rolling sunset date using SUNSET_DAYS
and new Date() which makes the Sunset header always 90 days in the future;
instead define a fixed sunset constant (e.g., DEPRECATION_SUNSET or
FIXED_SUNSET_ISO) representing the planned removal date and use that constant in
getDeprecationHeaders (replace the dynamic sunsetDate logic), keeping the other
headers (Deprecation, Link with NEW_API_BASE_URL) intact so the Sunset header is
stable across requests.

Comment on lines +10 to +17
const accessToken = useAccessToken();

const handleToggleFavorite = async (
templateId: string,
nextFavourite: boolean
) => {
if (!userData?.id || !templateId) return;

if (!accessToken) return;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -name "useAgentToggleFavorite.ts" -type f

Repository: Recoupable-com/Recoup-Chat

Length of output: 115


🏁 Script executed:

cat -n components/Agents/useAgentToggleFavorite.ts

Repository: Recoupable-com/Recoup-Chat

Length of output: 1895


🏁 Script executed:

# Search for how userData is used elsewhere in the file
rg "userData" components/Agents/ -A 3 -B 3

Repository: Recoupable-com/Recoup-Chat

Length of output: 8018


🏁 Script executed:

# Check if toast notifications are used in this codebase
rg "toast\." components/Agents/ -l | head -5

Repository: Recoupable-com/Recoup-Chat

Length of output: 113


🏁 Script executed:

# Look for the API endpoint being called
rg "NEW_API_BASE_URL" components/Agents/useAgentToggleFavorite.ts -A 5 -B 5

Repository: Recoupable-com/Recoup-Chat

Length of output: 827


Remove the userData?.id guard; let authentication drive the check.

The userData?.id check at line 16 blocks the operation even when a valid accessToken exists. Since the API payload (lines 28–31) contains only templateId and isFavourite—not userId—and the backend authenticates via the Bearer token, the frontend shouldn't gate the request on local state that may still be loading. Replace the silent return with a user-facing error when the token is missing.

Suggested adjustment
-    if (!userData?.id || !templateId) return;
-    if (!accessToken) return;
+    if (!templateId) return;
+    if (!accessToken) {
+      toast.error("Please sign in to update favorites.");
+      return;
+    }
🤖 Prompt for AI Agents
In `@components/Agents/useAgentToggleFavorite.ts` around lines 10 - 17, Remove the
local userData?.id guard inside handleToggleFavorite and let the backend
authenticate via the Bearer token; specifically, in handleToggleFavorite (which
currently checks userData?.id, templateId and accessToken) delete the
userData?.id check so the request can proceed when templateId exists and rely on
accessToken for auth. Also replace the silent return when accessToken is missing
with a user-facing error path (e.g., surface a toast/error message or throw a
handled error) so missing token is reported to the user; keep the existing
payload using templateId and isFavourite and preserve the templateId truthiness
check.

selectedArtist?.account_id,
setDisplayName,
email,
accessToken,
Copy link

Choose a reason for hiding this comment

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

The effect dependency array includes userData?.account_id, but this value is no longer used in the effect after removing it from the request body in the refactor. This will cause the effect to re-run unnecessarily when userData?.account_id changes, potentially triggering multiple chat creation attempts.

View Details
📝 Patch Details
diff --git a/hooks/useCreateChat.tsx b/hooks/useCreateChat.tsx
index 1f746ebd..b21a4ccd 100644
--- a/hooks/useCreateChat.tsx
+++ b/hooks/useCreateChat.tsx
@@ -114,7 +114,6 @@ const useCreateChat = ({
   }, [
     isOptimisticChatItem,
     chatRoom,
-    userData?.account_id,
     selectedArtist?.account_id,
     setDisplayName,
     accessToken,

Analysis

Unused dependency userData?.account_id in useCreateChat effect causes unnecessary re-runs

What fails: The useCreateChat hook re-runs whenever userData?.account_id changes, even though this value is no longer used in the effect after the refactor to migrate chat creation to the external Recoup API.

How to reproduce:

  1. Trigger a user re-authentication flow that changes userData?.account_id
  2. If isOptimisticChatItem is true and accessToken is valid, the effect will re-run
  3. The createChat() function will execute again, potentially sending duplicate POST requests to /api/chats

What was happening: Previously (before commit e22ac12), userData?.account_id was passed in the request body as accountId: userData?.account_id || "". When the external API began extracting account ID from the Privy Bearer token, this field was removed from the request body (lines 79-83), but the dependency array on line 117 was not updated.

Result vs Expected: The effect unnecessarily triggers on userData?.account_id changes, potentially creating duplicate chat items. After the API refactor, userData?.account_id is not referenced anywhere in the effect body and should not be a dependency.

Fix applied: Removed userData?.account_id from the dependency array. The effect now correctly depends only on: isOptimisticChatItem, chatRoom, selectedArtist?.account_id, setDisplayName, accessToken, and refetchConversations.

All remaining dependencies are used within the effect body.

Update client to fetch AI models from recoup-api instead of local endpoint.
Add RFC 8594 deprecation headers to local endpoint for 90-day sunset.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link
Contributor

@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: 3

🤖 Fix all issues with AI agents
In `@app/api/agent-creator/route.ts`:
- Around line 8-18: The current getDeprecationHeaders function recomputes
sunsetDate per request (using SUNSET_DAYS), so the window never closes; change
to compute a single fixed sunset timestamp at module initialization or read a
fixed date from an env var and use that value in getDeprecationHeaders.
Initialize a module‑level constant (e.g., FIXED_SUNSET_DATE or SUNSET_TIMESTAMP)
once using NEW_API_BASE_URL and SUNSET_DAYS or process.env.DEPRECATION_SUNSET,
then have getDeprecationHeaders return Deprecation, Sunset:
FIXED_SUNSET_DATE.toUTCString(), and Link using NEW_API_BASE_URL. Ensure the
fixed value is computed only once, not per call.

In `@app/api/ai/models/route.ts`:
- Around line 4-15: The Sunset date is being recomputed on every call to
getDeprecationHeaders(), causing the deadline to slide; instead compute the
sunset once at module load and reuse it. Create a module-level constant (e.g.,
SUNSET_DATE or PRECOMPUTED_SUNSET) by instantiating new Date() and adding
SUNSET_DAYS once, convert it to UTC string once (e.g., SUNSET_DATE_UTC) and have
getDeprecationHeaders() return headers using that constant (keeping Deprecation,
Sunset, and Link with NEW_API_BASE_URL) so the 90‑day window remains fixed.

In `@components/Agents/AgentCreator.tsx`:
- Around line 25-28: The fetch URL interpolation uses creatorId directly which
can break URLs for characters like ?, &, spaces or unicode; update the fetch
call that builds `${NEW_API_BASE_URL}/api/agent-creator?creatorId=${creatorId}`
to encode the creatorId (use encodeURIComponent on creatorId) before embedding
it so the request URL is always valid; ensure references in AgentCreator.tsx
(the fetch call creating res) and any other places that construct the same query
parameter are updated to use the encoded value.

Comment on lines +8 to +18
const SUNSET_DAYS = 90;

function getDeprecationHeaders(): Record<string, string> {
const sunsetDate = new Date();
sunsetDate.setDate(sunsetDate.getDate() + SUNSET_DAYS);

return {
Deprecation: "true",
Sunset: sunsetDate.toUTCString(),
Link: `<${NEW_API_BASE_URL}/api/agent-creator>; rel="deprecation"`,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Sunset date should be fixed, not recomputed per request.
As written, every request pushes the Sunset date out by 90 days, so the window never truly closes and clients get inconsistent timelines. Use a fixed date (env or constant) computed once.

💡 Proposed fix (example)
-const SUNSET_DAYS = 90;
+const SUNSET_DAYS = 90;
+const DEPRECATION_DATE = new Date("2026-01-16T00:00:00Z"); // set to actual deprecation start
+const SUNSET_DATE = new Date(DEPRECATION_DATE);
+SUNSET_DATE.setDate(SUNSET_DATE.getDate() + SUNSET_DAYS);

 function getDeprecationHeaders(): Record<string, string> {
-  const sunsetDate = new Date();
-  sunsetDate.setDate(sunsetDate.getDate() + SUNSET_DAYS);
-
   return {
-    Deprecation: "true",
-    Sunset: sunsetDate.toUTCString(),
+    Deprecation: DEPRECATION_DATE.toUTCString(),
+    Sunset: SUNSET_DATE.toUTCString(),
     Link: `<${NEW_API_BASE_URL}/api/agent-creator>; rel="deprecation"`,
   };
 }
🤖 Prompt for AI Agents
In `@app/api/agent-creator/route.ts` around lines 8 - 18, The current
getDeprecationHeaders function recomputes sunsetDate per request (using
SUNSET_DAYS), so the window never closes; change to compute a single fixed
sunset timestamp at module initialization or read a fixed date from an env var
and use that value in getDeprecationHeaders. Initialize a module‑level constant
(e.g., FIXED_SUNSET_DATE or SUNSET_TIMESTAMP) once using NEW_API_BASE_URL and
SUNSET_DAYS or process.env.DEPRECATION_SUNSET, then have getDeprecationHeaders
return Deprecation, Sunset: FIXED_SUNSET_DATE.toUTCString(), and Link using
NEW_API_BASE_URL. Ensure the fixed value is computed only once, not per call.

Comment on lines +4 to +15
const SUNSET_DAYS = 90;

function getDeprecationHeaders(): Record<string, string> {
const sunsetDate = new Date();
sunsetDate.setDate(sunsetDate.getDate() + SUNSET_DAYS);

return {
Deprecation: "true",
Sunset: sunsetDate.toUTCString(),
Link: `<${NEW_API_BASE_URL}/api/ai/models>; rel="deprecation"`,
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Sunset date is sliding here too—should be fixed.
Recomputing the Sunset date on every request keeps pushing the deadline forward, which defeats the 90‑day sunset intent.

💡 Proposed fix (example)
-const SUNSET_DAYS = 90;
+const SUNSET_DAYS = 90;
+const DEPRECATION_DATE = new Date("2026-01-16T00:00:00Z"); // set to actual deprecation start
+const SUNSET_DATE = new Date(DEPRECATION_DATE);
+SUNSET_DATE.setDate(SUNSET_DATE.getDate() + SUNSET_DAYS);

 function getDeprecationHeaders(): Record<string, string> {
-  const sunsetDate = new Date();
-  sunsetDate.setDate(sunsetDate.getDate() + SUNSET_DAYS);
-
   return {
-    Deprecation: "true",
-    Sunset: sunsetDate.toUTCString(),
+    Deprecation: DEPRECATION_DATE.toUTCString(),
+    Sunset: SUNSET_DATE.toUTCString(),
     Link: `<${NEW_API_BASE_URL}/api/ai/models>; rel="deprecation"`,
   };
 }
🤖 Prompt for AI Agents
In `@app/api/ai/models/route.ts` around lines 4 - 15, The Sunset date is being
recomputed on every call to getDeprecationHeaders(), causing the deadline to
slide; instead compute the sunset once at module load and reuse it. Create a
module-level constant (e.g., SUNSET_DATE or PRECOMPUTED_SUNSET) by instantiating
new Date() and adding SUNSET_DAYS once, convert it to UTC string once (e.g.,
SUNSET_DATE_UTC) and have getDeprecationHeaders() return headers using that
constant (keeping Deprecation, Sunset, and Link with NEW_API_BASE_URL) so the
90‑day window remains fixed.

Comment on lines +25 to +28
const res = await fetch(
`${NEW_API_BASE_URL}/api/agent-creator?creatorId=${creatorId}`,
{ cache: "no-store" }
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Encode creatorId before interpolating into the query string.
Unencoded values can break the URL or alter query parsing for IDs containing ?, &, spaces, or unicode.

💡 Proposed fix
-      const res = await fetch(
-        `${NEW_API_BASE_URL}/api/agent-creator?creatorId=${creatorId}`,
-        { cache: "no-store" }
-      );
+      const encodedCreatorId = encodeURIComponent(creatorId ?? "");
+      const res = await fetch(
+        `${NEW_API_BASE_URL}/api/agent-creator?creatorId=${encodedCreatorId}`,
+        { cache: "no-store" }
+      );
📝 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
const res = await fetch(
`${NEW_API_BASE_URL}/api/agent-creator?creatorId=${creatorId}`,
{ cache: "no-store" }
);
const encodedCreatorId = encodeURIComponent(creatorId ?? "");
const res = await fetch(
`${NEW_API_BASE_URL}/api/agent-creator?creatorId=${encodedCreatorId}`,
{ cache: "no-store" }
);
🤖 Prompt for AI Agents
In `@components/Agents/AgentCreator.tsx` around lines 25 - 28, The fetch URL
interpolation uses creatorId directly which can break URLs for characters like
?, &, spaces or unicode; update the fetch call that builds
`${NEW_API_BASE_URL}/api/agent-creator?creatorId=${creatorId}` to encode the
creatorId (use encodeURIComponent on creatorId) before embedding it so the
request URL is always valid; ensure references in AgentCreator.tsx (the fetch
call creating res) and any other places that construct the same query parameter
are updated to use the encoded value.

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.

2 participants