Skip to content

Test#1827

Merged
sweetmantech merged 22 commits into
mainfrom
test
Jun 30, 2026
Merged

Test#1827
sweetmantech merged 22 commits into
mainfrom
test

Conversation

@sweetmantech

@sweetmantech sweetmantech commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Summary by cubic

Switches support and agent emails to the .dev domain. Updates the global error page mailto and the RECOUP_FROM_EMAIL from-address to use @recoupable.dev.

  • Migration
    • Verify recoupable.dev as a sending domain in Resend (SPF/DKIM) before merge.
    • Ensure support@recoupable.dev and agent@recoupable.dev routing is live.

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

Review in cubic

ahmednahima0-beep and others added 22 commits June 2, 2026 21:49
#1765)

* refactor(chat): update chat components to use chatId instead of roomId

This commit removes the InstantChatRoom component and updates various hooks and components to replace references of roomId with chatId. The changes ensure that chat functionality is aligned with the new session-scoped architecture, improving consistency across the chat system. Additionally, the sessionId is now required in several components to streamline the chat transport process.

* refactor(chat): integrate sessionId and update chat path utilities

This commit enhances the chat components by introducing the `sessionId` in various hooks and updating the URL handling to utilize new utility functions for generating chat paths. The changes improve the consistency and maintainability of chat navigation, ensuring that the application correctly reflects the session-scoped architecture.

* fix(chat): ensure newRoomId is treated as a string in URL handling

This commit updates the `useCreateArtistTool` hook to explicitly cast `result.newRoomId` to a string when generating the chat path. This change prevents potential type-related issues and ensures consistent URL formatting. Additionally, it adds an import statement for testing utilities in the chat paths test file, enhancing test coverage and maintainability.

* refactor(Header, OrganizationProvider): remove usePathname and replace with window.location.pathname

This commit removes the usePathname hook from both Artist.tsx and OrganizationProvider.tsx, replacing it with direct access to window.location.pathname. This change simplifies the code and maintains the intended navigation behavior without relying on Next.js's router for pathname management.

* refactor(chat): split chatPaths per SRP, drop dead legacy branch, simplify useParams

- Remove dead `/chat/` branch from isActiveChatRoomPath — this PR makes
  /chat/{id} 404, so treating it as an active chat room contradicted the
  PR's own intent and could never fire in production.
- Split lib/chat/chatPaths.ts into one-function-per-file (getChatPath,
  getChatUrl, isActiveChatRoomPath) per repo SRP convention; mirror tests.
- Simplify useVercelChat to `const { chatId } = useParams<{ chatId?: string }>()`
  (KISS), consistent with chat.tsx.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Sweets Sweetman <sweetmantech@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#1767) (#1774)

