Remote chats: model, mode and option picks reach the owning machine

Merged
TE
6d ago
+423-6

Leo's bug (his DEV build, a chat on a Cloud machine): picking a model in the chat's model picker shows

Couldn't switch to claude-opus-5-5: session/set_model is not available for a chat on another machine

and the Mode picker would not open on a Cloud chat.

What

A chat whose acpmux runs on another machine (a Cloud VM, an SSH host) goes through RemoteAcpmuxWire. That wire served only start, prompt, cancel, permission answers, trust and presence, so every model, mode and option pick fell through to its remote.unsupported refusal.

  • cmux-tui (the daemon on the machine that runs the chat). New verbs agent-session-set-model {surface, model_id}, agent-session-set-mode {surface, mode_id} and agent-session-set-config {surface, config_id, value}, advertised as agent-session-settings-v1 alongside agent-session-attach-v1. Each sends the matching ACP call (session/set_model, session/set_mode, session/set_config_option) to acpmux on the tab's own pinned session. The verbs take no session id param (deny_unknown_fields). Each returns acpmux's result unchanged, including set_config_option's configOptions, which the page reads. Ids and values must be 1-256 characters of the model-id charset, the same rule as the app's AcpmuxPaneMethods.isModelID. An observer attachment gets agent_session.read_only. A teammate or link guest gets agent_session.not_trusted; the proxy scope allowlists don't list these verbs either. Spec: cmux-tui/spec/commands.md.
  • App. AgentSessionRemoteClient gains setModel, setMode and setConfig. By default they throw agent_session.settings_unsupported ("update cmux on that machine..."). AgentSessionAttachClient calls the new verbs only when the daemon advertises the capability. RemoteAcpmuxWire forwards the three methods only for its own session (names(sessionId)), refuses them on an observer as read-only, and returns acpmux's answer. The logic lives in Rust; the Swift side only forwards. agentSessionSettings is added as an optional DaemonCapability, and plans/cmux-next/daemon-capabilities.json is regenerated.
  • The host's existing rules still run before the wire: the gesture rule for set_mode and set_config_option, the full-access rule, and removal of the _meta.cmuxGesture ticket. The wire never sends _meta.

Mode picker

The access chip's AccessMenu (ComposerPickers.tsx) marks a mode as refused when picking it fails. Once every other mode is refused, the chip shows a fixed label instead of a menu. On a remote chat every session/set_mode failed with the same refusal, so after one pick the chip stopped opening. Now that set_mode is forwarded, picks succeed and the chip stays a menu. No webview change is needed.

Risk

Only remote chats are affected. If the remote machine runs an older daemon, the person sees a clear "update cmux on that machine" error instead of the old refusal. Local chats don't change.

Tests

  • Rust (fleet Linux): 158 agent_session tests pass and clippy -D warnings is clean. New: model_mode_and_option_picks_go_to_the_pinned_session covers the capability, the not-attached refusal, pinned params, acpmux's answer passed back unchanged, and bad ids and params (including _meta and a leading -). Also added: read-only refusals on an observer for the three verbs, and refusals for the remote relay and untrusted connections through every_verb.
  • Swift (fleet Mac): RemoteAcpmuxSettingsTests (new) covers forwarding for this chat only, configOptions passed back, the older-daemon error and the observer read-only refusal. It passes, as do RemoteAcpmuxPresenceTests, RemoteAcpmuxWireAnswerTests, RemoteAcpmuxObserverTests and AgentSessionAttachClientPresenceTests.

Agent session: agent session

šŸ¤– Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Fixes model, mode, and option picks in chats that run on another machine (a Cloud VM, an SSH host) so they reach that machine's acpmux instead of failing with "session/set_model is not available for a chat on another machine".

  • The daemon on the owning machine now serves agent-session-set-model, agent-session-set-mode, and agent-session-set-config (agent-session-settings-v1), mapping them to acpmux's session/set_model, session/set_mode, and session/set_config_option on the chat's own session. Observers get agent_session.read_only; teammates and link guests get agent_session.not_trusted.
  • The app advertises the capability and forwards the three calls through RemoteAcpmuxWire only for the chat's own session, returning acpmux's answer unchanged (including configOptions). An older daemon answers with a clear "update cmux on that machine" error.
  • Fixes the mode picker closing after one failed pick: previously every session/set_mode on a remote chat failed, so the chip showed a fixed label instead of a menu.

Migration

  • Remote machines running an older daemon show the settings-unsupported error until their cmux-tui is updated; local chats are unaffected.