fix(models): route Responses-only Copilot models to the Responses API - #58835
fix(models): route Responses-only Copilot models to the Responses API#58835SvichkarevAnatoly wants to merge 1 commit into
Conversation
`copilot_model_api_mode` decides the Copilot API mode primarily from a model-id regex that only recognises GPT-5+ models as Responses-API models. A non-GPT model that is Responses-only — e.g. `mai-code-1-flash-picker` — falls through to `chat_completions` and the request fails with HTTP 400 "model ... is not accessible via the /chat/completions endpoint". Keep the opencode-parity regex first (so GPT-5+ reasoning models stay on their native Responses endpoint even when the catalog also advertises /chat/completions), then consult the catalog's `supported_endpoints` to rescue models the regex doesn't cover: when a model does NOT advertise /chat/completions at all, route it by its declared endpoint (`/responses` -> codex_responses, `/v1/messages` -> anthropic_messages). Models that DO advertise /chat/completions (Claude, Gemini on Copilot) keep using it, so behaviour for them is unchanged. Verified live against a Business seat: `mai-code-1-flash-picker` now returns 200 via the Responses API and self-identifies correctly, while all other Copilot models keep their previous api_mode. Follow-up to NousResearch#58830 (raw-token exchange); together they make every model advertised by a Copilot seat usable. Relates to NousResearch#45813. Signed-off-by: Anatoly Svichkarev <6915620+SvichkarevAnatoly@users.noreply.github.com>
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Comment (LGTM)
Routing fix: routes Responses-only Copilot models to the Responses API. Correctly distinguishes between models that use the Responses API endpoint vs. the Chat Completions endpoint. 2 files changed — model routing logic and tests.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the catalog-routing gap. The primary defect is present on current main: hermes_cli/models.py:3408-3425 routes non-GPT catalog entries through a fallback that recognizes only Messages-only models, so a Responses-only entry reaches chat_completions. The proposed catalog fallback addresses that path while retaining the existing GPT-first rule.
Problems
agent/chat_completion_helpers.py:1503-1534independently computes fallback API mode. Its Copilot branch ultimately uses the GPT-name-only predicate inrun_agent.py:1430-1433, so a non-GPT Copilot fallback advertising only/responsesstill activates aschat_completions.
Suggested changes
- Reuse
copilot_model_api_mode()or a shared catalog-aware resolver in the fallback route, and add a fallback-activation regression test for a non-GPT/responses-only catalog entry.
Automated hermes-sweeper review.
| @@ -3310,9 +3315,11 @@ def copilot_model_api_mode( | |||
| for endpoint in (catalog_entry.get("supported_endpoints") or []) | |||
There was a problem hiding this comment.
This fixes the primary resolver, but fallback activation still derives Copilot mode separately in agent/chat_completion_helpers.py:1503-1534 through the GPT-name-only predicate. Please route that sibling path through the same catalog-aware decision and add a fallback regression test; otherwise a non-GPT /responses-only fallback remains on Chat Completions.
What does this PR do?
Routes Responses-only Copilot models to the Responses API so they stop failing with
HTTP 400 "model … is not accessible via the /chat/completions endpoint".copilot_model_api_mode()picks the Copilot API mode primarily from a model-id regex (_should_use_copilot_responses_api) that only recognises GPT-5+ models as Responses-API models. A non-GPT model that is Responses-only — e.g.mai-code-1-flash-picker— falls through tochat_completionsand the request fails.This PR keeps the opencode-parity regex first (so GPT-5+ reasoning models stay on their native Responses endpoint even when the catalog also advertises
/chat/completions), then consults the catalog'ssupported_endpointsto rescue models the regex doesn't cover: when a model does not advertise/chat/completionsat all, it is routed by its declared endpoint —/responses→codex_responses,/v1/messages→anthropic_messages. Models that do advertise/chat/completions(Claude, Gemini on Copilot) keep using it, so their behaviour is unchanged.mai-code-1-flash-picker/responsesclaude-*/gemini-*(Copilot)/chat/completions, …/v1/messagesRelated Issue
Relates to #45813
Type of Change
Changes Made
hermes_cli/models.py: incopilot_model_api_mode, replace the "messages-only" catalog check with a general "no/chat/completions" fallback that honours/responses(→ codex_responses) and/v1/messages(→ anthropic_messages).tests/hermes_cli/test_model_validation.py: add 3 unit tests — Responses-only non-GPT model → codex_responses, Messages-only → anthropic_messages, chat-capable non-GPT stays chat_completions.How to Test
mai-code-1-flash-picker.main:HTTP 400 … not accessible via the /chat/completions endpoint.pytest tests/hermes_cli/test_model_validation.py -q→ 90 passed.Checklist
Code
fix(models):)tests/hermes_cli/test_model_validation.py: 90 passed)Documentation & Housekeeping
cli-config.yaml.exampleCONTRIBUTING.md/AGENTS.md