* feat(chat): defer new-chat bootstrap wait from spinner to send button (#1767)

New chats landing on `/` or `/chat` blocked the whole view on a
full-screen spinner while `POST /api/sessions` + `POST /api/sandbox`
resolved (~12s cold, dominated by sandbox provisioning). Render `<Chat>`
immediately with a typeable input instead and provision in parallel; the
Send button stays disabled with a "Preparing your workspace…" cue until
the api-minted `sessionId` + `chatId` land, so the workflow transport
never fires without the ids its validator requires.

- NewChatBootstrap: render <Chat> eagerly with a stable placeholder chat
  id (survives the preparing → ready transition); drop the spinner.
- Thread `sessionId?`, `workflowChatId`, `isBootstrapPreparing` through
  Chat → VercelChatProvider → useVercelChat (provider kept inline).
- useVercelChat: `transportChatId = workflowChatId ?? id` drives the
  transport, optimistic conversation, and URL; only load persisted
  history on a canonical route so no spinner flashes over the input
  during the ready transition.
- ChatInput: gate Send on `isBootstrapPreparing`; input stays typeable.
- useChatTransport / useMessageLoader: sessionId optional + guard.
- useCreateArtistTool: guard the one context sessionId consumer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(chat): send live sessionId/chatId from workflow transport (#1767)

The new-chat flow mounts <Chat> (and useChat) during provisioning with
sessionId undefined + a placeholder chatId. useChat captures the transport
from that mount render and does not swap to the rebuilt instance when the
ids later resolve — so the first send POSTed `sessionId: undefined` to
/api/chat/workflow and got a 400 (the URL rewrote correctly because it
reads the live prop, not the transport).

Read the ids from refs inside transport.body() so a single stable
transport instance always sends the values current as of the request,
regardless of useChat's stale capture. Removed chatId/sessionId from the
memo deps since rebuilding the instance never helped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(chat): replace preparing-text cue with a workspace status dot (#1767)

Swap the flashing "Preparing your workspace…" toolbar text for a
stoplight status dot in the top-right of the chat input: red = off
(provisioning failed / unavailable), yellow = provisioning, green =
ready. Hover shows context via the shadcn tooltip.

- New `WorkspaceStatusIndicator` component in its own file (SRP) — a pure
  display component driven by a `status` prop, built on the existing
  shadcn-based `common/Tooltip`, so it's open for reuse without change.
- Thread `workspaceStatus: "off" | "provisioning" | "ready"` through
  Chat → VercelChatProvider → context (replacing the `isBootstrapPreparing`
  boolean); Send is gated while it's not `ready`.
- NewChatBootstrap now derives the status and renders `<Chat>` even on a
  provisioning error (red dot + disabled Send, input still visible)
  instead of swapping in a full-screen error view.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(chat): simplify provisioning tooltip copy (#1767)

Shorten the yellow/provisioning workspace-status tooltip to
"Preparing your workspace".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(chat): drop legacy GET /api/chats/{id}/artist caller (#1767)

* fix(chat): reactive conversations cache + user-scoped session query

* refactor(chat): drop dead /chat/:id artist cache fallback (post-#1765)

The conversations-cache fallback in useArtistFromChat only existed for the
legacy /chat/:id deep link (chatId but no sessionId). That route was
removed in #1765 — every chat is now reached via the canonical
/sessions/{sessionId}/chats/{chatId} URL, so sessionId is always present.

Reduce to the session path: GET /api/sessions/{sessionId} -> session.artistId
-> select. Removes useSyncExternalStore reactive-cache machinery,
findArtistIdInConversationsCache (+ its test), and the unused chatId param.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(chat): validate getSessionById response with zod (PR #1768 review)

Replace type-casting with boundary zod validation, matching the
getConversations convention. Drops the `as GetSessionByIdResponse`/
`as GetSessionByIdErrorResponse` casts in favor of safeParse/parse.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(chat): extract shared safeJsonParse into lib/api (PR #1768 review)

Replace the locally-defined safeJsonParse in getSessionById with a
shared helper in lib/api/, alongside the other HTTP helpers. DRY/SRP.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Sweets Sweetman <sweetmantech@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… and hooks

This commit updates the MessageEditor component and the useVercelChat hook to utilize transportChatId instead of the previous chatId. This change enhances the consistency of chat-related API calls and aligns with the new session-scoped architecture, ensuring that the correct chat identifier is used for operations like deleting trailing messages.
#1781)

* fix(chat): persist selected model before send so the workflow bills it

The chat-workflow path bills the model it reads from chats.model_id at
request time. The picker selection was never written there, so every new
chat (and any model change) billed the chats.model_id default instead of
the chosen model.

Before sending, await a PATCH of the selected model to
chats.model_id when it changed for the active chat (shouldPersistChatModel
guards redundant writes). The chat row already exists from new-chat
bootstrap, so this covers the first turn race-free without an api change.

Reuses buildPatchChatBody + updateChat(modelId) (originally from #1779).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(chat): extract model-persist-before-send into usePersistSelectedModel

Addresses OCP/SRP review feedback on #1781: instead of inlining the
persist-before-send block in useVercelChat, encapsulate it in a dedicated
usePersistSelectedModel hook (owns the lastPersisted ref + guard + PATCH).
useVercelChat now just calls `await persistSelectedModel()` before send.

Behavior unchanged; pure decision logic still covered by
shouldPersistChatModel tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(chat): persist selected model on retry/edit + append paths

Addresses review feedback on #1781:
- Retry/Edit call reload() → regenerate (and append() calls sendMessage)
  bypassing handleSubmit, so the selected model was not persisted before
  those sends — the regenerated turn could bill the previous/default model.
  Now await persistSelectedModel() in handleReload and append too.
- Clarify updateChat JSDoc: it patches title and/or modelId (not just rename).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Step 3 of the /api/chat/workflow → /api/chat rename (chat#1767), against
the merged docs contract (docs#235) and the api endpoint (api#645, on test).

useChatTransport now POSTs to ${baseUrl}/api/chat instead of
/api/chat/workflow. Comment-only refs in VercelChatProvider updated too.

⚠️ Deploy coordination: requires api#645 (which removes /api/chat/workflow)
to be live in the same environment. Must deploy together with the api
promotion and the open-agents repoint (step 4), or chat 404s.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t-id

Revert "refactor(chat): replace chatId with transportChatId in message editor and hooks"
* chore: upgrade @privy-io/react-auth v1.88.4 -> v3.31.0

Prerequisite for cross-subdomain (cookie) auth in #1801:
matches marketing's ^3.31.0 so both surfaces run a cookie-capable SDK.

Migration surface is minimal — every @privy-io import in chat is usePrivy
or the PrivyProvider component (audited all 48 sites); none of the
v3-renamed/removed hooks (useLoginToFrame, useSignAuthorization,
useSolanaWallets, useWallets, useLogin/useLogout callbacks) are used, and
usePrivy()'s return shape (login/logout/authenticated/user/getAccessToken/
ready) plus user.email.address / user.wallet.address are unchanged in v3.

Only code change: embeddedWallets.createOnLogin moved under a per-chain key
(v3 breaking change) -> embeddedWallets.ethereum.createOnLogin.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Update providers/PrivyProvider.tsx

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#1805)

* feat: show X (Twitter) in artist Connectors tab; keep LinkedIn label-only (chat#1793)

Mirror the api ALLOWED_ARTIST_CONNECTORS change on the frontend: add
`twitter` to the artist-settings connector allow-list. `linkedin` stays
excluded (label/owner-only).

TDD: new allowedArtistConnectors.test.ts asserts twitter included +
linkedin excluded, RED before GREEN.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: show LinkedIn in artist Connectors tab too (chat#1793)

Reversal of the earlier label-only call: per owner decision 2026-06-18,
LinkedIn is now an artist-facing connector. Add `linkedin` to the chat
ALLOWED_ARTIST_CONNECTORS, mirroring api#680.

TDD: flipped the linkedin assertion (now included), RED before GREEN.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: update artist allow-list comment — chat is the source of truth (chat#1793)

The api's ALLOWED_ARTIST_CONNECTORS is being deleted (no runtime consumer;
api#680). Reword the comment to drop the stale "separate from the API's
ALLOWED_ARTIST_CONNECTORS" reference and state that this list is the source
of truth, applied by filtering the unopinionated GET /api/connectors response.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: branded icons + display metadata for X, LinkedIn, YouTube connectors (chat#1793)

The artist Connectors tab showed X/LinkedIn (and YouTube) with the generic
Link2 fallback icon, a default description, and a mangled fallback name.
Add proper display entries:
- getConnectorIcon: SiX (X), SiYoutube (YouTube), lucide Linkedin (LinkedIn,
  since Simple Icons dropped the LinkedIn logo on brand request)
- connectorMetadata: descriptions for twitter + linkedin
- formatConnectorName: "X (Twitter)" + "LinkedIn"

TDD: connectorDisplay.test.ts asserts branded (non-fallback) icons + clean
names + real descriptions for the three slugs, RED before GREEN.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
NEW_API_BASE_URL resolved to https://api.recoupable.com in production, which no
longer resolves after the .com apex was retired — every client API call from
chat.recoupable.dev failed with ERR_NAME_NOT_RESOLVED (e.g. /api/ai/models, so
the model selector never populated). Point prod at the live api.recoupable.dev
domain. Non-prod base (test-recoup-api.vercel.app) is unchanged.

Refs #1819.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Repoint dead recoupable.com hosts to their live .dev equivalents and DRY
the URLs through shared constants in lib/consts.ts.

- Add APP_BASE_URL, DOCS_BASE_URL, API_PUBLIC_BASE_URL constants
- getChatUrl: chat.recoupable.com -> APP_BASE_URL (chat.recoupable.dev)
- ApiKeyManager / ExternalLinksGroup docs links -> DOCS_BASE_URL
  (docs.recoupable.dev); apex recoupable.com link left intact (still live)
- In-app API doc examples (account/fans/posts): api.recoupable.com ->
  api.recoupable.dev, via API_PUBLIC_BASE_URL where interpolatable
- JSDoc @see hosts -> docs.recoupable.dev
- Update getChatUrl test assertion to match new origin

Emails (agent@recoupable.com) and apex links left untouched.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
RECOUP_FROM_EMAIL agent@recoupable.com → @recoupable.dev (the agent's outbound
from-address); global-error page "Get help" support mailto → @recoupable.dev.

DO NOT MERGE until recoupable.dev is a verified sending domain in Resend —
the agent sends from this address, so an unverified domain bounces every email.
Per #1819 decision 2026-06-29.

Refs #1819.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
chat Building Building Preview Jun 30, 2026 2:33am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@sweetmantech, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 3 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a82f5a49-21cf-4c60-8f32-aff10056bec0

📥 Commits

Reviewing files that changed from the base of the PR and between e1fdbd2 and ffdd9ed.

📒 Files selected for processing (2)
  • app/global-error.tsx
  • lib/consts.ts
✨ Finishing Touches
🧪 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.

@sweetmantech sweetmantech merged commit 46f9c4c into main Jun 30, 2026
3 of 4 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ffdd9ed852

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread lib/consts.ts
IS_PROD ? "base" : "base-sepolia"
}/${process.env.PAYMASTER_KEY}`;
export const RECOUP_FROM_EMAIL = "Agent by Recoup <agent@recoupable.com>";
export const RECOUP_FROM_EMAIL = "Agent by Recoup <agent@recoupable.dev>";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep the Resend sender on a verified domain

This constant is passed as the from value by generateTxtFileEmail and posted directly to Resend in sendEmail; Resend rejects messages when the from domain is not one of the account's verified domains. In deployments where only the previous .com sender is verified, changing this to agent@recoupable.dev causes TXT-file notification emails to fail instead of reaching users, so keep the verified sender or make the verified sender configurable before switching domains.

Useful? React with 👍 / 👎.

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.

3 participants