Skip to content

fix(copilot): use live model catalog for context windows and token exchange#7272

Closed
difujia wants to merge 2 commits into
NousResearch:mainfrom
difujia:fix/copilot-provider-model-catalog
Closed

fix(copilot): use live model catalog for context windows and token exchange#7272
difujia wants to merge 2 commits into
NousResearch:mainfrom
difujia:fix/copilot-provider-model-catalog

Conversation

@difujia

@difujia difujia commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes the Copilot provider to use live model catalog data instead of hardcoded static values from models.dev. This enables proper support for account-specific models (e.g. claude-opus-4.6-1m with 1M context) and enterprise Copilot endpoints.

The main issues were:

  1. Context windows were hardcoded from models.dev, which doesn't reflect per-account model availability
  2. Raw GitHub tokens need to be exchanged for Copilot API JWTs to access internal-only models
  3. The OAuth client ID limited the visible model catalog
  4. Enterprise Copilot endpoints were not supported (the base URL was always api.githubcopilot.com)

Related Issue

Fixes #7731 — Copilot provider uses hardcoded context windows and lacks token exchange

Also fixes #6455 — adds enterprise endpoint support via token exchange (proxy-ep field in the exchanged token automatically derives the correct API base URL for enterprise accounts)

Also related to #1055 (general Copilot provider improvements)

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)

Changes Made

  • hermes_cli/copilot_auth.py: Implement token exchange (raw GitHub token -> Copilot API JWT) via /copilot_internal/v2/token, with in-process caching and graceful fallback. Switch OAuth client ID to VS Code's for full model catalog access. Add derive_copilot_base_url_from_token() to extract enterprise endpoints from exchanged tokens. Extract header version constants (_EDITOR_VERSION, _EXCHANGE_USER_AGENT).
  • hermes_cli/models.py: Add get_copilot_model_context_window() that queries the live Copilot /models API (cached 1h) for real context window values. Add _resolve_copilot_catalog_credentials() returning both token and base URL. Pass base_url through catalog fetch functions for enterprise support.
  • hermes_cli/auth.py: Cache the derived Copilot base URL from token exchange and use it in credential resolution.
  • hermes_cli/model_switch.py: Fetch live Copilot model catalog in list_authenticated_providers() so account-specific models appear in /model selection.
  • hermes_cli/runtime_provider.py: Exchange raw token for JWT at runtime and use the derived base URL (individual vs enterprise).
  • agent/model_metadata.py: Add Copilot live catalog lookup before falling back to models.dev for context window resolution.
  • agent/models_dev.py: Override models.dev context_window with live Copilot catalog value for copilot/copilot-acp/github-copilot providers.
  • agent/auxiliary_client.py, run_agent.py: Tighten URL matching to .githubcopilot.com (with dot prefix) for enterprise endpoint compatibility while avoiding false positives.

How to Test

  1. Configure a GitHub Copilot account: hermes setup -> select Copilot provider
  2. Run hermes and use /model to switch models — account-specific models should appear in the list
  3. Select a model like claude-opus-4.6-1m — context window should reflect the real value (1M) not the default
  4. Verify the agent works normally with the Copilot provider
  5. For enterprise users: verify that the correct enterprise endpoint is used automatically after token exchange

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature
  • I've run pytest tests/ -q and all tests pass (2 pre-existing failures unrelated to this PR)
  • I've added tests for my changes (42 tests in test_copilot_auth.py — 8 new test classes covering token exchange, base URL derivation, context window lookup)
  • I've tested on my platform: Ubuntu 24.04

Documentation & Housekeeping

  • I've updated relevant documentation — N/A (no user-facing doc changes needed)
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've considered cross-platform impact — changes are network/API only, no OS-specific code
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Screenshots / Logs

Tested end-to-end with GitHub Copilot Individual plan running claude-opus-4.6-1m (1M context window) via Telegram gateway.

@difujia difujia force-pushed the fix/copilot-provider-model-catalog branch 2 times, most recently from 32456d7 to 4535c39 Compare April 11, 2026 01:58
…change

The Copilot provider hardcoded context windows from models.dev static
data, which did not reflect account-specific models (e.g. claude-opus-4.6-1m
with 1M context). This change:

- Queries the live Copilot /models API for real context window values
  and caches results for 1 hour
- Implements token exchange (raw GitHub token -> Copilot API JWT) via
  /copilot_internal/v2/token, with in-process caching and graceful
  fallback to raw token on failure
- Switches the OAuth client ID to VS Code's (Iv1.b507a08c87ecfe98)
  which grants access to the full model catalog including internal-only
  models
- Derives the correct API base URL (individual vs enterprise) from the
  proxy-ep field in the exchanged token
- Broadens URL matching from 'api.githubcopilot.com' to
  'githubcopilot.com' to handle enterprise endpoints
- Fetches live model catalog in /model switch so account-specific models
  appear in the selection list

