feat(provider): add GitHub Copilot provider with device-flow auth (#1480)

* feat(provider): add GitHub Copilot provider with device-flow auth

Adds GitHub Copilot as a model provider, so Copilot models (gpt-4o/4.1/5,
Claude, Gemini, …) work through the normal chat + agent loop, incl. native
tool calling and vision.

Auth is one-click via the GitHub OAuth device flow; the access token is stored
as the endpoint's (encrypted) api_key and sent directly as `Authorization:
Bearer` (no Copilot-token exchange, no refresh — matching how editors talk to
the Copilot API). Copilot is a normal ModelEndpoint detected by host; the only
provider-specific behaviour is a small set of required request headers,
injected centrally.

Sign-in is available from Settings → model endpoints ("Connect GitHub
Copilot") and from chat via `/setup copilot`.

- src/copilot.py (new), routes/copilot_routes.py (new): constants, header
  builders, device-flow start/poll, model discovery, owner-scoped endpoint
  provisioning.
- src/llm_core.py, src/endpoint_resolver.py: detect `copilot`, inject headers,
  per-request x-initiator/vision.
- src/agent_loop.py: allowlist api.githubcopilot.com for native tool schemas.
- src/model_context.py: known context windows for Copilot (no unauthenticated
  /models probe).
- static/, README, tests/test_copilot*.py.

* Tidy copilot_routes: clarify supports_tools, note _PENDING is per-process
This commit is contained in:
Kenny Van de Maele
2026-06-04 21:13:14 +02:00
committed by GitHub
parent ca32b43b38
commit 1cd0aa2b8c
14 changed files with 946 additions and 2 deletions
+63
View File
@@ -35782,3 +35782,66 @@ body.theme-frosted .modal {
is already 16px and never zoomed leave it so we don't shrink it. */
.doc-email-richbody.doc-font-m { font-size: 16px !important; }
}
/* GitHub Copilot device-flow connect block (model endpoints → API) */
.adm-copilot-connect {
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid var(--border);
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.adm-copilot-connect #adm-copilotStatus { flex-basis: 100%; margin-top: 0; }
.adm-copilot-panel {
display: flex;
flex-direction: column;
gap: 8px;
padding: 10px;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 8px;
}
.adm-copilot-wait {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: color-mix(in srgb, var(--fg) 70%, transparent);
}
.adm-copilot-coderow {
display: flex;
align-items: center;
gap: 8px;
}
.adm-copilot-code-label {
font-size: 10px;
text-transform: uppercase;
letter-spacing: 0.06em;
color: color-mix(in srgb, var(--fg) 45%, transparent);
}
.adm-copilot-code {
font-family: var(--mono, ui-monospace, monospace);
font-size: 14px;
font-weight: 600;
letter-spacing: 0.12em;
padding: 4px 10px;
background: var(--panel);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--fg);
user-select: all;
}
.adm-copilot-copy { margin-left: auto; }
.adm-copilot-auth {
text-align: center;
text-decoration: none;
padding: 7px 12px;
font-size: 12px;
}
.adm-copilot-hint {
font-size: 11px;
line-height: 1.4;
color: color-mix(in srgb, var(--fg) 45%, transparent);
}