Skip to content

fix(opencode): sync v2 session option state and apply live agent switches - #1186

Merged
catatafishen merged 1 commit into
catatafishen:masterfrom
BambinoSK:fix/opencode-v2-session-option-sync
Oct 17, 2026
Merged

catatafishen merged 1 commit into
catatafishen:masterfrom
BambinoSK:fix/opencode-v2-session-option-sync

Conversation

@BambinoSK

Copy link
Copy Markdown
Contributor

Fixes #1185.

Problem

OpenCode v2 pushes no config_option_update notifications: the full updated configOptions array is returned only as the session/set_config_option response echo, and the plugin discarded it everywhere. Session option state therefore went stale for the whole session (the Effort tick kept the pre-switch value after a model change reset the per-model effort), and agent switches were silent no-ops: the menu restarts the process expecting buildCommand to forward the selection, but OpenCodeClient never passes an agent flag, v2 removed session/set_model, and session/new silently ignores agent/modeId params, so every session kept running build. Wire evidence and step-by-step repros are in the issue.

What this PR does

  • Apply the set_config_option echo to local option state. New shared AcpClient.applyConfigOptionEcho is attached to the request future in setConfigOption; the echoed array (including cross-effects such as effort resetting on a model switch) is merged through the same path as config_option_update notifications. Rejected options (-32602) complete exceptionally and leave state untouched.
  • Capture model-switch cross-effects. OpenCodeClient.sendSetModel's v2 branch, which routes model changes through session/set_config_option (v2 removed session/set_model), attaches the same hook. The whenComplete runs before the blocking wait, so a late echo still applies after a timeout.
  • Tick-mark the live value in the gear menu. New SessionOption.effectiveValue: the agent-reported live value wins, the locally stored pick is only the pre-session fallback, so the menu no longer keeps stale selections after agent-side resets.
  • Switch agents live on v2. New AbstractClient.canSwitchAgentLive(slug). OpenCode v2 advertises its session modes (build, plan, plus custom agents from .opencode/agents/) as the mode config option's values, and session/set_config_option(mode) switches the live session, so OpenCodeClient overrides onAgentSlugChanged (live push) and onSessionCreated (deferred push of a selection stored before the session existed), guarded by the advertised values so invalid slugs are never sent and redundant switches are suppressed. The menu applies switchable slugs without a process restart, persists them for future sessions, and shows a status banner; non-switchable agents keep the restart flow and v1 keeps the legacy behavior.

Notes for reviewers

  • The echo application is a no-op for agents that answer without a configOptions key or push notifications instead (same merge path, idempotent replace by id); agents whose options are static (no live initialValue) keep the stored-pick behavior in the menu. AcpClientEchoGuardTest pins these guards.
  • The onAgentSlugChanged/onSessionCreated extension points and the deferred-then-applied selection flow follow the existing Kiro v3 pattern.
  • 10 files changed, +612/-5, with tests: AcpClientEchoGuardTest, OpenCodeClientModelEchoTest, OpenCodeClientAgentSwitchTest, SessionOptionEffectiveValueTest.

Verification

  • :plugin-core:test green on this branch for AcpClientEchoGuardTest, OpenCodeClientModelEchoTest, OpenCodeClientAgentSwitchTest, SessionOptionEffectiveValueTest, OpenCodeClientBehaviorTest, OpenCodeClientModelRoutingTest, AcpClientProtocolTest.
  • Live-verified on OpenCode v2.0.27 (evidence in the issue): the Effort tick resets after a model switch; build/plan switches apply to the running session (the agent's self-reported mode changes in-session, same session id, no restart); a persisted selection is applied when a new session starts; a custom agent in .opencode/agents/ is listed, live-switchable, and runs with its own system prompt.

How to verify the interactive behavior

  1. Connect OpenCode v2, open a session, set Effort to High, switch the model in the Model dropdown, reopen the gear menu: the tick is back on Default.
  2. Ask the agent which mode it runs as, select Plan in the Agent menu (no restart happens), ask again: it answers plan. Select Build and ask again: build.
  3. With Plan selected, start a fresh session: it begins in plan.

…ches

OpenCode v2 pushes no config_option_update notifications: the full updated
configOptions array is returned only as the session/set_config_option
response echo, and the plugin discarded it everywhere. Session option state
therefore went stale for the whole session: switching the model (which
resets the per-model effort to its default) left the Effort tick on the
pre-switch value, and agent switches were silent no-ops because the Agent
menu restarts the process expecting buildCommand to forward the selection,
while v2 removed session/set_model and session/new silently ignores agent
params, so every session kept running build.

- AcpClient.setConfigOption applies the echoed configOptions array to the
  local option state via a shared applyConfigOptionEcho hook; rejected
  options (-32602) complete exceptionally and leave state untouched.
- OpenCodeClient.sendSetModel's v2 branch, which routes model changes
  through session/set_config_option, attaches the same hook so
  model-switch cross-effects are captured too.
- The gear menu tick-marks the agent-reported live value (new
  SessionOption.effectiveValue) with the stored pick as pre-session
  fallback, instead of preferring the stale stored selection.
- New AbstractClient.canSwitchAgentLive(slug): OpenCode v2 exposes its
  session modes (build, plan, and custom project agents registered as mode
  values) as the mode config option, and session/set_config_option(mode)
  switches the live session. The menu applies switchable slugs live via
  setCurrentAgentSlug, persists them for future sessions and applies them
  on session creation; other agents keep the process-restart flow and v1
  keeps the legacy behavior.
@github-actions

Copy link
Copy Markdown

⚠️ ClusterFuzzLite — Maintainer Security Review Required

A maintainer needs to approve the ClusterFuzzLite PR fuzzing workflow run for this fork PR.

Before approving, please review the code changes from BambinoSK/agentbridge@93f17a54 to confirm there is no code that could:

  • Exfiltrate the CFLITE_STORAGE_REPO_TOKEN CI secret
  • Abuse CI infrastructure or the fuzz corpus storage repository

The fuzz targets from the fork branch will be compiled and executed with access to repository secrets. Rubber-stamping this approval without reviewing the code is a security risk.

This comment is posted automatically whenever ClusterFuzzLite is triggered on a fork PR.

@codecov

codecov Bot commented Oct 15, 2026

Copy link
Copy Markdown

@catatafishen
catatafishen merged commit 689cb56 into catatafishen:master Oct 17, 2026
19 of 20 checks passed

This branch is waiting to be deployed

1 waiting deployment
fuzzing-gate — 93f17a54 Waiting Oct 15, 2026 by BambinoSK via Maintainer approval gate (fork PR) #1638
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.

OpenCode v2: session option state never syncs and agent switching is a silent no-op

2 participants