Skip to content

design opencode config

sinrimin edited this page Oct 20, 2026 · 1 revision

opencode dedicated config panel (#62)

Issue #62. The #60 pattern applied to opencode: the runtime-config form is target-aware — the provider row keeps ONLY the connection (provider → baseURL + credential), and an opencode-native panel owns everything else, stored on a typed additive spec.opencode. Ground truth: research §3.3 (opencode 1.18.31 schema, rig-verified) + the official config docs; UI reference: cc-switch's opencode form.

Wire

opencode: {
  models?: [{ id, name?, contextWindow?, maxOutputTokens?,
              reasoning?, temperatureEnabled?, vision?, options? }],  // ≤17
  smallModel?: string,          // bare id; the writer prefixes harness-nexus/
  autoupdateDisabled?: boolean,
}

Core mirrors it as OpencodeConfigData on RuntimeConfigSpecData; the service carries it through the upsert row and the GET view (the #60 lesson — the field-by-field row rebuild drops unknown fields, so both ends were wired up front).

Panel (opencode-panel.tsx)

Three sections — 模型 / 模型详情 / 行为:

  • 模型: default model (registry select when the picked provider has chat models, free text otherwise) + the 可选附加模型 allowlist rows — the generic form's rows, moved in (#60's migration).
  • 模型详情: one COLLAPSIBLE bordered group per switchable model (mono-id header + chevron; labeled fields inside at every width — the #60 mobile lesson applied from the start):
    • 显示名 → name
    • 上下文窗口 → limit.context (informational: context-remaining readout + auto-compaction) · 输出上限 → limit.output (a REAL request cap; opencode clamps globally to 32,000 — hinted)
    • capabilities → reasoning, temperature (BOOLEAN GATE — only when true does opencode send an agent's temperature value; the value itself is per-agent and out of scope), attachment (vision)
    • 请求选项 → options key-value rows, the #56 editing idiom (known boolean keys ride a Switch, others raw JSON parsed at the apply boundary); passthrough exists ONLY on the openai-compatible wire — hinted
  • 行为: 后台小模型 → top-level small_model (opencode's background model for lightweight tasks like title generation — the analog of claude-code's haiku pin; picked from the managed set, falls back to the main model when unset) · 禁用自动升级 → autoupdate: false (docs caveat: may not apply to package-manager installs incl. npm — our channel; hinted).

Draft state + prefill/serialize/validate live in the panel module (OcDraft, ocDraftFromSpec, serializeOcDraft, ocIssue); the apply button stays disabled while ocIssue reports a problem. serializeOcDraft drops a detail group with no knob set, drops smallModel when its id left the switchable set (the writer would point opencode at an unlisted route), and serializes to undefined for an all-default draft (untouched rows keep their pre-#62 shape).

Writer (applyOpencodeConfig)

Per-field precedence in the provider block's models map: panel value > #51 modelEntries seed > conservative fallback (8192/128000) — limit.* are REQUIRED by opencode's config schema, so an unset field FALLS BACK instead of deleting a key (the deliberate contrast with claude-code's unset-REMOVES-ours semantics; the bridge stays as fallback, so pre-#62 specs behave identically). Capability keys write only their true arm; options writes when non-empty.

Top-level small_model (harness-nexus/<id>) and autoupdate: false are BASE_URL-style owned: configured → write, cleared → remove ours. The provider block, /v1-normalized baseURL, {file:…} key reference and the raw 0600 key file are unchanged from W12.

Deliberately NOT built

  • agent-level temperature/top_p VALUES — per-agent concept, we manage no opencode agents (the panel only opens the entry-level gate)
  • default_agent, provider-level headers/extra options
  • models.dev metadata auto-fill (possible follow-up, could ride #51 query-models)
  • OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX unclamping, the responses wire

Tests

packages/cli/test/runtime-config.test.ts (panel-wins-per-field over the seed, capabilities/options writes, small_model/autoupdate ownership, idempotency, knob-less revert with fallback chain) and packages/shared/test/runtime-config.test.ts (schema bounds).

Clone this wiki locally