Conversation
c44cdf0 to
91999eb
Compare
Desktop/external clients that send a model field in the session chat or
chat/stream request body can now override the gateway default for that
turn. _create_agent() and _run_agent() accept requested_model, which
takes priority over _resolve_gateway_model() when present.
Wired through:
- POST /api/sessions/{id}/chat
- POST /api/sessions/{id}/chat/stream
This enables the desktop composer model picker to hot-swap the model
mid-session without requiring a config.yaml write + gateway restart.
Upstream PRs NousResearch#22825, NousResearch#25552, and NousResearch#36110 address similar gaps on /v1/*
paths; this patch is scoped to the /api/sessions/* surface only.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the model value through all three API endpoints. The direct body-model behavior is still absent for unconfigured values, but current main has since added a different routing seam.
Problems
- Current main resolves request models through configured
model_routesaliases only (gateway/platforms/api_server.py:1207,:2194,:3312,:4285), with explicit session/modelprecedence in_create_agent(:1291-1334). The proposed parallelmodel_overridepath would bypass that architecture. - The added raw provider-config lookup and fixed LiteLLM URL do not use the current provider runtime resolver.
gateway.run._resolve_runtime_agent_kwargs_for_providerresolves provider runtime fields including API mode and credential pool (gateway/run.py:1906-1924), and the existing route path calls it atgateway/platforms/api_server.py:1305-1311.
Suggested changes
- Salvage this through the existing
model_routes/routeflow, preserving session override precedence and using the provider-runtime resolver. - Add endpoint-level coverage for the intended unconfigured/direct-request behavior across chat completions, Responses, and Runs.
This is an automated hermes-sweeper review.
| # This allows API consumers (CCC, external UIs) to select a model | ||
| # per-request rather than always using the gateway default. | ||
| if model_override: | ||
| model = model_override |
There was a problem hiding this comment.
Current main resolves a switched provider through _resolve_runtime_agent_kwargs_for_provider (gateway/run.py:1906-1924) so it retains API mode, command arguments, and credential-pool behavior. Please salvage this through the current model_routes provider-resolution seam instead of reading a raw providers map here.
API consumers could not select a model per request: the body's 'model'
field was only honored when it matched a configured model_routes alias;
anything else silently fell back to the gateway default.
Salvaged through the existing model_routes seam per review, replacing
the earlier parallel model_override path:
- New opt-in flag platforms.api_server.extra.direct_model_requests
(default off — generic OpenAI clients hardcode model names and
existing deployments rely on unknown values falling back).
- _resolve_request_route(): configured aliases always win; with the
flag on, an unconfigured value that differs from the advertised
model name synthesizes an ephemeral {'model': value} route.
- Reuses _create_agent's route application, so session /model override
precedence is preserved and provider runtime resolution stays with
_resolve_runtime_agent_kwargs_for_provider — no raw provider-config
lookups, no fixed LiteLLM URL.
- Endpoint coverage across chat completions, Responses, and Runs, plus
default-off fallback and session-override-beats-request tests.
91999eb to
ca84221
Compare
|
@teknium1 done — rebuilt through the Force-pushed a single commit (
Local verification: |
Follow-ups on the salvaged #54426 routing contract: - Bare `model` without `provider` on the OpenAI-compatible endpoints (/v1/chat/completions, /v1/responses) is now opt-in via gateway.platforms.api_server.direct_model_requests (default off) — generic OpenAI clients hardcode model names ('gpt-4o', ...) and existing deployments rely on those falling back to the gateway default. Explicit `provider` requests and the Hermes-native session-chat + /v1/runs surfaces are always honored. Idea credit: PR #22825 by @mssteuer. - A model_routes alias with no `model` key can no longer leak the alias string as the executing model name (defensive; parse-time validation already drops such routes). - Fix mis-indented _run_agent call args in _handle_session_chat_stream. - Docs: document the opt-in flag.
|
Closing in favor of PR #70853 (salvage of #54426), which now covers per-request model selection across all four API server execution surfaces — including your core idea: the opt-in |
Follow-ups on the salvaged NousResearch#54426 routing contract: - Bare `model` without `provider` on the OpenAI-compatible endpoints (/v1/chat/completions, /v1/responses) is now opt-in via gateway.platforms.api_server.direct_model_requests (default off) — generic OpenAI clients hardcode model names ('gpt-4o', ...) and existing deployments rely on those falling back to the gateway default. Explicit `provider` requests and the Hermes-native session-chat + /v1/runs surfaces are always honored. Idea credit: PR NousResearch#22825 by @mssteuer. - A model_routes alias with no `model` key can no longer leak the alias string as the executing model name (defensive; parse-time validation already drops such routes). - Fix mis-indented _run_agent call args in _handle_session_chat_stream. - Docs: document the opt-in flag.
Follow-ups on the salvaged NousResearch#54426 routing contract: - Bare `model` without `provider` on the OpenAI-compatible endpoints (/v1/chat/completions, /v1/responses) is now opt-in via gateway.platforms.api_server.direct_model_requests (default off) — generic OpenAI clients hardcode model names ('gpt-4o', ...) and existing deployments rely on those falling back to the gateway default. Explicit `provider` requests and the Hermes-native session-chat + /v1/runs surfaces are always honored. Idea credit: PR NousResearch#22825 by @mssteuer. - A model_routes alias with no `model` key can no longer leak the alias string as the executing model name (defensive; parse-time validation already drops such routes). - Fix mis-indented _run_agent call args in _handle_session_chat_stream. - Docs: document the opt-in flag.
Follow-ups on the salvaged NousResearch#54426 routing contract: - Bare `model` without `provider` on the OpenAI-compatible endpoints (/v1/chat/completions, /v1/responses) is now opt-in via gateway.platforms.api_server.direct_model_requests (default off) — generic OpenAI clients hardcode model names ('gpt-4o', ...) and existing deployments rely on those falling back to the gateway default. Explicit `provider` requests and the Hermes-native session-chat + /v1/runs surfaces are always honored. Idea credit: PR NousResearch#22825 by @mssteuer. - A model_routes alias with no `model` key can no longer leak the alias string as the executing model name (defensive; parse-time validation already drops such routes). - Fix mis-indented _run_agent call args in _handle_session_chat_stream. - Docs: document the opt-in flag.
Summary
When API consumers (e.g. CCC task dispatcher, external UIs) pass a
modelfield in their request body, the API server now correctly uses that model instead of falling back to the gateway default.Problem
The
modelfield was extracted from the request body but never passed through to_create_agent(). This caused all API-spawned sessions to use the gateway default model regardless of what model was requested.Impact: Sessions requested on cheaper models (e.g.
openrouter/openai/gpt-5.5,litellm/gemini-2.5-flash) silently ran on the gateway default (claude-opus-4-6), burning expensive tokens on the wrong provider. In our setup, ~66 coding sessions in 18 hours ran on Opus when they should have been on OpenRouter.Root Cause
_handle_chat_completions,_handle_responses, and_handle_runsall extracted the model from the request body, but_create_agent()had nomodel_overrideparameter to receive it — the extracted value was used only for status display, never for actual agent creation.Fix
_create_agent()now accepts amodel_overrideparameteropenrouter/prefix → resolves OpenRouter credentials fromprovidersconfiglitellm-orlitellm/prefix → routes to LiteLLM proxy_run_agent()forwardsmodel_overrideto_create_agent()body.modelasmodel_overridebody.model == self._model_name, no override is applied)Tests
Added
tests/gateway/test_api_server_model_override.pywith 5 regression tests:_create_agentrespects override with openrouter prefix (credential resolution)_create_agentrespects override with litellm prefix (proxy routing)_create_agentrespects plain model name (model swap, keep provider)_create_agentuses gateway default when no overrideAll 162 existing API server tests continue to pass.