Use Cases
- Chat assistants and copilots where consecutive turns share a long system prompt or tool set and benefit from the provider prompt cache.
- Agent loops that call the router several times per user turn and should not change models halfway through.
- Support conversations where the tone and level of detail should stay consistent from the first reply to the last.
Enable Session Affinity
In the UI
- Open the Smart Router in AI Gateway and edit it, or create a new one.
- Under Session affinity, turn on Pin conversations to one model.
- Set Pin for to the idle window: 1, 5, 10, 30, or 60 minutes. The default is 10 minutes.
- Click Save changes, or Create for a new router.
Through the API
Sendsession_affinity when creating or updating a Smart Router. ttl_seconds is the idle window in seconds, between 60 and 3600, and defaults to 600 when omitted. On update the object is replaced as a whole; omitting ttl_seconds resets the window to the default of 600.
POST /v2/smart-routers. See the Smart Routers API reference.
Seed the Pin
The pin is keyed on an id the caller sends. Nothing is derived from the message content.
When both are present the body wins over the header. A thread id and a conversation id with the same value produce two independent pins. See Request Metadata for the thread field and headers.
Quick Start
Call the Smart Router twice with the same thread id. The first turn is scored and returnsX-Orq-Session-Affinity: miss; the second turn reuses the pinned model and returns hit.
model field in the response names the concrete model on both turns.
How a Pin Is Decided
The first turn of a thread is scored and routed as usual. The pin is written only after that turn’s first provider call succeeds, so a failed or retried first turn never pins a model. A turn the scorer could not classify with confidence is served but not pinned; the next turn tries again. On a hit, the request goes straight to the pinned model with no scoring call on the request path, and the idle window is refreshed. Easy and Medium hits still trigger one background scoring call for escalation; Hard hits make none.Escalation
A thread that starts easy can turn hard. On every hit with an Easy or Medium pin, the router re-scores the turn in the background. When the new score ranks in a higher band, the pin moves up to that band’s model and stays there. A pin never moves down: a downgrade would reset the provider cache for a small saving. Hard pins are never re-scored. The escalation is a compare-and-set write that keeps the pin’s remaining lifetime, so two turns racing on one thread cannot move the decision backwards.Pin Lifetime
The idle window is sliding. Every hit refreshes it, so an active conversation keeps its model for as long as it stays active, and a thread that stays quiet longer than the window is routed fresh on its next turn. There is no absolute ceiling. A pin is dropped, and the request routed per request instead, when:- The pinned model fails on the first provider call of a turn.
- The pinned model is no longer in the router’s pool, or no longer callable in the workspace.
- The stored pin cannot be parsed.
Where It Applies
On the Responses and Messages endpoints, a turn that runs a tool loop settles the pin on its first provider call only. Sub-agents pin under their own router and their own key. Scheduled agent runs carry no thread or conversation id and are routed per request.
Observability
Every routed request records the decision on its span:
The escalation attributes are recorded on a separate
auto-router.escalation span in the same trace, because the re-score runs after the response is sent.
The metrics router.session_affinity.hits, router.session_affinity.misses, router.session_affinity.dissolves, and router.session_affinity.escalations count the same events per router. See Traces.
A pin holds a model name, a band, and a timestamp. No message content or user data is stored with it.