Gateway

Architecture

Cargo workspace, 11 crates, strictly layered — lower layers never depend on higher ones:

server → {views, task} → handler → dag → {engines, state} → {models, protocol, config} → consts
Crate Layer Role
consts L0 error codes, the Protocol enum
models L1 request/response domain types, typed params, usage, cost
protocol L1 OpenAI / Anthropic wire types + cross-protocol conversions
config L1 YAML config loading (conf/gateway.yaml)
state L2 auth, account pool, quotas, rate limits, ledger, batch/file stores (in-process defaults; Postgres/Redis fleet backends)
engines L2 engine implementations behind the Transport seam, SSE + AWS EventStream decoding, usage extraction, SigV4
dag L3 4-layer pipeline executor + nodes
handler L4 online/offline orchestration, DLP/blocklist plugins
task L5 background tasks (quota reset, content purge, usage rollup, availability flush/alerts, webhook dispatch)
views L5 axum HTTP/WebSocket handlers, protocol conversion
server L6 binary entrypoint: config + state + transport wiring

Request flow

client ──► views (auth, parse, protocol normalize)
       ──► handler (pre plugins: blocklist, moderation, then DLP redact)
       ──► dag: preprocess        resolve model, quota check, cache lookup
              account_select      priority / PTU-first / cooldown-aware selection, latency-ranked tiers when enabled
              model_access        rate limits, engine call, failover on an upstream fault
              post_process        usage → billing ledger, cache store
       ──► handler (post plugins) ──► views (JSON or SSE re-emit)

A client disconnect does not cancel the pipeline: every request runs on its own task (run_pipeline / spawn_stream_pipeline), so once admitted, quota and ledger accounting run to completion even if the caller goes away. Spawned background work (offline batches) likewise outlives the submitting request.

The DAG executes four fixed layers; nodes within a layer run sequentially in declaration order. Within model_access, call_engine reselects once on an upstream 5xx or a 401/402/403 credential or billing refusal: the failed account is excluded and another of the model’s accounts is tried; a PTU→paygo switch is recorded as ptu_spillover in the ledger. Around the DAG, the handler re-runs all four layers for the next entry of the model’s fallback_models chain when a run ends in an upstream fault before any byte was sent.

Seams (traits)

Every boundary to the outside world is a trait with a deterministic default, so the whole pipeline is testable offline:

Testing