Skip to content

fix(opencode): decode agents whose hidden flag is null - #9

Merged
doublepi123 merged 2 commits into
mainfrom
fix/agent-picker-build
Oct 17, 2026
Merged

doublepi123 merged 2 commits into
mainfrom
fix/agent-picker-build

Conversation

@doublepi123

Copy link
Copy Markdown
Owner

With oh-my-opencode-slim installed, OpenCode's GET /agent reports the plugin agents (orchestrator, fixer, explorer, ...) with "hidden": null (verified on a live OpenCode 1.19.3 server; built-in agents omit the key, compaction/title/summary send true). OpenCodeAgent.hidden was a non-null Boolean = false, so defaultJson (no coerceInputValues) rejected the whole list, the catalogue fell back to no agents, and the mode chip opened an empty menu: tapping build appeared to do nothing.

  • OpenCodeAgent.hidden and V2 V2Agent.hidden are now Boolean? = null; only true hides an agent
  • Tests: the real 1.19.3 + plugin shape (V1), and a hidden: null agent in the V2 agent list

Follow-ups (separate PRs): consider coerceInputValues in defaultJson so other explicit nulls can't fail a whole list; show a disabled/explanatory state when the mode chip has no agents.

Pre-PR review

Reviewed at b4b525f. The follow-up commit 51ba08d applies the reviewer's first two non-blocking suggestions only (KDoc wording, and a "hidden":null agent in the V2 test fixture).

判定: APPROVE

ブロッカー

なし

提案(非ブロッキング)

  • app/src/main/java/com/yugahashimoto/andcode/core/api/OpenCodeV2ApiClient.kt:187-191 — KDoc の「the app's agent model has no hidden flag yet」は以前から事実と合っていません。OpenCodeAgent.hidden は既にあります。この PR で同じ箇所を触っているので、「V2 は hidden を OpenCodeAgent に写さず、ここで除外する」という趣旨に直すとよいです。

  • app/src/test/java/com/yugahashimoto/andcode/core/api/OpenCodeV2ApiClientTest.kt:1141 — V2 側の AGENT_LIST は hidden:false/true だけで、"hidden":null の要素がありません。V2Agent の変更が守られていることを確かめるため、null の要素を 1 件足すことを勧めます。今回の実害は V1 経路の GET /agent なので任意です。

  • 同じ「null でリスト全体が落ちる」パターンの防御について。今回の修正は対症療法として正しいです。ただ defaultJson(app/src/main/java/com/yugahashimoto/andcode/core/api/OpenCodeApiClient.kt:771-776)は coerceInputValues を有効にしていません。そのため次のフィールドに明示的な null が来ると、同じように一覧全体のデコードが失敗します。

    • OpenCodeAgent.native: Boolean = false
    • OpenCodeModel.name: String = id と variants: Map = emptyMap()
    • OpenCodeModelLimit.context/output: Long = 0L
    • OpenCodeProvider.name/models、ProviderCatalog.all/default/connected
    • OpenCodeFileNode.ignored など

    プラグインのエージェントが native:false を明示していることは確認済みとのことなので、ブロッカーにはしません。別 PR で coerceInputValues = true を入れる案を検討してください。これを入れると、null が来たときに既定値へ寄せられます。未知の enum 値も既定値に寄せられるようになるので、その影響の確認は必要です。

  • 空メニューの UX(範囲外なので評価のみ)。ChatHomeScreen.kt:1879-1931 では、selectableAgents が空でも chip は押せます。押すと中身のない DropdownMenu が開き、ラベルは "build" のままです。これが「押しても反応しない」ように見える直接の原因です。エージェント取得の失敗は RuntimeCatalogState.error に入りますが(messages.agents(...))、chip からはその状態が分かりません。次のどちらかを別 PR で検討すると、同じ種類の報告を切り分けやすくなります。

    • 空のときは chip を無効表示にする
    • 「エージェントを取得できません」という無効な項目を 1 件出す(要: 新しい文字列キーを全 8 ロケールに追加)

チェック済み項目

  • リスト全体が失敗するか: defaultJson は ignoreUnknownKeys/isLenient/encodeDefaults だけです。explicitNulls は既定の true、coerceInputValues は無効です。この設定では、null 非許容の Boolean に null が来るとデコード例外になります(isLenient は null の扱いを変えません)。OpenCodeApiClient.agents() → getList → json.decodeFromString<List<T>> で一覧全体が例外になります(OpenCodeApiClient.kt:101, 609-617)。その例外は RuntimeCatalogRepository の runCatching { target.listAgents() } で失敗になり、catalog.agents.getOrDefault(emptyList())(RuntimeCatalogRepository.kt:203, 244)で空一覧になります。説明どおりの経路であることを確認しました。
  • hidden の参照残り: main/test 全体を rg しました。OpenCodeAgent/V2Agent の hidden を参照するのは selectablePrimaryAgents(!= true)と V2 の agents()(== true)の 2 か所だけで、両方とも直っています。テストで hidden = true を渡している箇所は、Boolean? にしてもそのまま通ります。assertTrue の import も消えています。
  • 位置引数のコンストラクタ呼び出し: ClaudeCodeTarget.kt:358 と AntigravityTarget.kt:158 は (name, description, mode, native) の 4 引数で、hidden は渡していません。CodexModels.kt:39 は名前付き引数です。どれも影響を受けません。
  • ディスクキャッシュと設定保存: ProviderCatalogCache は ProviderCatalog だけを保存し、エージェントは保存しません。AppPreferencesRepository が保存するのは selectedAgentId(文字列)だけです。OpenCodeAgent をエンコードしている箇所もありません(encodeToString を検索、encodeDefaults の影響なし)。永続化への影響はありません。
  • 選び直しのロジック: AppPreferencesRepository.reconcile と ModeChip のラベル決定は selectablePrimaryAgents/defaultAgentName 経由です。この修正でプラグインのエージェント(orchestrator)が一覧に入り、サーバーの default_agent の順番どおりに選ばれます。
  • テスト: 新しいテストは実運用と同じ OpenCodeApiClient.defaultJson を使っています。中身は hidden:null、hidden キーなし、hidden:true、subagent、未知キー variant の組み合わせで、選べる一覧と既定エージェントの両方を検証しています。旧実装ならこのテストは失敗します。
  • i18n: 画面に出る文字列の追加や変更はありません。ロケールファイルへの影響もありません。
  • フォーマット: .editorconfig では ktlint の max-line-length が無効で、max_line_length = 140 に収まっています。追加した KDoc/コメントの書き方も既存に合わせてあります。JDK が無く、私も ./gradlew detekt spotlessCheck testDebugUnitTest は実行していません。PR 作成前に CI か手元で通ることを確認してください。

With oh-my-opencode-slim installed, OpenCode's GET /agent reports the
plugin agents (orchestrator, fixer, explorer, ...) with "hidden": null.
OpenCodeAgent.hidden was a non-null Boolean, so kotlinx.serialization
rejected the whole list, the catalogue fell back to no agents, and the
mode chip opened an empty menu - tapping "build" appeared to do nothing.

Make hidden nullable (V1 and V2 DTOs) and treat only true as hidden.
Verified against a live OpenCode 1.19.3 server with the plugin enabled.
@doublepi123
doublepi123 merged commit eff6cbc into main Oct 17, 2026
5 checks passed
@doublepi123
doublepi123 deleted the fix/agent-picker-build branch October 17, 2026 06:58
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.

1 participant