authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-09-02 20:27:42-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-02 20:27:42-04:00
logdbc7bfa3f36cc61a3f1a2015e47d71ae9dee5421
tree72f7883b838e813595951b1718b9938715886d39
parent2971ec3209d7ef1b00d7ded70fe6342816b1539f
signature Signed by PGP key B5690EEEBB952194

fix(opencode): show Reasoning selector for OpenCode models (#9287)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

3 files changed, 35 insertions(+), 5 deletions(-)

apps/server/src/provider/Layers/OpenCodeProvider.ts+33-3
......@@ -171,7 +171,30 @@ function inferDefaultAgent(agents: ReadonlyArray<Agent>): string | undefined {
171171}
172172
173173const DEFAULT_OPENCODE_MODEL_CAPABILITIES: ModelCapabilities = createModelCapabilities({
174 optionDescriptors: [],
174 optionDescriptors: [
175 {
176 id: "variant",
177 label: "Reasoning",
178 type: "select",
179 options: [
180 { id: "low", label: "Low" },
181 { id: "medium", label: "Medium", isDefault: true },
182 { id: "high", label: "High" },
183 { id: "xhigh", label: "Extra High" },
184 ],
185 currentValue: "medium",
186 },
187 {
188 id: "agent",
189 label: "Agent",
190 type: "select",
191 options: [
192 { id: "build", label: "Build", isDefault: true },
193 { id: "plan", label: "Plan" },
194 ],
195 currentValue: "build",
196 },
197 ],
175198});
176199
177200function openCodeCapabilitiesForModel(input: {
......@@ -179,7 +202,14 @@ function openCodeCapabilitiesForModel(input: {
179202 readonly model: ProviderListResponse["all"][number]["models"][string];
180203 readonly agents: ReadonlyArray<Agent>;
181204}): ModelCapabilities {
182 const variantValues = Object.keys(input.model.variants ?? {});
205 const rawVariantValues = Object.keys(input.model.variants ?? {});
206 // When a model advertises no variants, synthesize the standard reasoning
207 // levels so the composer still offers a Reasoning selector (mirrors the
208 // Codex/Grok experience where reasoning is always configurable). The set
209 // covers the common OpenCode variant spectrum; `inferDefaultVariant`
210 // picks the provider-appropriate default (e.g. medium for openai/opencode).
211 const variantValues =
212 rawVariantValues.length > 0 ? rawVariantValues : ["low", "medium", "high", "xhigh"];
183213 const defaultVariant = inferDefaultVariant(input.providerID, variantValues);
184214 const variantOptions = variantValues.map((value) =>
185215 defaultVariant === value
......@@ -201,7 +231,7 @@ function openCodeCapabilitiesForModel(input: {
201231 ? [
202232 {
203233 id: "variant",
204 label: "Variant",
234 label: "Reasoning",
205235 type: "select" as const,
206236 options: variantOptions,
207237 ...(defaultVariant ? { currentValue: defaultVariant } : {}),
apps/web/src/components/chat/TraitsPicker.test.ts+1-1
......@@ -167,7 +167,7 @@ describe("buildUnavailableModelOptionDescriptors", () => {
167167 ).toEqual([
168168 {
169169 id: "variant",
170 label: "Variant",
170 label: "Reasoning",
171171 type: "select",
172172 options: [{ id: "max", label: "max" }],
173173 currentValue: "max",
apps/web/src/components/chat/TraitsPicker.tsx+1-1
......@@ -40,7 +40,7 @@ const SAVED_OPTION_LABELS: Readonly<Record<string, string>> = {
4040 agent: "Agent",
4141 effort: "Effort",
4242 reasoningEffort: "Reasoning effort",
43 variant: "Variant",
43 variant: "Reasoning",
4444};
4545
4646function savedOptionLabel(id: string): string {