Backend Flexibility: Routing a Personal Agent Through OpenRouter
Point a self-hosted personal agent at OpenRouter (or any OpenAI-compatible gateway) so you can change models and providers without rewriting tools or chat adapters.
Search across all documentation pages
Point a self-hosted personal agent at OpenRouter (or any OpenAI-compatible gateway) so you can change models and providers without rewriting tools or chat adapters.
Model ids, pricing, and provider slugs change. Verify at build time on OpenRouter's model and provider docs.
Configure one OpenAI-compatible client with base_url + API key, put MODEL_ID and optional routing prefs in env/config, route cheap models for triage and stronger models for hard scheduling, and log usage so an always-on host cannot silently burn budget.
MODEL_BASE_URL to https://openrouter.ai/api/v1 (verify at build) and keep tools unaware of the brand.extra_body.provider - verify fields at build).max_turns, and smaller max tokens for digests.import os
from openai import OpenAI
client = OpenAI(
base_url=os.environ.get("MODEL_BASE_URL", "https://openrouter.ai/api/v1"),
api_key=os.environ["MODEL_API_KEY"],
default_headers={
# Optional OpenRouter attribution headers - verify current names at build
"HTTP-Referer": os.environ.get("OR_REFERER", "https://localhost"),
"X-Title": os.environ.get("OR_TITLE", "personal-agent"),
},
)
MODELS = {
"default": os.environ.get("MODEL_ID", "openai/gpt-4o-mini"), # verify at build
"strong": os.environ.get("MODEL_ID_STRONG", "anthropic/claude-sonnet-4"), # verify
"cheap": os.environ.get("MODEL_ID_CHEAP", "google/gemini-2.5-flash"), # verify
}
def complete(
messages: list[dict],
*,
tier: str = "default",
tools: list | None = None,
provider: dict | None = None,
) -> object:
kwargs = {
"model": MODELS[tier],
"messages": messages,
}
if tools:
kwargs["tools"] = tools
if provider:
kwargs["extra_body"] = {"provider": provider}
return client.chat.completions.create(**kwargs)
# Digest wake: optimize for price/latency
resp = complete(
[{"role": "user", "content": "Label this email: ..."}],
tier="cheap",
provider={"sort": "price", "allow_fallbacks": True}, # verify support at build
)
# Scheduling wake: optimize for quality + tool fidelity
resp = complete(
messages,
tier="strong",
tools=tool_schemas,
provider={"require_parameters": True, "allow_fallbacks": True},
)Env sketch for the host:
MODEL_BASE_URL=https://openrouter.ai/api/v1
MODEL_API_KEY=sk-or-...
MODEL_ID=openai/gpt-4o-mini
MODEL_ID_CHEAP=google/gemini-2.5-flash
MODEL_ID_STRONG=anthropic/claude-sonnet-4
DAILY_TOKEN_BUDGET=500000Swap to a local server later without touching adapters:
MODEL_BASE_URL=http://127.0.0.1:11434/v1
MODEL_API_KEY=local
MODEL_ID=llama3.3A Clawdbot/OpenClaw-style host already isolates connectors from the brain.
The brain should also be swappable: new model quality, price shocks, outages, or privacy preferences should be config changes.
OpenRouter is one multi-model gateway with a unified API. Direct provider SDKs and local servers are valid alternatives behind the same client interface.
| Concern | Own it in the host | Leave to gateway/provider |
|---|---|---|
| Tool schemas | yes | - |
| Max turns / budgets | yes | - |
| Chat allowlists | yes | - |
| Model id selection | yes (policy) | routing among hosts for that model |
| Provider order / fallbacks | optional config | execution |
| Final billing | monitor | invoice |
Do not scatter raw provider SDKs inside every tool.
| Wake type | Typical tier | Notes |
|---|---|---|
| Morning digest classify | cheap | High volume, short outputs |
| Chat Q&A | default | Balanced |
| Multi-step schedule negotiation | strong | Tool fidelity matters |
| Embeddings / recall (if any) | embedding model | Separate client path |
| Shell planning (if enabled) | strong + approvals | Never price-optimize away judgment |
Keep the tier map in config versioned with the agent.
Self-hosting the runtime does not stop prompt content from reaching model providers.
When mail snippets leave your VPS:
MODEL_ID secondary.require_parameters: true (when supported) avoids silent tool stripping on weak endpoints.Always-on should not mean always-calling.
Charge tokens to wakes, not uptime.
Emit a daily spend summary to your private chat.
Hard-stop when DAILY_TOKEN_BUDGET is exceeded (except an explicit /override you rarely use).
| Approach | Pros | Cons |
|---|---|---|
| OpenRouter (or similar gateway) | One key, many models | Extra hop; policy review needed |
| Direct provider API | Simplest mental model | Painful multi-model ops |
| Multi-SDK failover you write | Full control | You own normalization |
| Fully local OpenAI-compatible server | Data locality | Hardware and quality limits |
| Provider BYOK through a gateway | Use existing cloud credits | More billing surfaces |
No. Use any OpenAI-compatible endpoint. OpenRouter is a convenient multi-model option, not a requirement of self-hosting.
No. Verify tool support per model id. Keep a known-good default for agent loops.
Use the gateway's provider preference object (for OpenRouter: order / only / ignore style fields - verify at build) or call the provider directly.
Yes. Choose base_url and model id per tier. Keep schemas identical so tools stay portable.
Optional referer/title style headers are commonly used for app attribution; confirm current docs at build and keep them in env.
When quality drops, price changes, or a provider incident hits. Treat ids as config, not code constants buried in functions.
No. Routing is orthogonal to tool allowlists and approvals.
Wake id, tier, model id, latency, token usage, tool names, and error codes - not raw secrets or full message bodies in long-term logs.
Some gateways let you bring provider keys. That can change cost and data paths; read the gateway's BYOK docs before enabling on a personal mail agent.
One stable tool-capable model id, price-sorted fallbacks if available, daily budget cap, no multi-tier complexity until digests are solid.
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.
Reviewed by Chris St. John·Last updated Jul 16, 2026