Skip to content

Merge test into main#1739

Merged
sweetmantech merged 1 commit into
mainfrom
test
May 8, 2026
Merged

Merge test into main#1739
sweetmantech merged 1 commit into
mainfrom
test

Conversation

@sweetmantech
Copy link
Copy Markdown
Collaborator

@sweetmantech sweetmantech commented May 8, 2026

Summary

Promotes testmain. Brings in:

Test plan

  • CI green on test

Summary by cubic

Removes the deprecated ArtistAgent flow and the GET /api/agents endpoint. Consolidates chat logic around Conversation only to reduce complexity.

  • Refactors
    • Removed /api/agents, lib/supabase/getArtistAgents, and hooks/useArtistAgents.
    • Updated sidebar components and chat hooks to accept Conversation only; dropped union types and agentId logic.
    • Simplified helpers (getChatDisplayInfo, getChatRoomId) to work with Conversation only.

Written for commit a77ca7f. Summary will update on new commits.

Summary by CodeRabbit

Release Notes

  • Removed Features

    • Removed artist agent viewing and management capabilities from the application.
    • Removed the agents API endpoint.
  • Improvements

    • Simplified chat modals and sidebar interactions to focus exclusively on conversations.
    • Streamlined chat renaming, deletion, and recent chat list workflows.

* fix: remove dead ArtistAgent code and GET /api/agents endpoint

Co-authored-by: Cursor <cursoragent@cursor.com>

* updating

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 8, 2026

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

Project Deployment Actions Updated (UTC)
chat Ready Ready Preview May 8, 2026 9:39pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR removes the ArtistAgent type and its supporting infrastructure—including the /api/agents endpoint, data-fetching hooks, and type definitions—then narrows all UI components and utilities to work exclusively with Conversation objects, eliminating union-type guards and simplifying property access throughout.

Changes

ArtistAgent Type Removal Refactoring

Layer / File(s) Summary
Type Definitions & API Removal
lib/supabase/getArtistAgents.ts, app/api/agents/route.ts
ArtistAgent interface and getArtistAgents() function are removed; /api/agents GET endpoint and its Next.js caching config are deleted.
Data Fetching Simplification
hooks/useArtistAgents.ts, hooks/useConversations.tsx
useArtistAgents hook is removed entirely; useConversations now derives all data from fetchedConversations filtered by selectedArtist or orgArtistIds, eliminating the agent-merge pattern.
Hook Parameter Narrowing
hooks/useCreateChat.tsx, hooks/useRenameModal.ts
chatRoom parameter type narrowed from Conversation | ArtistAgent to Conversation; direct property access (chatRoom.id, chatRoom.topic, chatRoom.memories) replaces type casting.
Utility Helper Simplification
lib/chat/getChatRoomId.ts, lib/chat/getChatDisplayInfo.ts
Functions simplified to accept only Conversation; type-guard conditionals and union handling removed; return shapes reduced to essentials (displayName only).
Sidebar Hook Type Narrowing
components/Sidebar/RecentChats/useRecentChats.ts
activeChatId now derives from roomId param only (no fallback to agentId); modal state and callbacks (openModal, handleChatClick) narrowed to Conversation.
Modal & Item Component Updates
components/Sidebar/Modals/DeleteConfirmationModal.tsx, components/Sidebar/Modals/RenameModal.tsx, components/Sidebar/RecentChats/ChatItem.tsx, components/Sidebar/RecentChats/RecentChatList.tsx
Props narrowed to accept only Conversation (or Conversation[]); local type guards removed; internal logic uses direct property access (topic, id, memories) instead of derived helpers.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • recoupable/chat#1737: Removes the same ArtistAgent code and /api/agents endpoint as part of a parallel cleanup effort.
  • recoupable/chat#1711: Removes dead artist-agent API routes and supporting utilities in a related refactoring.
  • recoupable/chat#1603: Modifies hooks/useCreateChat.tsx with changes to auth and API call behavior.

