a turn is one exchange: your message, the model's work, its answer. a step is one model call inside it. a turn with three tool calls takes several steps.
send the conversation, read the stream, run the tools the model called, send again. the turn ends when the model calls no tool and has nothing left to say. a hundred steps is the ceiling.
| part | contents | changes |
|---|---|---|
| instructions | the system prompt | never, byte for byte |
| history | every earlier message | only by appending |
| new message | environment, skills catalogue, extension lines, what you typed | every turn |
nothing volatile is in the system prompt. the date, the git branch and the skills catalogue ride in the per-turn message instead. a system prompt that varied would move the cached prefix, and every turn would pay full price for the whole conversation.
a provider charges less for a prefix it has seen. that is why history is only ever appended to, and why steering joins at a step boundary rather than being inserted earlier.
OpenAI and Google cache a prefix without being asked. Anthropic and Bedrock cache only what is marked, so glrs marks the second-to-last message: the newest point that will still be there next turn. the mark advances every turn, which extends the cached prefix rather than replacing it. on the first turn there is no second-to-last, so the only message is marked, and the second turn opens on a prefix the provider has already seen.
everything else reaches an OpenAI-compatible endpoint, and caches or does not
according to the model behind it. glrs sends no cache control there, because
there is none to send: prompt_cache_key is OpenAI's, and a Foundry deployment
answers Unrecognized request argument supplied rather than ignoring it. the
same is true of textVerbosity, which is how a request about verbosity came to
fail as though it were about reasoning.
what that leaves is the prefix itself, which is the part glrs controls. measured over two turns on one Foundry resource:
| model | reused on the second turn |
|---|---|
azure/gpt-5.6-sol |
2601 of 2982 |
azure-foundry/DeepSeek-V4-Flash |
3584 of 4100 |
azure-foundry/kimi-k2.6 |
nothing; that model does not cache |
a cold prefix reports nothing cached on its first outing. that is the cache being written, not a failure.
| joins | costs | |
|---|---|---|
| steering | the running turn, at its next step | the tokens of what was said |
| follow-up | its own turn, once the agent runs out of work | a new turn |
steering takes a modifier because it interrupts; a follow-up does not. steering that arrives too late to join becomes a follow-up, ahead of the ones already waiting.
three layers, innermost first:
the third exists because the first two cannot see a mid-response drop: fetch resolved long ago and the body is still being read.
re-sending is safe only while the attempt is unobservable, meaning no text, no reasoning and no tool call has been produced. once anything has, the failure surfaces instead of being retried.
the context cannot grow forever, so past a threshold the older part is replaced by a summary. the cut lands on a user message, because a tool result separated from the call it answers is an invalid request.
thresholds and what survives: sessions.