Summary
On opencode 1.18.15 (Arch package), the github-copilot provider never appears in the model picker. opencode auth login -p github-copilot works (auth succeeds), but opencode models github-copilot returns "Provider not found", and /models in the TUI shows no Copilot models.
Root cause
In packages/opencode/src/plugin/github-copilot/copilot.ts, the models() hook returns only models where result.pickerEnabled.has(model.api.id):
return CopilotModels.get(...)
.then((result) => {
models = result.models
return Object.fromEntries(
Object.entries(result.models).filter(([, model]) => result.pickerEnabled.has(model.api.id)),
)
})
pickerEnabled (built in models.ts:257) is the set of models with model_picker_enabled: true in the API response:
pickerEnabled: new Set([...remote].filter(([, item]) => item.model_picker_enabled).map(([id]) => id)),
GitHub's GET https://api.githubcopilot.com/models currently returns model_picker_enabled: false for every single model — even ones that are policy.state: "enabled" and fully usable. So pickerEnabled is always empty, the filter drops everything, and the provider surfaces zero models.
Evidence
Using a valid, freshly-authenticated Copilot OAuth token (device flow, client_id=Ov23li8tweQw6odWQebz):
HTTP 200, total models: 47
policy states: disabled: 18 | none: 23 (internal: copilot-search-*, exec-agent-*) | enabled: 6
model_picker_enabled=true: 0
The 6 policy.state: "enabled" models (gpt-4o, gpt-5-mini, claude-haiku-4.5, gpt-4.1, mai-code-1-flash, mai-code-1.1-flash) pass the existing usable() check (models.ts:207), and chat completions against them work fine:
POST https://api.githubcopilot.com/chat/completions → 200, "Hi there! ..."
So the account/subscription is fine — the filter is the problem. Note: exchanging the OAuth token for a Copilot session token via api.github.com/copilot_internal/v2/token and using that against /models returns 403, so the session-token route is not a workaround either.
Suggested fix
Filter by the already-existing usable() predicate (policy.state !== "disabled" + has max_output_tokens/max_prompt_tokens + has tool_calls) instead of, or in addition to, model_picker_enabled. Either:
- Return
result.models (already filtered by usable() inside CopilotModels.get) without the pickerEnabled filter, or
- Union
pickerEnabled with the usable set.
model_picker_enabled appears to be a deprecated/no-longer-reliable signal from GitHub's API.
Workaround
A local plugin overriding the provider's models() hook to return all usable models (same usable() criteria, no picker filter) restores all 25 available Copilot models:
// ~/.config/opencode/plugins/copilot-picker-fix.js
export const CopilotPickerFix = async () => ({
provider: {
id: "github-copilot",
async models(provider, ctx) {
if (ctx.auth?.type !== "oauth") return provider.models
const base = ctx.auth.enterpriseUrl
? `https://copilot-api.${ctx.auth.enterpriseUrl.replace(/^https?:\/\//, "").replace(/\/$/, "")}`
: "https://api.githubcopilot.com"
const r = await fetch(`${base}/models`, {
headers: { Authorization: `Bearer ${ctx.auth.refresh}`, "User-Agent": "opencode/1.18.15", "X-GitHub-Api-Version": "2026-06-01" },
signal: AbortSignal.timeout(5000),
})
if (!r.ok) return provider.models
const j = await r.json()
const models = {}
for (const m of j.data || []) {
if (m.policy?.state === "disabled") continue
const lim = m.capabilities?.limits
if (!lim?.max_output_tokens || !lim?.max_prompt_tokens) continue
if (m.capabilities?.supports?.tool_calls === undefined) continue
const isMsg = m.supported_endpoints?.includes("/v1/messages")
models[m.id] = {
id: m.id, providerID: "github-copilot",
api: { id: m.id, url: isMsg ? `${base}/v1` : base, npm: isMsg ? "@ai-sdk/anthropic" : "@ai-sdk/github-copilot" },
status: "active",
limit: { context: lim.max_context_window_tokens ?? lim.max_prompt_tokens, input: lim.max_prompt_tokens, output: lim.max_output_tokens },
capabilities: { temperature: true, reasoning: true, attachment: true, toolcall: m.capabilities.supports.tool_calls, input: { text: true, audio: false, image: !!m.capabilities.supports.vision, video: false, pdf: false }, output: { text: true, audio: false, image: false, video: false, pdf: false }, interleaved: false },
family: m.capabilities.family, name: m.name, cost: { input: 0, output: 0, cache: { read: 0, write: 0 } }, options: {}, headers: {},
release_date: m.version.startsWith(`${m.id}-`) ? m.version.slice(m.id.length + 1) : m.version,
}
}
return models
},
},
})
Environment
- opencode 1.18.15-1 (Arch Linux package)
- GitHub Copilot subscription: active (chat completions return 200)
- OAuth apps tested: opencode's own (
Ov23li8tweQw6odWQebz) and the VSCode Copilot app (Iv1.b507a08c87ecfe98) — same result either way
Summary
On opencode 1.18.15 (Arch package), the
github-copilotprovider never appears in the model picker.opencode auth login -p github-copilotworks (auth succeeds), butopencode models github-copilotreturns "Provider not found", and/modelsin the TUI shows no Copilot models.Root cause
In
packages/opencode/src/plugin/github-copilot/copilot.ts, themodels()hook returns only models whereresult.pickerEnabled.has(model.api.id):pickerEnabled(built inmodels.ts:257) is the set of models withmodel_picker_enabled: truein the API response:GitHub's
GET https://api.githubcopilot.com/modelscurrently returnsmodel_picker_enabled: falsefor every single model — even ones that arepolicy.state: "enabled"and fully usable. SopickerEnabledis always empty, the filter drops everything, and the provider surfaces zero models.Evidence
Using a valid, freshly-authenticated Copilot OAuth token (device flow,
client_id=Ov23li8tweQw6odWQebz):The 6
policy.state: "enabled"models (gpt-4o, gpt-5-mini, claude-haiku-4.5, gpt-4.1, mai-code-1-flash, mai-code-1.1-flash) pass the existingusable()check (models.ts:207), and chat completions against them work fine:So the account/subscription is fine — the filter is the problem. Note: exchanging the OAuth token for a Copilot session token via
api.github.com/copilot_internal/v2/tokenand using that against/modelsreturns 403, so the session-token route is not a workaround either.Suggested fix
Filter by the already-existing
usable()predicate (policy.state !== "disabled"+ hasmax_output_tokens/max_prompt_tokens+ hastool_calls) instead of, or in addition to,model_picker_enabled. Either:result.models(already filtered byusable()insideCopilotModels.get) without thepickerEnabledfilter, orpickerEnabledwith the usable set.model_picker_enabledappears to be a deprecated/no-longer-reliable signal from GitHub's API.Workaround
A local plugin overriding the provider's
models()hook to return all usable models (sameusable()criteria, no picker filter) restores all 25 available Copilot models:Environment
Ov23li8tweQw6odWQebz) and the VSCode Copilot app (Iv1.b507a08c87ecfe98) — same result either way