Skip to content

fix(desktop,db): unbreak chat in local-first workspaces and clean up no-credential UX - #6266

Closed
Kitenite wants to merge 2 commits into
mainfrom
fix-chat-local-workspace
Closed

Kitenite wants to merge 2 commits into
mainfrom
fix-chat-local-workspace

Conversation

@Kitenite

@Kitenite Kitenite commented Aug 7, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Drop the chat_sessions.v2_workspace_id → v2_workspaces FK (migration 0064): since workspaces went local-first (feat(desktop,host-service): local-first projects — host.db owns projects, workspace cloud sync retired #5731) they have no cloud mirror row, so chat.createSession failed its insert for every newly created workspace and chat was unusable there.
  • Stop the chat pane's error loop: the 4fps getSnapshot poll retried runtime creation (including macOS keychain reads) four times a second while flipping between the loading spinner and the error banner — it now holds a steady error state and backs off to 5s until it recovers.
  • Replace the raw "No model provider credentials available" error with a neutral setup callout and an Open Model Settings button.

Why / Context

Reported symptom: sending a chat message in a v2 workspace surfaced Failed query: insert into "chat_sessions" … and the pane kept "reloading". Root causes were the stale cloud FK (the referenced v2_workspaces row is never created anymore) and the snapshot poll treating every failed background retry as a fresh load.

How It Works

  • v2WorkspaceId stays on the cloud chat_sessions row as a plain uuid — it still scopes the Electric-synced session list per workspace; it just no longer requires a cloud workspace row. Losing onDelete: set null only leaves orphaned session rows that the UI already never shows (the selector filters by live workspace id).
  • useWorkspaceChatDisplay: isConversationLoading uses isPending only, and refetchInterval returns 5s while the query is errored (auto-recovers to 4fps on success).
  • ChatInputFooter recognizes the missing-credentials error and renders the actionable banner; all other errors keep the existing destructive banner.

Manual QA Checklist (all done via CDP against the dev desktop, workspace 0830f756)

  • Before fix: reproduced the exact failed insert in the chat pane; 0 rows landed in chat_sessions
  • After applying 0064 to an isolated Neon branch: same interaction creates the session row with the local-only workspace id, no error
  • Session round-trips through Electric into the session selector after a full renderer reload
  • Errored snapshot poll: measured ~2 getSnapshot calls per 5s window (was 4/s), steady banner, no spinner flicker
  • Setup banner renders for the credentials error; button navigates to #/settings/models
  • Full chat turn with working credentials (dev sandbox host-service can't see keychain credentials; failure point is past the fixed code paths)

Testing

  • bun run typecheck (packages/db, packages/trpc, apps/desktop)
  • bun run lint
  • bun test apps/desktop/.../v2-workspace (117 pass)
  • Migration verified: constraint name in generated SQL matches pg_constraint on a production-derived branch; applied cleanly via bun run db:migrate

Risks / Rollout

  • Risk: low — FK drop is forward-only but non-destructive; no data rewritten.
  • Rollout: apply migration with the normal API/DB deploy; fixes existing desktop builds without a release (per cloud-before-desktop ordering).
  • Rollback: re-adding the FK would fail on rows referencing local-only workspaces; revert the renderer commit independently if needed.

Follow-ups

  • Settings → Models can show Anthropic "Active" while the runtime rejects the same credential (expired OAuth failing refresh): presence check and hasUsableRuntimeEnv disagree. Separately, the credential resolver only probes legacy keychain services (claude-cli), not modern Claude Code's "Claude Code-credentials".
  • Chat local-first (host-service chat_sessions) remains Phase B of plans/remove-cloud-project-model.md.

Summary by cubic

Fixes chat in local-first workspaces by removing the stale chat_sessions.v2_workspace_id FK and stabilizing the chat pane’s error behavior. Adds a simple model setup callout with an “Open Model Settings” button and backs off polling on errors.

  • Bug Fixes

    • Dropped chat_sessions → v2_workspaces FK; kept v2_workspace_id as a plain uuid so session inserts work for local-only workspaces.
    • Backed off snapshot polling to 5s while errored and stopped flipping between spinner and error; loading now uses a stable pending state.
    • Replaced the raw missing-credentials error with a neutral setup banner and quick access to model settings.
  • Migration

    • Run migration 0064_drop_chat_sessions_v2_workspace_fk to drop the FK (forward-only, non-destructive).

Written for commit 279a4ac. Summary will update on new commits.

Review in cubic

…paces

Workspaces have no cloud mirror since local-first (#5731), so
chat.createSession's insert failed the v2_workspace_id FK for every
workspace created since. Keep the column as a plain uuid pointing at
the host-local workspace id.
…setup banner

- getSnapshot polling backs off to 5s while errored (was retrying
  runtime creation + keychain reads at 4fps) and no longer flips the
  pane between spinner and error on every retry
- "No model provider credentials available" now renders as a neutral
  callout with an Open Model Settings button instead of a raw error
@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds model-provider error detection and settings navigation, changes chat error polling and loading behavior, and removes the foreign-key constraint from chat_sessions.v2_workspace_id.

Changes

Chat session reliability

Layer / File(s) Summary
Model-provider error flow
apps/desktop/.../ChatInputFooter.tsx, apps/desktop/.../utils/getErrorMessage.ts
Detects missing model-provider credentials. Shows a setup alert with an “Open Model Settings” button. Other errors keep the destructive alert.
Chat error retry behavior
apps/desktop/.../useWorkspaceChatDisplay.ts
Refetches failed snapshot queries every five seconds. Uses isPending for conversation loading state.
Workspace session constraint removal
packages/db/src/schema/schema.ts, packages/db/drizzle/0064_drop_chat_sessions_v2_workspace_fk.sql, packages/db/drizzle/meta/_journal.json
Removes the chat_sessions.v2_workspace_id foreign-key reference and records the migration.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ChatInputFooter
  participant ErrorUtility
  participant ModelSettings
  ChatInputFooter->>ErrorUtility: Check chat error message
  ErrorUtility-->>ChatInputFooter: Return missing-provider status
  ChatInputFooter->>ModelSettings: Navigate to /settings/models
Loading

Possibly related issues

  • superset-sh/superset#5852: Addresses the same chat_sessions.v2_workspace_id foreign-key constraint that can block local-first chat session inserts.

Possibly related PRs

Suggested reviewers: saddlepaddle

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title uses conventional commit format and clearly summarizes the chat reliability and no-credential UX fixes.
Description check ✅ Passed The description explains the problem, implementation, testing, risks, rollout, rollback, and follow-ups in sufficient detail.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 fix-chat-local-workspace

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

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

Inline comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/ChatInputFooter.tsx:
- Around line 163-189: Add the cursor-text class alongside select-text on both
error surfaces in ChatInputFooter: the setup message span within the
showModelProviderSetup branch and the fallback error paragraph rendering
errorMessage. Preserve all existing styling and behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: da392122-5b74-4c40-91cc-a6022c08010f

📥 Commits

Reviewing files that changed from the base of the PR and between 93168b7 and 279a4ac.

📒 Files selected for processing (7)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/ChatInputFooter.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/utils/getErrorMessage.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/hooks/useWorkspaceChatDisplay/useWorkspaceChatDisplay.ts
  • packages/db/drizzle/0064_drop_chat_sessions_v2_workspace_fk.sql
  • packages/db/drizzle/meta/0064_snapshot.json
  • packages/db/drizzle/meta/_journal.json
  • packages/db/src/schema/schema.ts

Comment on lines +163 to +189
{showModelProviderSetup ? (
<div
role="alert"
className="mb-3 select-text rounded-md border border-destructive/20 bg-destructive/10 px-4 py-2 text-sm text-destructive"
className="mb-3 flex items-center justify-between gap-3 rounded-md border border-border bg-muted/50 px-4 py-2 text-sm"
>
{errorMessage}
</p>
<span className="select-text text-muted-foreground">
Chat needs a model provider. Connect Claude or add an API key to
get started.
</span>
<Button
size="sm"
variant="outline"
className="shrink-0"
onClick={() => void navigate({ to: "/settings/models" })}
>
Open Model Settings
</Button>
</div>
) : (
errorMessage && (
<p
role="alert"
className="mb-3 select-text rounded-md border border-destructive/20 bg-destructive/10 px-4 py-2 text-sm text-destructive"
>
{errorMessage}
</p>
)

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add cursor-text to both error surfaces.

The setup message at Line [168] and the fallback error at Line [185] include select-text but not cursor-text. Add the missing class so users receive the required text-selection cursor.

Proposed fix
-							<span className="select-text text-muted-foreground">
+							<span className="select-text cursor-text text-muted-foreground">
...
-								className="mb-3 select-text rounded-md border border-destructive/20 bg-destructive/10 px-4 py-2 text-sm text-destructive"
+								className="mb-3 select-text cursor-text rounded-md border border-destructive/20 bg-destructive/10 px-4 py-2 text-sm text-destructive"

As per coding guidelines, rendered error messages must include select-text cursor-text classes so users can copy them; Sonner toasts are exempt.

📝 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
{showModelProviderSetup ? (
<div
role="alert"
className="mb-3 select-text rounded-md border border-destructive/20 bg-destructive/10 px-4 py-2 text-sm text-destructive"
className="mb-3 flex items-center justify-between gap-3 rounded-md border border-border bg-muted/50 px-4 py-2 text-sm"
>
{errorMessage}
</p>
<span className="select-text text-muted-foreground">
Chat needs a model provider. Connect Claude or add an API key to
get started.
</span>
<Button
size="sm"
variant="outline"
className="shrink-0"
onClick={() => void navigate({ to: "/settings/models" })}
>
Open Model Settings
</Button>
</div>
) : (
errorMessage && (
<p
role="alert"
className="mb-3 select-text rounded-md border border-destructive/20 bg-destructive/10 px-4 py-2 text-sm text-destructive"
>
{errorMessage}
</p>
)
{showModelProviderSetup ? (
<div
role="alert"
className="mb-3 flex items-center justify-between gap-3 rounded-md border border-border bg-muted/50 px-4 py-2 text-sm"
>
<span className="select-text cursor-text text-muted-foreground">
Chat needs a model provider. Connect Claude or add an API key to
get started.
</span>
<Button
size="sm"
variant="outline"
className="shrink-0"
onClick={() => void navigate({ to: "/settings/models" })}
>
Open Model Settings
</Button>
</div>
) : (
errorMessage && (
<p
role="alert"
className="mb-3 select-text cursor-text rounded-md border border-destructive/20 bg-destructive/10 px-4 py-2 text-sm text-destructive"
>
{errorMessage}
</p>
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/components/ChatInputFooter/ChatInputFooter.tsx
around lines 163 - 189, Add the cursor-text class alongside select-text on both
error surfaces in ChatInputFooter: the setup message span within the
showModelProviderSetup branch and the fallback error paragraph rendering
errorMessage. Preserve all existing styling and behavior.

Source: Coding guidelines

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🚀 Preview Deployment

🔗 Preview Links

Service Status Link
Neon Database (Neon) ✅ View Branch
Vercel API (Vercel) ✅ Open Preview
Vercel Web (Vercel) ✅ Open Preview
Vercel Marketing (Vercel) ✅ Open Preview
Vercel Admin (Vercel) ✅ Open Preview
Vercel Docs (Vercel) ✅ Open Preview

Preview updates automatically with new commits

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

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.

No issues found across 7 files

Re-trigger cubic

@github-actions

Copy link
Copy Markdown
Contributor

This PR has had no activity for 53 days and will close in 7 days unless there is new activity. If this contribution is still important or relevant, please leave a comment to keep it open. If it closes, you are welcome to reopen it or ask a maintainer to reopen it. Thank you for contributing!

@github-actions github-actions Bot added the stale label Sep 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This PR was automatically closed due to inactivity to help keep the review queue manageable. This does not mean the contribution was rejected. If this contribution is still important or relevant, please reopen it or leave a comment asking a maintainer to reopen it. Thank you for contributing!

@github-actions github-actions Bot closed this Oct 13, 2026

This branch was previously deployed

1 inactive deployment
preview — 279a4ace Deployed Aug 7, 2026 by Kitenite via Deploy Marketing #7263
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant