fix: detect copilot provider via gh auth token in /model picker

Seed copilot credentials from resolve_copilot_token() in the credential
pool's _seed_from_singletons(), alongside the existing anthropic and
openai-codex seeding logic. This makes copilot appear in the /model
provider picker when the user authenticates solely through gh auth token.

Cherry-picked from PR #9767 by Marvae.
This commit is contained in:
Marvae 2026-04-14 11:03:49 -07:00 committed by Teknium
parent 3e0bccc54c
commit 0bd3f521ae
2 changed files with 61 additions and 0 deletions

View file

@ -1152,6 +1152,30 @@ def _seed_from_singletons(provider: str, entries: List[PooledCredential]) -> Tup
},
)
elif provider == "copilot":
# Copilot tokens are resolved dynamically via `gh auth token` or
# env vars (COPILOT_GITHUB_TOKEN / GH_TOKEN). They don't live in
# the auth store or credential pool, so we resolve them here.
try:
from hermes_cli.copilot_auth import resolve_copilot_token
token, source = resolve_copilot_token()
if token:
source_name = "gh_cli" if "gh" in source.lower() else f"env:{source}"
active_sources.add(source_name)
changed |= _upsert_entry(
entries,
provider,
source_name,
{
"source": source_name,
"auth_type": AUTH_TYPE_API_KEY,
"access_token": token,
"label": source,
},
)
except Exception as exc:
logger.debug("Copilot token seed failed: %s", exc)
elif provider == "openai-codex":
state = _load_provider_state(auth_store, "openai-codex")
tokens = state.get("tokens") if isinstance(state, dict) else None

View file

@ -1071,3 +1071,40 @@ def test_load_pool_does_not_seed_claude_code_when_anthropic_not_configured(tmp_p
# Should NOT have seeded the claude_code entry
assert pool.entries() == []
def test_load_pool_seeds_copilot_via_gh_auth_token(tmp_path, monkeypatch):
"""Copilot credentials from `gh auth token` should be seeded into the pool."""
monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
_write_auth_store(tmp_path, {"version": 1, "credential_pool": {}})
monkeypatch.setattr(
"hermes_cli.copilot_auth.resolve_copilot_token",
lambda: ("gho_fake_token_abc123", "gh auth token"),
)
from agent.credential_pool import load_pool
pool = load_pool("copilot")
assert pool.has_credentials()
entries = pool.entries()
assert len(entries) == 1
assert entries[0].source == "gh_cli"
assert entries[0].access_token == "gho_fake_token_abc123"
def test_load_pool_does_not_seed_copilot_when_no_token(tmp_path, monkeypatch):
"""Copilot pool should be empty when resolve_copilot_token() returns nothing."""
monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
_write_auth_store(tmp_path, {"version": 1, "credential_pool": {}})
monkeypatch.setattr(
"hermes_cli.copilot_auth.resolve_copilot_token",
lambda: ("", ""),
)
from agent.credential_pool import load_pool
pool = load_pool("copilot")
assert not pool.has_credentials()
assert pool.entries() == []