Skip to content

Routing policy (routing.yaml)

Reference for the YAML schema RoutingYamlParser (gateway-router) reads, per PRD section 7 (F2). Loaded once at startup and on every POST /admin/routes/reload (F2.7), from the filesystem path configured via aether.routing.config-path (env var ROUTING_CONFIG_PATH, default routing.yaml relative to the working directory) — a real file on disk, not a classpath resource, since a classpath resource baked into the jar cannot be hot-reloaded.

providers:
<provider-name>:
baseUrl: <http base URL the ProviderAdapter for this name calls>
routes:
- alias: <model name clients request, e.g. "mock" or "fast-chat">
chain:
- provider: <provider-name, must exist under providers:>
model: <the model name to send to that provider>
weight: <integer, optional>
- provider: <provider-name>
model: <model name>
# weight omitted here: this entry is a strict, order-only fallback
  • providers: every name referenced by any route’s chain must have an entry here. Each entry currently maps to a MockProviderAdapter(gateway-providers); real provider types (Ollama, Groq, Gemini) are added in Phase 12 with their own adapter classes, at which point this section will likely need a type: field to select which adapter constructs the entry (not needed yet, since only the mock adapter exists).
  • routes[].alias: the value clients pass as model in POST /v1/chat/completions. At this phase, alias resolution is exact match only; predicate-based routing (F2.4: API-key tag, request size, X-Aether-Route header) is loaded but only X-Aether-Route forcing a specific alias is wired end-to-end so far.
  • routes[].chain: an ordered list of candidate provider/model pairs. Entries with a weight are weighted-randomly ordered relative to each other on every request (F2.5); entries without a weight are strict, order-preserved fallbacks, always tried after every weighted entry, regardless of their position in the YAML list.
  • A chain member’s circuit breaker is keyed by provider:model (F3.1), not by provider alone, so a bad model on an otherwise-healthy provider does not trip the breaker for that provider’s other models.

Example: the local dev / M2 default (routing.yaml at repo root)

Section titled “Example: the local dev / M2 default (routing.yaml at repo root)”
providers:
mock-primary:
baseUrl: http://localhost:8082
mock-fallback:
baseUrl: http://localhost:8083
routes:
- alias: mock
chain:
- provider: mock-primary
model: mock
weight: 100
- provider: mock-fallback
model: mock

A request for "model": "mock" always tries mock-primary first (the only weighted entry, so weighted-random selection is trivial with one candidate); if mock-primary’s breaker is open or its calls exhaust their retry budget, the request fails over to mock-fallback next, per F3.2.

POST /admin/routes/reload calls RoutingPolicyRepository.reload(), which re-reads and re-parses the file and atomically swaps both the route table and the constructed ProviderAdapter instances. In-flight requests using the old policy snapshot are unaffected; new requests use the reloaded policy immediately.