Tested on Ubuntu 24.04 with GitHub Copilot Individual plan.
@difujia difujia force-pushed the fix/copilot-provider-model-catalog branch from 4535c39 to de63326 Compare April 11, 2026 01:59
The Copilot credential pool stores raw GitHub tokens (ghu_/gho_/github_pat_)
and the default base URL (api.githubcopilot.com). When _swap_credential()
is called during subagent delegation or credential rotation, these raw
values would overwrite the already-exchanged JWT and enterprise base URL,
causing 400 'model_not_supported' errors for models like claude-opus-4.6-1m
that require the enterprise endpoint.

Now _swap_credential() detects the copilot provider and calls
resolve_copilot_api_token() to exchange the raw token for a JWT and derive
the correct base URL before applying the swap. The exchange is cached
in-process so repeated calls are near-zero cost.

Fixes: delegate_task subagents and cron jobs failing with 400 errors
when using Copilot provider with credential pool rotation.
@difujia

difujia commented Apr 12, 2026

Copy link
Copy Markdown
Contributor Author

@teknium1 @alt-glitch Friendly ping — this PR fixes several critical Copilot provider issues that affect all Copilot users:

  1. Token exchange — raw GitHub tokens (gho_) need to be exchanged for Copilot API JWTs to access internal-only models like claude-opus-4.6-1m (1M context). Without this, users can only see the public model subset.
  2. OAuth Client ID — the current ID (Ov23li...) limits the visible model catalog. Switching to VS Code's ID (Iv1.b507a08c87ecfe98) grants access to the full catalog.
  3. Live context windows — context windows are currently hardcoded from models.dev static data, which doesn't reflect account-specific models. This queries the live /models API instead.
  4. Enterprise support — enterprise Copilot users get a different API base URL (api.enterprise.githubcopilot.com), which is now auto-detected from the exchanged token.

Includes 8 new test classes (42 tests total in test_copilot_auth.py). Tested end-to-end on Ubuntu 24.04 with Copilot Individual plan running claude-opus-4.6-1m via Telegram gateway.

Happy to rebase on latest main if needed!

@Jitha-afk

Copy link
Copy Markdown

Thanks for doing this! @difujia

difujia added a commit to difujia/hermes-agent that referenced this pull request Apr 20, 2026
… resolver

The Copilot provider resolved context windows via models.dev static data,
which does not include account-specific models (e.g. claude-opus-4.6-1m
with 1M context). This adds the live Copilot /models API as a higher-
priority source for copilot/copilot-acp/github-copilot providers.

New helper get_copilot_model_context() in hermes_cli/models.py extracts
capabilities.limits.max_prompt_tokens from the cached catalog. Results
are cached in-process for 1 hour.

In agent/model_metadata.py, step 5a queries the live API before falling
through to models.dev (step 5b). This ensures account-specific models
get correct context windows while standard models still have a fallback.

Part 1 of NousResearch#7731.
Refs: NousResearch#7272
@difujia

difujia commented Apr 23, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of the split PRs as suggested by @konsisumer in #7731:

Thanks for the review guidance!

@difujia difujia closed this Apr 23, 2026
teknium1 pushed a commit that referenced this pull request Apr 24, 2026
… resolver

The Copilot provider resolved context windows via models.dev static data,
which does not include account-specific models (e.g. claude-opus-4.6-1m
with 1M context). This adds the live Copilot /models API as a higher-
priority source for copilot/copilot-acp/github-copilot providers.

New helper get_copilot_model_context() in hermes_cli/models.py extracts
capabilities.limits.max_prompt_tokens from the cached catalog. Results
are cached in-process for 1 hour.

In agent/model_metadata.py, step 5a queries the live API before falling
through to models.dev (step 5b). This ensures account-specific models
get correct context windows while standard models still have a fallback.

Part 1 of #7731.
Refs: #7272
nekorytaylor666 pushed a commit to nekorytaylor666/hermes-agent that referenced this pull request Apr 24, 2026
… resolver

The Copilot provider resolved context windows via models.dev static data,
which does not include account-specific models (e.g. claude-opus-4.6-1m
with 1M context). This adds the live Copilot /models API as a higher-
priority source for copilot/copilot-acp/github-copilot providers.

New helper get_copilot_model_context() in hermes_cli/models.py extracts
capabilities.limits.max_prompt_tokens from the cached catalog. Results
are cached in-process for 1 hour.

In agent/model_metadata.py, step 5a queries the live API before falling
through to models.dev (step 5b). This ensures account-specific models
get correct context windows while standard models still have a fallback.

Part 1 of NousResearch#7731.
Refs: NousResearch#7272
justrhoto pushed a commit to justrhoto/hermes-agent that referenced this pull request Apr 24, 2026
… resolver

The Copilot provider resolved context windows via models.dev static data,
which does not include account-specific models (e.g. claude-opus-4.6-1m
with 1M context). This adds the live Copilot /models API as a higher-
priority source for copilot/copilot-acp/github-copilot providers.