Suggested reviewers

  • cubic-dev-ai

Poem

🎭 Farewell, agents in the shadows—type guards fade to dust,
Unions collapse to singularity, as the refactor does trust,
Direct paths through properties, no casting required,
Conversations stand alone, their purpose clarified. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Solid & Clean Code ⚠️ Warning DRY violation: Two different fallback strings for empty topics ("Chat Analysis" vs "Untitled Chat") with duplicate fallback logic. Review identified this; not fixed. Consolidate fallbacks: Change getChatDisplayInfo to item.topic?.trim() || "Untitled Chat" to match ChatItem and eliminate inconsistency.
✅ Passed checks (2 passed)
Check name Status Explanation
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test

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 13 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Auto-approved: Removes dead ArtistAgent code and API endpoint. Changes are mechanical (removing union types, simplifying conditionals) with no behavior change. CI green, AI found no issues. Low risk of breakage.

Copy link
Copy Markdown
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: 1

Caution

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

⚠️ Outside diff range comments (1)
components/Sidebar/Modals/RenameModal.tsx (1)

36-53: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing label and aria-describedby for the rename input.

The input has id="chatName" but no associated <label htmlFor="chatName">, and the error message on line 50 isn't linked back to the input. Screen reader users won't hear the field name nor the validation feedback. Quick wins:

♻️ Proposed accessibility fix
       <h2 className="text-xl font-semibold mb-5">Rename Chat</h2>
       <form onSubmit={handleSubmit}>
         <div className="mb-5">
+          <label htmlFor="chatName" className="sr-only">
+            Chat name
+          </label>
           <input
             type="text"
             id="chatName"
             className={`w-full px-4 py-3 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors duration-200 text-base ${
               error ? "border-red-500" : "border-border"
             }`}
             value={name}
             onChange={handleChange}
             onBlur={handleBlur}
             placeholder="Enter chat name"
+            aria-invalid={Boolean(error)}
+            aria-describedby={error ? "chatName-error" : undefined}
           />
           <div className="h-5 mt-2">
             {error && (
-              <p className="text-red-500 text-sm animate-fadeIn">{error}</p>
+              <p id="chatName-error" className="text-red-500 text-sm animate-fadeIn" role="alert">
+                {error}
+              </p>
             )}
           </div>
         </div>

As per coding guidelines: "Provide clear labels and error messages in form components" and "Use aria-describedby for error message associations in form components".

🤖 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 `@components/Sidebar/Modals/RenameModal.tsx` around lines 36 - 53, The rename
input with id "chatName" lacks an associated label and its error message isn't
linked for assistive tech; add a <label htmlFor="chatName"> (e.g., "Chat name")
adjacent to the input and give the error <p> an id (e.g., "chatName-error") then
set aria-describedby={error ? "chatName-error" : undefined} on the input (update
where value/name are managed in the component using the existing name,
handleChange, handleBlur and error variables) so screen readers announce both
the field label and validation feedback.
🧹 Nitpick comments (5)
components/Sidebar/RecentChats/ChatItem.tsx (2)

55-67: ⚡ Quick win

Duplicates the same optimistic-payload check in useCreateChat.

This block performs the same content.optimistic === true discrimination that hooks/useCreateChat.tsx does (lines 33–48 there). Now that the type is Conversation-only, both call sites would benefit from a shared typed predicate (e.g., isOptimisticMemory(memory) exported from lib/chat/). Consolidating eliminates the parallel as Record<string, unknown> / inline content-shape casts and keeps the optimistic contract in one place.

🤖 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 `@components/Sidebar/RecentChats/ChatItem.tsx` around lines 55 - 67, This
duplicates the optimistic-memory check; extract a shared typed predicate (e.g.,
export function isOptimisticMemory(memory: unknown): memory is MemoryType) into
lib/chat (name it isOptimisticMemory) and replace the inline logic in
ChatItem.tsx (the isOptimisticChatItem computation over chatRoom.memories) and
the analogous check in useCreateChat.tsx with calls to isOptimisticMemory to
remove the repeated casts and centralize the optimistic payload shape check.

