feat(api-server): per-client model routing via model_routes (#3176 salvage) - #833
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Salvages NousResearch#3176 by @Mibayy, rebased/reimplemented against the heavily-evolved
api_server.pyon current main.Adds a no-code routing layer to the OpenAI-compatible API server: a
model_routesmap inplatforms.api_server.extraroutes the client-requested OpenAImodelfield to a real model/provider (+optional per-route upstreamapi_key/base_url), so one Hermes deployment can serve multiple clients on different backends. Unmatched model values fall back to the global model, andGET /v1/modelslists all configured aliases for client-side discovery.Design decisions (vs. the original PR)
/modeloverride →model_routesroute → global config._create_agentconsultsGatewayRunner._session_model_overrides(via the existing_gateway_runner_refweakref) and skips the route when the session carries an explicit/modeloverride — a user-issued switch always beats static per-client config, mirroring the just-mergedchannel_overridesprecedence in_resolve_session_agent_runtime.provider:but no explicit key resolves real credentials via_resolve_runtime_agent_kwargs_for_provider(the same seamchannel_overridesuses), instead of just renaming the provider on top of the default provider's key like the original PR did.api_keyis an upstream provider credential, not caller authentication — callers still authenticate with the global bearer key checked viahmac.compare_digestin_check_auth. Route secrets are never logged (only alias/model/provider names appear in debug logs) and never exposed through/v1/models(test-asserted)._parse_model_routesdrops malformed entries (non-dict routes, missingmodel) with a warning and strips unknown keys, so a config typo can't take down the API server or smuggle arbitrary AIAgent kwargs./v1/chat/completions(streaming + non-streaming),/v1/responses(streaming + non-streaming), and/v1/runs(the original PR predated/v1/runs).Changes
gateway/platforms/api_server.py—_parse_model_routesvalidation,_resolve_route,_session_model_override_for,route=plumbing through_create_agent/_run_agentand all handlers,/v1/modelsalias listingtests/gateway/test_api_server.py— 17 new tests (parsing/validation,/v1/modelsdiscovery + secret-leak guard, handler wiring for chat/responses, agent-creation overrides, session-override precedence)cli-config.yaml.example— documentedmodel_routesblockscripts/release.py— AUTHOR_MAP attribution for @MibayyValidation
scripts/run_tests.sh tests/gateway/test_api_server.py -qruff check gateway/platforms/api_server.py tests/gateway/test_api_server.pygit rev-list origin/main..merge-baseInfographic
Nous Research
Mirror-of: NousResearch#57028
NousResearch#57028