Routing and configuration are deliberately simple: the config file describes providers and model mappings, and the resolver turns a request body’s model string into a Route. The design favors data changes over code changes, which is why provider definitions are a BTreeMap<String, ProviderConfig> and why new Anthropic-compatible gateways can be added as TOML tables src/config.rs:9-269 src/routing.rs:37-89.
erDiagram
SERVER_CONFIG {
string bind
string default_provider
}
PROVIDER_CONFIG {
string kind
string base_url
string auth
string api_key_env
string api_key_header
string effort
}
ROUTE_CONFIG {
string model
string provider
string upstream_model
string effort
}
ROUTE_PREFIX_CONFIG {
string prefix
string provider
}
MODEL_CONFIG {
string id
string display_name
}
CONFIG ||--|| SERVER_CONFIG : contains
CONFIG ||--o{ PROVIDER_CONFIG : providers
CONFIG ||--o{ ROUTE_CONFIG : routes
CONFIG ||--o{ ROUTE_PREFIX_CONFIG : route_prefixes
CONFIG ||--o{ MODEL_CONFIG : models
flowchart TB
Defaults[Serialized defaults] --> File[TOML file]
File --> Env[SHUNT_ env]
Env --> Extract[Figment extract Config]
Extract --> Bind[Validate bind address]
Bind --> Urls[Validate provider base URLs]
Urls --> Auth[Validate api_key_env]
Auth --> Refs[Validate default/route/prefix provider refs]
Refs --> Warn[Warn discovery model without route]
Warn --> Ok[Validated Config]
classDef dark fill:#2d333b,stroke:#6d5dfc,color:#e6edf3;
class Defaults,File,Env,Extract,Bind,Urls,Auth,Refs,Warn,Ok dark;
linkStyle default stroke:#8b949e;
sequenceDiagram
autonumber
participant Proxy as proxy::forward
participant Routing as routing::resolve
participant JSON as serde_json
participant Config as Config
Proxy->>Routing: body bytes
Routing->>JSON: parse RoutingView with model
JSON-->>Routing: model string
Routing->>Config: scan exact routes
Routing->>Config: scan prefix routes
Routing->>Config: fallback default provider
Routing-->>Proxy: Route with AdapterKind
| Input condition |
Selected provider |
Upstream model |
Effort source |
Source |
Exact route.model == model |
route.provider |
route.upstream_model or original model |
Route override, then provider default |
src/routing.rs:49-58 |
Prefix model.starts_with(prefix) |
Prefix provider |
Original model |
Provider default |
src/routing.rs:60-64 |
| No match |
server.default_provider |
Original model |
Provider default |
src/routing.rs:65-66 |
| Unknown provider after validation |
Fallback adapter is Anthropic |
Original model |
None/provider default if present |
src/routing.rs:75-82 |
flowchart LR
ProviderKind[ProviderKind] -->|anthropic| AnthropicKind[AdapterKind Anthropic]
ProviderKind -->|responses| ResponsesKind[AdapterKind Responses]
AnthropicKind --> Pass[Pass-through adapter]
ResponsesKind --> Translate[Responses adapter]
classDef dark fill:#2d333b,stroke:#6d5dfc,color:#e6edf3;
class ProviderKind,AnthropicKind,ResponsesKind,Pass,Translate dark;
linkStyle default stroke:#8b949e;