Skip to content

feat(api-server): per-client model routing via model_routes (#3176 salvage) - #833

Merged
hashbender merged 1 commit into
mainfrom
mirror/pr-57028
Jul 2, 2026
Merged

feat(api-server): per-client model routing via model_routes (#3176 salvage)#833
hashbender merged 1 commit into
mainfrom
mirror/pr-57028

Conversation

@hashbender

Copy link
Copy Markdown
Owner

Summary

Salvages NousResearch#3176 by @Mibayy, rebased/reimplemented against the heavily-evolved api_server.py on current main.

Adds a no-code routing layer to the OpenAI-compatible API server: a model_routes map in platforms.api_server.extra routes the client-requested OpenAI model field to a real model/provider (+optional per-route upstream api_key/base_url), so one Hermes deployment can serve multiple clients on different backends. Unmatched model values fall back to the global model, and GET /v1/models lists all configured aliases for client-side discovery.

platforms:
  api_server:
    enabled: true
    extra:
      key: "your-api-server-secret"
      model_routes:
        minimax-m2:                       # alias clients send as "model"
          model: "minimax/minimax-m1"
          provider: "openrouter"          # optional
          # api_key: "sk-..."             # optional upstream key override
          # base_url: "https://..."       # optional base URL override

Design decisions (vs. the original PR)

  • Precedence: session /model override → model_routes route → global config. _create_agent consults GatewayRunner._session_model_overrides (via the existing _gateway_runner_ref weakref) and skips the route when the session carries an explicit /model override — a user-issued switch always beats static per-client config, mirroring the just-merged channel_overrides precedence in _resolve_session_agent_runtime.
  • Provider credential resolution: a route with provider: but no explicit key resolves real credentials via _resolve_runtime_agent_kwargs_for_provider (the same seam channel_overrides uses), instead of just renaming the provider on top of the default provider's key like the original PR did.
  • Security: per-route api_key is an upstream provider credential, not caller authentication — callers still authenticate with the global bearer key checked via hmac.compare_digest in _check_auth. Route secrets are never logged (only alias/model/provider names appear in debug logs) and never exposed through /v1/models (test-asserted).
  • Config validation: _parse_model_routes drops malformed entries (non-dict routes, missing model) with a warning and strips unknown keys, so a config typo can't take down the API server or smuggle arbitrary AIAgent kwargs.
  • Coverage: routing is wired through all three agent-serving surfaces — /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_routes validation, _resolve_route, _session_model_override_for, route= plumbing through _create_agent/_run_agent and all handlers, /v1/models alias listing
  • tests/gateway/test_api_server.py — 17 new tests (parsing/validation, /v1/models discovery + secret-leak guard, handler wiring for chat/responses, agent-creation overrides, session-override precedence)
  • cli-config.yaml.example — documented model_routes block
  • scripts/release.py — AUTHOR_MAP attribution for @Mibayy

Validation

Check Result
scripts/run_tests.sh tests/gateway/test_api_server.py -q 193 passed (176 pre-existing + 17 new), 0 failed
ruff check gateway/platforms/api_server.py tests/gateway/test_api_server.py All checks passed
git rev-list origin/main..merge-base 0 (clean rebase on main)

Infographic

infographic

Nous Research


Mirror-of: NousResearch#57028
NousResearch#57028

@hashbender
hashbender merged commit 37488fa into main Jul 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant