Repository navigation
fix(opencode): decode agents whose hidden flag is null - #9
Merged
Merged
Conversation
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.
This was referenced Oct 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
With oh-my-opencode-slim installed, OpenCode's
GET /agentreports 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 sendtrue).OpenCodeAgent.hiddenwas a non-nullBoolean = false, sodefaultJson(nocoerceInputValues) 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.hiddenand V2V2Agent.hiddenare nowBoolean? = null; onlytruehides an agenthidden: nullagent in the V2 agent listFollow-ups (separate PRs): consider
coerceInputValuesindefaultJsonso 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":nullagent 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 = falseOpenCodeModel.name: String = idとvariants: Map = emptyMap()OpenCodeModelLimit.context/output: Long = 0LOpenCodeProvider.name/models、ProviderCatalog.all/default/connectedOpenCodeFileNode.ignoredなどプラグインのエージェントが
native:falseを明示していることは確認済みとのことなので、ブロッカーにはしません。別 PR でcoerceInputValues = trueを入れる案を検討してください。これを入れると、null が来たときに既定値へ寄せられます。未知の enum 値も既定値に寄せられるようになるので、その影響の確認は必要です。空メニューの UX(範囲外なので評価のみ)。ChatHomeScreen.kt:1879-1931 では、
selectableAgentsが空でも chip は押せます。押すと中身のないDropdownMenuが開き、ラベルは"build"のままです。これが「押しても反応しない」ように見える直接の原因です。エージェント取得の失敗はRuntimeCatalogState.errorに入りますが(messages.agents(...))、chip からはその状態が分かりません。次のどちらかを別 PR で検討すると、同じ種類の報告を切り分けやすくなります。チェック済み項目
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の組み合わせで、選べる一覧と既定エージェントの両方を検証しています。旧実装ならこのテストは失敗します。.editorconfigでは ktlint の max-line-length が無効で、max_line_length = 140に収まっています。追加した KDoc/コメントの書き方も既存に合わせてあります。JDK が無く、私も./gradlew detekt spotlessCheck testDebugUnitTestは実行していません。PR 作成前に CI か手元で通ることを確認してください。