Skip to content

feat: account-level Chat setting (user_settings), out of PostHog - #9162

Merged
harshithmullapudi merged 9 commits into
mainfrom
superset/chat-user-settings
Oct 30, 2026
Merged

harshithmullapudi merged 9 commits into
mainfrom
superset/chat-user-settings

Conversation

@harshithmullapudi

@harshithmullapudi harshithmullapudi commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #9155 (user_settings table); merge that first and let it deploy. Supersedes #9154.

Summary

  • Chat leaves PostHog. Desktop and mobile get Settings → Experimental → Chat, stored per account in user_settings.experimental_chat and off by default. Turn it on once and it applies on every device and on the server.
  • One rule everywhere: new sessions open as chat only when the setting is on and the agent supports ACP (Claude, Codex, OpenCode, Pi). Every other case opens a terminal. This applies to desktop, mobile, automations (the owner's setting) and cloud workspace starts.
  • Existing chats always show. Chats from automations, another device, or an older build are adopted and listed whatever the setting says; the setting only decides how new sessions open.
  • Presets bar is back on chat tabs, and "Fork into chat" is hidden while Chat is off.

How It Works

Piece What
userSettings.get / userSettings.update New router, mirroring channelNotificationPrefs. No row means the defaults; update upserts only the fields it was given and returns the settings
lib/user-settings.ts loadUserSettings / acpChatEnabled(userId). Used by automations (relay and cloud) and cloudWorkspace.create
Desktop useAcpChatEnabled() is a cloudTrpc.userSettings.get query. AcpChatSetting writes the result back with setData. The old local acp-chat store is deleted and its key moved to DEAD_KEYS
Mobile useAcpChatEnabled() is a React Query userSettings.get (refetched on foreground through the existing focus manager); the Settings switch writes the result into the cache

Show vs open

  • Showing no longer depends on the setting: desktop useAutoAdoptChatSessions, useConsumeAutomationRunLink, seedPendingCloudChat; mobile home list, "Manage sessions", chat tabs and stop button, ended chats.
  • Opening new sessions checks the setting and ACP support: desktop launcher, presets, new chat (button and hotkey), new workspace, fork into chat; mobile new-session sheet and new terminal workspace.

Auth and the session are untouched.

Compatibility

  • Old desktop and mobile builds still read the PostHog flag for what they show. Chat is off by default, so automations and cloud starts open terminals, which every build shows.
  • Edge case: someone who turns Chat on in a new build but also uses an old build outside the flag won't see chats there until they update.
  • tRPC: only additions (a new userSettings router). Nothing released loses an input or output.
  • Behaviour change: people in acp-chat lose chat (and their automations switch to terminals) until they turn the setting on. An automation that continues a previous chat starts a fresh terminal while its owner has Chat off (hostSession.test.ts:156).

Manual QA

Earlier iteration (#9154, device-local setting), desktop dev app over CDP, before (main) vs after:

Before After
Settings → Experimental No Chat switch Chat switch, off
Chat off: Claude preset Terminal Terminal
Chat off: terminal "CLI mode" menu Offers Fork into chat Fork session / Continue only
Chat on: Claude preset n/a Chat pane
Chat on: Copilot preset (no ACP) n/a Terminal
Presets bar on a chat tab Hidden Shown
  • Not re-run against this version. The table isn't on the workspace's Neon dev branch yet (applying migrations was blocked here). Re-check the rows above, plus: toggle on desktop, mobile follows after a foreground refetch
  • Not run: mobile on a simulator; a real automation run end to end

Testing

  • tsc: packages/trpc, packages/auth, apps/desktop clean. apps/mobile: same 188 errors as main, none in changed files
  • bun test: trpc 817 (new user-settings.test.ts), desktop full suite (useCreateAgentSession fixture now mocks useAcpChatEnabled), mobile 248, auth 90
  • bun run check:i18n clean (2 new strings translated in all 16 locales); biome check clean
  • An independent review agent read the account-column version: no correctness bugs; its compatibility and session-cache findings are resolved by moving to user_settings and having automations follow the owner's setting

Follow-ups

  • Delete the acp-chat PostHog flag once no live build reads it
  • Settings copy says "Claude and Codex"; OpenCode and Pi also chat (re-keys 2 strings)

Summary by cubic

Moves the Chat experimental setting out of PostHog and per-device storage into an account-level user_settings row, so desktop, mobile, and server-side automations all agree on one value that's off by default.

  • Adds a userSettings tRPC router (get/update) that reads and upserts experimentalChat; no row means off.
  • Desktop and mobile replace their acp-chat PostHog flag and local store with userSettings.get queries and persist via userSettings.update.
  • Launch paths wait for the setting (useResolveAcpChatEnabled) instead of reading "off" while it loads; desktop sign-out resets the query so the next account never sees the previous one's value.
  • Existing chats are always shown regardless of the setting; the setting only decides whether new sessions open as chat (and only for agents that support ACP).
  • Automations open as chat only when the owner's setting is on; the old acp-chat PostHog flag remains only for released builds and can be removed later.
  • The Chat switch is disabled while a save is in flight; "Track file changes per turn" stays visible but disabled while Chat is off.
  • The desktop device-local acp-chat store is deleted and its key moves to DEAD_KEYS, so anyone with the setting enabled in a previous build will see terminals until they flip the new account-level toggle.

Migration
Existing acp-chat feature-flag users lose chat access until they enable the new setting in Settings → Experimental → Chat; the old local key is dead.

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

View guided diff Turn on auto-fix

Account-level switch for opening new agent sessions as chat, so desktop,
mobile and server-side launches read one value. Constant-default ADD
COLUMN: metadata-only on Postgres 11+.
Per review, account settings stay off auth.users, which every
authenticated request reads. user_settings follows
channel_notification_prefs: user_id primary key, typed columns with
defaults, and no row means the defaults, so Chat stays off for every
account without a backfill.

Replaces the users.experimental_chat column from the previous commit,
which never shipped.
…m clients

Automations no longer read the acp-chat PostHog flag: they ask for a chat
whenever the agent supports ACP, and the host still answers with a
terminal when it can't chat with that agent.

cloudWorkspace.create takes an optional `surface`. Desktop and mobile send
their Chat experimental setting; callers that omit it (released builds,
CLI, MCP, SDK) keep the old flag lookup, so the input is additive.
The Chat switch is shown to everyone and is the only gate; the acp-chat
PostHog flag is no longer read. A stored null (never touched) now means
off. ACP agents open as chat when it is on; every other agent, and every
agent when it is off, opens a terminal.

- Show the presets bar on chat tabs again; agent presets already pick
  chat or terminal from the setting and ACP support.
- Hide "Fork into chat" while Chat is off.
- Cloud workspace creation sends the setting as `surface`.
Device-local switch in Settings → Experimental replaces the acp-chat
PostHog flag in every mobile chat gate. Cloud workspace creation (composer
and voice tool) sends it as `surface`.
The Chat experimental switch now writes users.experimental_chat through
user.updateExperimentalChat and every surface reads it from the session,
so desktop, mobile and the server agree. It only decides how new agent
sessions open; chats that already exist (from automations, another
device, or a released build) are always adopted and listed.

- Drop the device-local stores; desktop's acp-chat key moves to DEAD_KEYS.
- Drop the unreleased cloudWorkspace.create `surface` input: the server
  reads the account setting for every caller.
- Desktop: chat sessions are adopted and automation run links focus chats
  regardless of the setting; the switch moves into AcpChatSetting.
- Mobile: chats are listed, managed and stoppable regardless of the
  setting; only new sessions follow it.
Automations open as chat only when the owner has Chat on and the agent
supports ACP; otherwise a terminal. Everyone starts with Chat off, so
released builds, which hide chats from accounts outside the acp-chat
flag, keep seeing every run.
Per review, the setting moves off auth.users into user_settings, so the
session and auth stay untouched.

- New userSettings router (get/update), mirroring channelNotificationPrefs:
  no row means the defaults, update upserts only the given fields.
- Server reads it through loadUserSettings for automations and cloud
  workspace starts.
- Desktop and mobile read it with a userSettings.get query; the switch
  writes the returned settings back into that query.
- Desktop: the "Track file changes per turn" switch moves into its own
  component, alongside AcpChatSetting.
@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Caution

Review failed

The pull request is closed.

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@greptile-apps

greptile-apps Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The Chat preference changes new-session launches across client and server workflows.

Wait to merge until new sessions resolve the account setting before choosing chat or terminal.

Findings

  1. P1 Loading settings turns Chat off ▶
  2. P2 Previous account's choice appears ▶
  3. P2 Last toggle can lose ▶
  4. P2 Search points to missing control ▶
Fix with agent prompt
### Issue 1
apps/desktop/src/renderer/hooks/useAcpChatEnabled/useAcpChatEnabled.ts:4-5
`useAcpChatEnabled` treats an unanswered request as Chat being off. On a fresh launch, someone with Chat enabled can start a supported agent before `userSettings.get` returns and get a terminal instead. Desktop previously waited for the setting to resolve. Keep a loading state and resolve the setting before choosing the session type; apply the same fix to mobile.

### Issue 2
apps/desktop/src/renderer/hooks/useAcpChatEnabled/useAcpChatEnabled.ts:4-5
The desktop settings query has no account in its key, and signing out does not clear its cache. If another user signs in before that cache expires, the hook returns the previous user's setting while it refetches. That can show the wrong switch value and choose the wrong session type. Key the query by the signed-in account or remove it when the account changes.

### Issue 3
apps/desktop/src/renderer/routes/_authenticated/settings/experimental/components/ExperimentalSettings/components/AcpChatSetting/AcpChatSetting.tsx:41-46
The switch stays usable while its save is pending. Turning Chat on and then off can send overlapping writes; if the first write finishes last, Chat ends up on despite the user's last choice. Mobile has the same race. Disable the switch while saving, or serialize saves so the last choice wins.

### Issue 4
apps/desktop/src/renderer/routes/_authenticated/settings/experimental/components/ExperimentalSettings/components/ChatTurnSnapshotsSetting/ChatTurnSnapshotsSetting.tsx:18
`ChatTurnSnapshotsSetting` now disappears when Chat is off, but settings search still counts its match. Searching for `snapshot` can point to Experimental with no matching control. The search also hides the Chat switch needed to reveal it. Keep the control visible but disabled, or make search account for this dependency.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Moves Chat from PostHog and desktop-local storage to an account setting in user_settings.

  • Chat settings now follow an account across devices.
  • New agent sessions use the account's Chat choice.
  • Existing chats stay visible when Chat is turned off.

Acknowledged scope:

  • harshithmullapudi explicitly acknowledged that existing flag users lose Chat until they enable the new setting; this is intended behavior.
  • harshithmullapudi explicitly deferred updating the settings copy that names only Claude and Codex in the PR follow-ups.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  Settings[Desktop or mobile settings] --> Update[userSettings.update]
  Update --> DB[(user_settings)]
  DB --> Get[userSettings.get]
  Get --> Clients[Desktop and mobile launchers]
  DB --> Server[Cloud starts and automations]
  Clients --> Gate{Chat enabled and agent supports ACP?}
  Server --> Gate
  Gate -->|Yes| Chat[New chat]
  Gate -->|No| Terminal[New terminal]
  Existing[Existing chats] --> Visible[Always listed]
Loading

Reviews (1) · Last reviewed commit: "feat: read the Chat setting from user_se..." · Reviewed by Greptile

Copy link
Copy Markdown
Contributor

Review at 703fa73e: minor issues. The approach is sound and the tRPC change only adds procedures. The router works against Postgres (PGlite with migration 0179). Desktop tests, mobile tests and i18n checks are clean.

  • minor apps/desktop/src/renderer/hooks/useAcpChatEnabled/useAcpChatEnabled.ts:4: returns false while userSettings.get loads or after it fails. The old await is gone, so useCreateAgentSession.ts:68, useAgentSessionLauncher.ts:73 and useSubmitWorkspace.ts:287 can open a terminal for a Chat-on user. Fix: await utils.userSettings.get.ensureData() in those async paths.
  • minor packages/trpc/src/lib/user-settings.ts:16: the current acp-chat cohort is silently opted out, and so are their automations. Consider a backfill or a desktop notice.
  • nit persisted-keys.ts:12, constants.ts:229: both comments still say users.experimental_chat. constants.ts:243 still says "with ACP_CHAT".
  • nit useHostTerminals.ts:162 (and desktop auto-adopt): chat listing now runs for every user on every host poll. Confirm the extra host-service load is acceptable.
  • nit chat-turn-snapshots.ts:37: adopted chats get no turn snapshots while Chat is off.

Desktop: the Chat switch shows with no flag and is off by default. A failed update reverts the switch and shows a toast. I could not check the "on" state: this workspace's DB branch has no user_settings table. Mobile was not run.

Full report and screenshots: https://app.superset.sh/page/pr-9162-review-account-level-chat-setting-euo24t

- Launch paths wait for the setting (useResolveAcpChatEnabled) instead of
  reading "off" while userSettings.get loads: desktop launcher, new agent
  session, new workspace; mobile new terminal workspace and new session.
- Desktop sign-out resets userSettings.get, so the next account never sees
  the previous one's value. Mobile already clears its query cache.
- The Chat switch is disabled while a save is in flight, so quick toggles
  cannot land out of order (desktop and mobile).
- "Track file changes per turn" stays visible, disabled while Chat is off,
  so settings search never points at a hidden control.
- Comments name user_settings.experimental_chat and the Chat setting.

Copy link
Copy Markdown
Collaborator Author

Review follow-up (fd92c2c), for the Greptile threads (now resolved) and @superset-home's review:

Finding Status
useAcpChatEnabled reads false while loading, so launches can open a terminal Fixed. Launch paths await useResolveAcpChatEnabled() (ensureData / ensureQueryData): desktop launcher and presets, new agent session, new workspace; mobile new terminal workspace and new session
Previous account's setting after sign-in Fixed. Desktop sign-out resets userSettings.get; mobile already clears its query cache
Overlapping toggles Fixed. Switch disabled while saving, desktop and mobile
Search points at the hidden snapshots control Fixed. Always rendered, disabled while Chat is off
Comments still say users.experimental_chat / "with ACP_CHAT" Fixed (persisted-keys.ts, constants.ts)
Current acp-chat cohort silently opted out Open: product decision. Options are a one-off backfill into user_settings, a desktop notice, or leaving it as off-by-default
Chat listing on every host poll Kept on purpose. Existing chats have to show for everyone (automations, other devices). One extra call per host poll, failures ignored
No turn snapshots in adopted chats while Chat is off Intended. Snapshots belong to the Chat experiment

Checks: desktop tsc clean, full suite 9023 passing; mobile 248 passing (no new type errors); check:i18n clean.

@harshithmullapudi
harshithmullapudi changed the base branch from superset/users-experimental-chat to main October 30, 2026 22:09
@harshithmullapudi
harshithmullapudi merged commit ed179b8 into main Oct 30, 2026
17 of 18 checks passed

This branch was successfully deployed

1 active deployment
preview — fd92c2cd Deployed Oct 30, 2026 by harshithmullapudi via Deploy Docs #13386
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