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

Closed
KI
1mo ago
+6781-14

Summary

  • Drop the chat_sessions.v2_workspace_id → v2_workspaces FK (migration 0064): since workspaces went local-first (#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).