New helper get_copilot_model_context() in hermes_cli/models.py extracts
capabilities.limits.max_prompt_tokens from the cached catalog. Results
are cached in-process for 1 hour.

In agent/model_metadata.py, step 5a queries the live API before falling
through to models.dev (step 5b). This ensures account-specific models
get correct context windows while standard models still have a fallback.

Part 1 of NousResearch#7731.
Refs: NousResearch#7272
ulasbilgen pushed a commit to ulasbilgen/hermes-adhd-agent that referenced this pull request May 1, 2026
… resolver

The Copilot provider resolved context windows via models.dev static data,
which does not include account-specific models (e.g. claude-opus-4.6-1m
with 1M context). This adds the live Copilot /models API as a higher-
priority source for copilot/copilot-acp/github-copilot providers.

New helper get_copilot_model_context() in hermes_cli/models.py extracts
capabilities.limits.max_prompt_tokens from the cached catalog. Results
are cached in-process for 1 hour.

In agent/model_metadata.py, step 5a queries the live API before falling
through to models.dev (step 5b). This ensures account-specific models
get correct context windows while standard models still have a fallback.

Part 1 of NousResearch#7731.
Refs: NousResearch#7272
aj-nt pushed a commit to aj-nt/hermes-agent that referenced this pull request May 1, 2026
… resolver

The Copilot provider resolved context windows via models.dev static data,
which does not include account-specific models (e.g. claude-opus-4.6-1m
with 1M context). This adds the live Copilot /models API as a higher-
priority source for copilot/copilot-acp/github-copilot providers.

New helper get_copilot_model_context() in hermes_cli/models.py extracts
capabilities.limits.max_prompt_tokens from the cached catalog. Results
are cached in-process for 1 hour.

In agent/model_metadata.py, step 5a queries the live API before falling
through to models.dev (step 5b). This ensures account-specific models
get correct context windows while standard models still have a fallback.

Part 1 of NousResearch#7731.
Refs: NousResearch#7272
donald131 pushed a commit to donald131/hermes-agent that referenced this pull request May 2, 2026
… resolver

The Copilot provider resolved context windows via models.dev static data,
which does not include account-specific models (e.g. claude-opus-4.6-1m
with 1M context). This adds the live Copilot /models API as a higher-
priority source for copilot/copilot-acp/github-copilot providers.

New helper get_copilot_model_context() in hermes_cli/models.py extracts
capabilities.limits.max_prompt_tokens from the cached catalog. Results
are cached in-process for 1 hour.

In agent/model_metadata.py, step 5a queries the live API before falling
through to models.dev (step 5b). This ensures account-specific models
get correct context windows while standard models still have a fallback.

Part 1 of NousResearch#7731.
Refs: NousResearch#7272
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
… resolver

The Copilot provider resolved context windows via models.dev static data,
which does not include account-specific models (e.g. claude-opus-4.6-1m
with 1M context). This adds the live Copilot /models API as a higher-
priority source for copilot/copilot-acp/github-copilot providers.

New helper get_copilot_model_context() in hermes_cli/models.py extracts
capabilities.limits.max_prompt_tokens from the cached catalog. Results
are cached in-process for 1 hour.

In agent/model_metadata.py, step 5a queries the live API before falling
through to models.dev (step 5b). This ensures account-specific models
get correct context windows while standard models still have a fallback.

Part 1 of NousResearch#7731.
Refs: NousResearch#7272
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
… resolver

The Copilot provider resolved context windows via models.dev static data,
which does not include account-specific models (e.g. claude-opus-4.6-1m
with 1M context). This adds the live Copilot /models API as a higher-
priority source for copilot/copilot-acp/github-copilot providers.

New helper get_copilot_model_context() in hermes_cli/models.py extracts
capabilities.limits.max_prompt_tokens from the cached catalog. Results
are cached in-process for 1 hour.

In agent/model_metadata.py, step 5a queries the live API before falling
through to models.dev (step 5b). This ensures account-specific models
get correct context windows while standard models still have a fallback.

Part 1 of NousResearch#7731.
Refs: NousResearch#7272
Egavasyug pushed a commit to Egavasyug/hermes-agent that referenced this pull request Jun 10, 2026
… resolver

The Copilot provider resolved context windows via models.dev static data,
which does not include account-specific models (e.g. claude-opus-4.6-1m
with 1M context). This adds the live Copilot /models API as a higher-
priority source for copilot/copilot-acp/github-copilot providers.

New helper get_copilot_model_context() in hermes_cli/models.py extracts
capabilities.limits.max_prompt_tokens from the cached catalog. Results
are cached in-process for 1 hour.

In agent/model_metadata.py, step 5a queries the live API before falling
through to models.dev (step 5b). This ensures account-specific models
get correct context windows while standard models still have a fallback.

Part 1 of NousResearch#7731.
Refs: NousResearch#7272
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants