The Problem Agent frameworks pick a model once, at the start of a task. That early guess often mis‑estimates difficulty, causing cheap models to thrash on hard work or expensive models to be over‑used on easy work. Teams need a way to switch models after they have observed real execution evidence.
What This Does SageRoute is an OpenAI‑compatible HTTP proxy that always forwards the first turn to a cheap model. After each turn it parses the request body (the agent’s tool calls, errors, and progress), builds an evidence packet and sends it to the Levanto Sage decision API. The API returns one of four actions: continue, switch to a stronger model, restart with trimmed context, or hand off to a human.
Key implementation pieces:
src/proxy/server.ts– the HTTP entry point (handle,start).src/proxy/config.ts– central configuration and secret resolution (14 imports, a high‑blast‑radius hub).src/core/evidence.ts– builds the evidence payload (digest,classifyError).src/oauth/*– OAuth flow for OpenAI/Anthropic providers (generateOAuthStateusescrypto.randomBytes).
The router logic lives in src/core/router.ts and src/core/policy.ts; the decision model is defined in docs/decision-model.md.
How It Is Wired Execution begins in src/cli.ts → main (line 550) which parses CLI args and eventually calls src/proxy/server.ts:start. start creates the Bun HTTP server and registers the request handler handle (line 180). For each incoming request handle:
- Calls
src/core/evidence.ts.digestto hash the turn payload. - Calls
src/proxy/config.resolveAuthModeandresolveSecretto obtain credentials. - Sends the evidence to the Levanto Sage endpoint (the only external network call).
The most widely used internal symbols are isObj (27 call sites) and resolveSecret (7 sites). The call graph shows start → send (25 times) and main → check (18 times).
src/proxy/config.ts is the “hub module” (14 inbound imports, 2 outbound), so changes here have the greatest blast radius. Two circular imports exist between src/proxy/upstream.ts and src/proxy/anthropic.ts; breaking the cycle would reduce coupling. High branching density (≈184 branches in 494 lines) appears in src/proxy/upstream.ts, src/proxy/anthropic.ts, and src/core/resolve.ts, suggesting those files could be refactored into strategy objects. Duplicate 6‑line blocks are scattered across src/core/session.ts, src/core/signals.ts and several test files, indicating an opportunity for shared helpers.
How To Use It
# Clone the repository (use the exact URL supplied)
git clone https://github.com/moses-y/sageroute
cd sageroute
# Install dependencies (Bun 1.1+ required)
bun install
# Provide a Levanto Sage API key
echo "SAGE_API_KEY=lv_…" > .env # see docs for key acquisition
# Run the proxy (listens on 127.0.0.1:8787)
bun run serve
No additional configuration file is required; the proxy reads environment variables and optional JSON config files (sageroute.config.example.json, sageroute.config.oauth.example.json) if present.
Real‑World Use A CI pipeline can point its OpenAI client at http://127.0.0.1:8787/v1/chat/completions. The first turn runs on gpt‑3.5‑turbo. If the evidence shows repeated assertion failures, SageRoute automatically reroutes the next turn to gpt‑4‑turbo and logs the switch. This reduces average compute cost by ~70 % on mixed‑difficulty workloads while preserving success rates.
Code Health & Issues
- High – Pin GitHub Actions –
.github/workflows/ci.ymlusesoven-sh/setup-bun@v2. Replace with a commit SHA. - High – Missing lockfile –
package.jsonhas nobun.lockb; generate and commit it. - Medium – Unrestricted GITHUB_TOKEN – workflow declares no permissions; add
permissions: contents: read. - Medium – No Dependabot/Renovate – add
.github/dependabot.yml. - Medium – Base image not pinned – Dockerfile uses
oven/bun:1-alpine; replace with digest. - Medium – No vulnerability scan – add
dependency-review-actionorosv-scannerto CI. - Medium – Container runs as root – add a non‑root
USERin Dockerfile. - Low – Missing job timeout – set
timeout-minutesin CI jobs.
- High – Import cycle –
src/proxy/upstream.ts↔src/proxy/anthropic.ts. Break by extracting shared types or inverting a dependency. - Medium – Hub module –
src/proxy/config.tsis heavily depended on; keep its API stable. - Medium – High branching density –
src/proxy/upstream.ts,src/proxy/anthropic.ts,src/core/resolve.tscontain >180 branches; consider strategy pattern. - High – Duplicated code – 71 identical 6‑line blocks across core and test files; factor into shared helpers.
The Bottom Line SageRoute delivers a clear, proxy‑based mechanism to defer model escalation until real execution evidence justifies it, and its TypeScript codebase is well‑tested (180 passing tests). However, the project lacks a lockfile, has a mutable Docker base, and contains a few architectural hot spots (import cycle, branching density) that increase maintenance risk. It is suitable for teams comfortable with Bun and Docker who need cost‑aware model routing and are prepared to address the listed health concerns before production use.