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 {...@@ -171,7 +171,30 @@ function inferDefaultAgent(agents: ReadonlyArray<Agent>): string | undefined {
171}171}
172172
173const DEFAULT_OPENCODE_MODEL_CAPABILITIES: ModelCapabilities = createModelCapabilities({173const 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 ],
175});198});
176199
177function openCodeCapabilitiesForModel(input: {200function openCodeCapabilitiesForModel(input: {
...@@ -179,7 +202,14 @@ function openCodeCapabilitiesForModel(input: {...@@ -179,7 +202,14 @@ function openCodeCapabilitiesForModel(input: {
179 readonly model: ProviderListResponse["all"][number]["models"][string];202 readonly model: ProviderListResponse["all"][number]["models"][string];
180 readonly agents: ReadonlyArray<Agent>;203 readonly agents: ReadonlyArray<Agent>;
181}): ModelCapabilities {204}): 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"];
183 const defaultVariant = inferDefaultVariant(input.providerID, variantValues);213 const defaultVariant = inferDefaultVariant(input.providerID, variantValues);
184 const variantOptions = variantValues.map((value) =>214 const variantOptions = variantValues.map((value) =>
185 defaultVariant === value215 defaultVariant === value
...@@ -201,7 +231,7 @@ function openCodeCapabilitiesForModel(input: {...@@ -201,7 +231,7 @@ function openCodeCapabilitiesForModel(input: {
201 ? [231 ? [
202 {232 {
203 id: "variant",233 id: "variant",
204 label: "Variant",234 label: "Reasoning",
205 type: "select" as const,235 type: "select" as const,
206 options: variantOptions,236 options: variantOptions,
207 ...(defaultVariant ? { currentValue: defaultVariant } : {}),237 ...(defaultVariant ? { currentValue: defaultVariant } : {}),
apps/web/src/components/chat/TraitsPicker.test.ts+1-1
...@@ -167,7 +167,7 @@ describe("buildUnavailableModelOptionDescriptors", () => {...@@ -167,7 +167,7 @@ describe("buildUnavailableModelOptionDescriptors", () => {
167 ).toEqual([167 ).toEqual([
168 {168 {
169 id: "variant",169 id: "variant",
170 label: "Variant",170 label: "Reasoning",
171 type: "select",171 type: "select",
172 options: [{ id: "max", label: "max" }],172 options: [{ id: "max", label: "max" }],
173 currentValue: "max",173 currentValue: "max",
apps/web/src/components/chat/TraitsPicker.tsx+1-1
...@@ -40,7 +40,7 @@ const SAVED_OPTION_LABELS: Readonly<Record<string, string>> = {...@@ -40,7 +40,7 @@ const SAVED_OPTION_LABELS: Readonly<Record<string, string>> = {
40 agent: "Agent",40 agent: "Agent",
41 effort: "Effort",41 effort: "Effort",
42 reasoningEffort: "Reasoning effort",42 reasoningEffort: "Reasoning effort",
43 variant: "Variant",43 variant: "Reasoning",
44};44};
4545
46function savedOptionLabel(id: string): string {46function savedOptionLabel(id: string): string {