46-52: 💤 Low value

useEffect to mirror prop into state can be replaced by useSyncExternalStore-free derivation, but state is needed here.

Local note rather than a change request: the state is required only because useCreateChat writes back via setDisplayName after the server returns the topic. If you ever remove that callback path (e.g., let React Query's refetched conversation drive the topic and just derive getChatDisplayInfo(chatRoom).displayName inline), you could drop both the useState and this useEffect and have a single source of truth from the query cache.

🤖 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 `@components/Sidebar/RecentChats/ChatItem.tsx` around lines 46 - 52, Keep the
local state and effect as written because displayName is mutated via
setDisplayName by useCreateChat after server response: retain const
[displayName, setDisplayName] =
useState(getChatDisplayInfo(chatRoom).displayName) and the useEffect that
updates it on chatRoom changes, and ensure the create-chat callback in
useCreateChat calls setDisplayName to write the server topic back; if you later
remove that callback path, replace both the useState and useEffect with a
derived const displayName = getChatDisplayInfo(chatRoom).displayName to use a
single source of truth.
hooks/useCreateChat.tsx (1)

33-69: ⚡ Quick win

Type-narrowing is fine; consider extracting the optimistic-message lookup.

The content shape is asserted via as casts in two places (lines 36–39 and 55–59) with overlapping inline types. Now that chatRoom is strictly Conversation, this is a good moment to lift the optimistic-payload type into @/types/Chat (e.g., OptimisticMemoryContent) and use a small typed predicate like getOptimisticFirstMessage(memories). That would also let ChatItem.tsx (which performs the same optimistic === true check at lines 55–67) share the predicate — DRY across the optimistic flow.

Not a blocker for this PR; flagging because the union removal makes the helper trivial to extract now.

🤖 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 `@hooks/useCreateChat.tsx` around lines 33 - 69, Extract the optimistic-memory
content shape into a typed alias (e.g., OptimisticMemoryContent) in `@/types/Chat`
and implement a small typed predicate/helper (e.g.,
getOptimisticFirstMessage(memories) or isOptimisticMemory(memory): memory is
OptimisticMemoryContent) that encapsulates the optimistic === true and
parts[0].text checks; then replace the inline casts and duplicated logic in
useCreateChat.tsx (the chatRoom.memories find that produces firstMessage and the
later cast used for messageText) with that helper, and reuse the same helper in
ChatItem.tsx to remove duplication.
lib/chat/getChatRoomId.ts (1)

3-3: 💤 Low value

Trivial passthrough — consider inlining at call sites eventually.

With the union gone, getChatRoomId(x) is just x.id. Not worth churning this PR over, but on a future cleanup pass this helper (and arguably getChatDisplayInfo) could be inlined or fully removed since they no longer encapsulate any branching logic.

🤖 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 `@lib/chat/getChatRoomId.ts` at line 3, getChatRoomId is a trivial passthrough
(returns chatRoom.id) now that the union type is gone; remove the helper and
replace its call sites with direct property access (use chatRoom.id) or inline
it where used, and likewise consider removing getChatDisplayInfo if it also
contains no branching—update imports/usages referencing getChatRoomId (and
getChatDisplayInfo) to use the direct fields and delete the now-unnecessary
functions.
components/Sidebar/Modals/DeleteConfirmationModal.tsx (1)

50-60: ⚖️ Poor tradeoff

Sequential bulk-delete is intentional but worth confirming the UX trade-off.

The for-loop awaits each deleteChat so the progress counter (current/total) updates step-by-step — good for transparency. Trade-off: deleting N chats takes N round trips serialized. For typical bulk sizes (a handful) this is fine; if users routinely select dozens, consider a small concurrency window (e.g., p-limit style, 3–5 in flight) while still reporting progress. Not changing anything yet — just flagging.

🤖 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 `@components/Sidebar/Modals/DeleteConfirmationModal.tsx` around lines 50 - 60,
Current implementation in the DeleteConfirmationModal loops sequentially over
chatsToDelete awaiting deleteChat each time which is simple but serializes
network calls; to address the reviewer’s trade-off either keep as-is for small
batches or implement a bounded concurrency executor (e.g., using p-limit or a
simple worker pool) to run ~3–5 deleteChat calls in parallel while still
updating setDeletingProgress as each promise settles and pushing failures into
failedChats; ensure you use the same identifiers (chatsToDelete, deleteChat,
setDeletingProgress, failedChats, chatCount) so progress increments on each
completed delete and errors are collected and logged consistently.
🤖 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 `@lib/chat/getChatDisplayInfo.ts`:
- Around line 3-5: Update getChatDisplayInfo to use the same empty-topic
fallback as the UI: return displayName: item.topic || "Untitled Chat" in
getChatDisplayInfo, and remove the duplicate fallback logic in ChatItem (so
ChatItem uses the displayName from getChatDisplayInfo directly); target the
getChatDisplayInfo export and the ChatItem component's displayName usage to
consolidate the placeholder string.

---

Outside diff comments:
In `@components/Sidebar/Modals/RenameModal.tsx`:
- Around line 36-53: The rename input with id "chatName" lacks an associated
label and its error message isn't linked for assistive tech; add a <label
htmlFor="chatName"> (e.g., "Chat name") adjacent to the input and give the error
<p> an id (e.g., "chatName-error") then set aria-describedby={error ?
"chatName-error" : undefined} on the input (update where value/name are managed
in the component using the existing name, handleChange, handleBlur and error
variables) so screen readers announce both the field label and validation
feedback.

---

Nitpick comments:
In `@components/Sidebar/Modals/DeleteConfirmationModal.tsx`:
- Around line 50-60: Current implementation in the DeleteConfirmationModal loops
sequentially over chatsToDelete awaiting deleteChat each time which is simple
but serializes network calls; to address the reviewer’s trade-off either keep
as-is for small batches or implement a bounded concurrency executor (e.g., using
p-limit or a simple worker pool) to run ~3–5 deleteChat calls in parallel while
still updating setDeletingProgress as each promise settles and pushing failures
into failedChats; ensure you use the same identifiers (chatsToDelete,
deleteChat, setDeletingProgress, failedChats, chatCount) so progress increments
on each completed delete and errors are collected and logged consistently.

In `@components/Sidebar/RecentChats/ChatItem.tsx`:
- Around line 55-67: This duplicates the optimistic-memory check; extract a
shared typed predicate (e.g., export function isOptimisticMemory(memory:
unknown): memory is MemoryType) into lib/chat (name it isOptimisticMemory) and
replace the inline logic in ChatItem.tsx (the isOptimisticChatItem computation
over chatRoom.memories) and the analogous check in useCreateChat.tsx with calls
to isOptimisticMemory to remove the repeated casts and centralize the optimistic
payload shape check.
- Around line 46-52: Keep the local state and effect as written because
displayName is mutated via setDisplayName by useCreateChat after server
response: retain const [displayName, setDisplayName] =
useState(getChatDisplayInfo(chatRoom).displayName) and the useEffect that
updates it on chatRoom changes, and ensure the create-chat callback in
useCreateChat calls setDisplayName to write the server topic back; if you later
remove that callback path, replace both the useState and useEffect with a
derived const displayName = getChatDisplayInfo(chatRoom).displayName to use a
single source of truth.

In `@hooks/useCreateChat.tsx`:
- Around line 33-69: Extract the optimistic-memory content shape into a typed
alias (e.g., OptimisticMemoryContent) in `@/types/Chat` and implement a small
typed predicate/helper (e.g., getOptimisticFirstMessage(memories) or
isOptimisticMemory(memory): memory is OptimisticMemoryContent) that encapsulates
the optimistic === true and parts[0].text checks; then replace the inline casts
and duplicated logic in useCreateChat.tsx (the chatRoom.memories find that
produces firstMessage and the later cast used for messageText) with that helper,
and reuse the same helper in ChatItem.tsx to remove duplication.

In `@lib/chat/getChatRoomId.ts`:
- Line 3: getChatRoomId is a trivial passthrough (returns chatRoom.id) now that
the union type is gone; remove the helper and replace its call sites with direct
property access (use chatRoom.id) or inline it where used, and likewise consider
removing getChatDisplayInfo if it also contains no branching—update
imports/usages referencing getChatRoomId (and getChatDisplayInfo) to use the
direct fields and delete the now-unnecessary functions.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 47303af6-30eb-4fed-924c-93ece88e2dc2

📥 Commits

Reviewing files that changed from the base of the PR and between 864201d and a77ca7f.

📒 Files selected for processing (13)
  • app/api/agents/route.ts
  • components/Sidebar/Modals/DeleteConfirmationModal.tsx
  • components/Sidebar/Modals/RenameModal.tsx
  • components/Sidebar/RecentChats/ChatItem.tsx
  • components/Sidebar/RecentChats/RecentChatList.tsx
  • components/Sidebar/RecentChats/useRecentChats.ts
  • hooks/useArtistAgents.ts
  • hooks/useConversations.tsx
  • hooks/useCreateChat.tsx
  • hooks/useRenameModal.ts
  • lib/chat/getChatDisplayInfo.ts
  • lib/chat/getChatRoomId.ts
  • lib/supabase/getArtistAgents.ts
💤 Files with no reviewable changes (3)
  • hooks/useArtistAgents.ts
  • lib/supabase/getArtistAgents.ts
  • app/api/agents/route.ts

Comment on lines +3 to +5
export const getChatDisplayInfo = (item: Conversation) => ({
displayName: item.topic || "Chat Analysis",
});
Copy link
Copy Markdown
Contributor

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

Fallback string is inconsistent with ChatItem and now reads stale.

ChatItem.tsx (line 86) falls back to "Untitled Chat" when displayName is empty/whitespace, but this helper returns "Chat Analysis" when topic is falsy. Two issues:

  1. The "Analysis" wording was meaningful when this helper handled ArtistAgent; with the union gone it no longer fits the conversation-only model.
  2. Two different fallbacks exist for what is conceptually the same empty-topic state, so users will see different placeholders depending on which code path runs.

Suggest consolidating on one label (e.g., "Untitled Chat") and dropping the duplicate fallback in ChatItem.tsx.

♻️ Proposed fix
-export const getChatDisplayInfo = (item: Conversation) => ({
-  displayName: item.topic || "Chat Analysis",
-});
+export const getChatDisplayInfo = (item: Conversation) => ({
+  displayName: item.topic?.trim() || "Untitled Chat",
+});
📝 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
export const getChatDisplayInfo = (item: Conversation) => ({
displayName: item.topic || "Chat Analysis",
});
export const getChatDisplayInfo = (item: Conversation) => ({
displayName: item.topic?.trim() || "Untitled Chat",
});
🤖 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 `@lib/chat/getChatDisplayInfo.ts` around lines 3 - 5, Update getChatDisplayInfo
to use the same empty-topic fallback as the UI: return displayName: item.topic
|| "Untitled Chat" in getChatDisplayInfo, and remove the duplicate fallback
logic in ChatItem (so ChatItem uses the displayName from getChatDisplayInfo
directly); target the getChatDisplayInfo export and the ChatItem component's
displayName usage to consolidate the placeholder string.

@sweetmantech sweetmantech merged commit 9e94db1 into main May 8, 2026
4 checks passed
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