Auto model routing

sference/auto picks a model per session from the first user message — low, medium, or high tier — and keeps it for the session. Beta, org opt-in.

Auto model routing

Beta

Auto model routing is in beta and off by default. An organization admin turns it on per organization (console → Members → the Organization card → Auto model routing, or PATCH /control/v1/teams/me/organization {"auto_routing_enabled": true}). Until then the model is hidden from every listing and requests for it return 403.

sference/auto picks a model for you, once per session, based on how hard the first message looks. A small classifier reads the first user message and rates it low, medium, or high; that tier's model then serves every later turn of the session.

TierModelImages
lowdeepseek-ai/DeepSeek-V4.1-Flashyes
mediumzai-org/GLM-5.3no
highmoonshotai/Kimi-K3yes

Send it like any other model id on POST /v1/chat/completions, /v1/messages, or /v1/responses:

curl https://api.sference.com/v1/chat/completions \
  -H "Authorization: Bearer $SFERENCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"sference/auto","messages":[{"role":"user","content":"Refactor this module to use dependency injection."}]}'

What you get back

The response model is the routed model, never sference/auto — so cost display and logging work without changes. Every response also carries two headers:

HeaderExampleMeaning
x-sference-routed-modelmoonshotai/Kimi-K3The model that served the request
x-sference-route-tierhighThe tier it was routed to

You are billed at the routed model's rates. The classification call is not billed to you.

How a session is identified

The API is stateless and clients send no session id, so the router infers the session from how agent harnesses behave: they resend the whole conversation on every request. Turn 1 sends [system, user1]; turn 5 sends [system, user1, …, user5]. The start of the conversation is identical every time.

A session is therefore every request sharing the same team + endpoint + system prompt text + first user message text. The router hashes those four, looks the hash up, and either decides (first time) or reuses the stored tier. The decision expires after 1 hour idle, refreshed by every request in the session. Only the hash and tier are stored, never content.

Where this can surprise you

  • Weak openers. A session that starts with "hi", "continue", or /init is rated on that text, and the whole session stays on the low tier even if the real task arrives on turn 2. Start a session with the actual task.
  • System prompt drift. If your harness puts something that changes into the system prompt (a date, git status, tool list), the session key changes mid-conversation and the session is re-decided — possibly switching models and losing its prompt cache.
  • Compaction. /compact in Claude Code rewrites the first message, which produces a new decision. The cache is gone at that point anyway.
  • Subagents start their own message history, so each gets its own decision. Usually what you want: an exploration subagent can run on the cheap tier.

Limits

  • Three endpoints only. POST /v1/chat/completions, /v1/messages, and /v1/responses. Batches reject it at create with 400 — batch rows are not sessions.
  • No cross-tier failover. If the routed model is at capacity you get the normal 429/503 for that model. Silently changing tier mid-session would hide capacity problems and break the prompt cache.
  • Images never go to the medium tier, because GLM-5.3 has no vision. An image on a medium session re-routes it to the high tier once.
  • An org model allowlist still applies. If it excludes sference/auto, requests get 403; the router only routes to tiers the allowlist permits.