Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion packages/opencode/src/plugin/github-copilot/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,19 +220,27 @@ export async function get(
return item && usable(item) ? ([[item.id, item]] as const) : []
}),
)
// Secondary lookup index: normalize version separators so catalog keys like
// "claude-sonnet-4-6" (hyphen) match API IDs like "claude-sonnet-4.6" (dot).
const remoteByNormalized = new Map(
[...remote].map(([id, item]) => [id.replace(/\./g, "-"), item] as const),
)

// prune existing models whose api.id isn't in the endpoint response
const matched = new Set<string>()
for (const [key, model] of Object.entries(result)) {
const m = remote.get(model.api.id)
const m = remote.get(model.api.id) ?? remoteByNormalized.get(model.api.id.replace(/\./g, "-"))
if (!m) {
delete result[key]
continue
}
matched.add(m.id)
result[key] = build(key, m, baseURL, model)
}

// add new endpoint models not already keyed in result
for (const [id, m] of remote) {
if (matched.has(id)) continue
if (id in result) continue
result[id] = build(id, m, baseURL)
}
Expand Down
18 changes: 15 additions & 3 deletions packages/opencode/src/provider/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,9 @@ const OPENAI_GPT5_PRO_2_PLUS_EFFORTS = ["medium", "high", "xhigh"]
const OPENAI_GPT5_CHAT_EFFORTS = ["medium"]
const OPENAI_GPT5_CODEX_XHIGH_EFFORTS = [...WIDELY_SUPPORTED_EFFORTS, "xhigh"]
const OPENAI_GPT5_CODEX_3_PLUS_EFFORTS = ["none", ...OPENAI_GPT5_CODEX_XHIGH_EFFORTS]
// Copilot API returns reasoning_effort: ["low","medium","high","max"] for claude-sonnet-4.6.
// reasoning_summary=auto and include are accepted by /chat/completions for claude models.
const COPILOT_CLAUDE_EFFORTS = [...WIDELY_SUPPORTED_EFFORTS, "max"]

// OpenAI rolled out the `none` reasoning_effort tier on this date (Responses API).
// Models released before it 400 on `reasoning_effort: "none"`, so we only expose
Expand Down Expand Up @@ -822,7 +825,16 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
return {}
}
if (model.id.includes("claude")) {
return Object.fromEntries(WIDELY_SUPPORTED_EFFORTS.map((effort) => [effort, { reasoningEffort: effort }]))
return Object.fromEntries(
COPILOT_CLAUDE_EFFORTS.map((effort) => [
effort,
{
reasoningEffort: effort,
reasoningSummary: "auto",
include: INCLUDE_ENCRYPTED_REASONING,
},
]),
)
}
const copilotEfforts = iife(() => {
if (id.includes("5.1-codex-max") || id.includes("5.2") || id.includes("5.3"))
Expand Down Expand Up @@ -901,8 +913,8 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
if (model.api.id.includes("opus-4.7")) {
efforts = ["medium"]
}
// Efforts currently supported are: low, medium, high
efforts = efforts.filter((v) => v !== "max" && v !== "xhigh")
// xhigh is not surfaced by the Copilot API; max is explicitly supported
efforts = efforts.filter((v) => v !== "xhigh")
}
return Object.fromEntries(
efforts.map((effort) => [
Expand Down
Loading