Ask a service-desk agent which of last week's P1 incidents are still open, and you have taken one turn. The model has not. Before the answer appears it has received at least two separate requests, and each one carried the whole conversation from the first word, because the model kept none of it between them.

Thesis: A turn is not a message but a loop of model calls: the model is stateless, so the instructions, the tool definitions and the full history are in its input on every call, whether your code resends the history or the provider stores it, and one turn from your side lasts as many calls as the model needs, ending only when a response says the turn is over.


This is the first chapter of The Agentic Lifecycle, a series that follows one request through an agent stage by stage: the turn, tokens, the context window, sampling, tool calls, the reasoning that travels with them, and what survives between turns. Each chapter carries one interactive piece; this one is a step-through of a single conversation.

Three Parties, Five Parts

Every agent conversation has three parties, and only two of them are visible in the chat window.

  • You, typing a message.
  • The model, which reads a request and writes a response. Nothing else.
  • The harness, the code that calls the model, runs the tools you define and decides whether to call it again. In The Agent Is a While Loop this is the while. Here it is the part that assembles each request. Some providers also run their own server-side tools, such as web search; a later chapter covers those.

The request the harness builds has five kinds of content, and they are written by different hands.

Part Written by In the model's input
System prompt the team that built the agent on every call
Tool definitions the team that built the agent on every call
User messages you on every call after you type them
Assistant messages, including tool requests the model, on earlier calls on every call after they are generated
Tool results the harness, from your systems on every call after the tool runs

Once a part enters the model's input, it is in the input again on every later call until something deliberately takes it out. In a chained API the instructions and tools are the exception: they stay only while your code keeps resending them. Vendors encode these parts differently. Anthropic's Messages API takes the system prompt and the tools as top-level fields, and its documentation says the API builds a system prompt from the tool definitions on each request. Tool results go back inside a user-role message as tool_result blocks. OpenAI's Responses API sends them as a function_call_output item instead. The shapes differ. The round trip does not.

Step Through One Conversation

The widget below follows one illustrative conversation with an IT service-desk agent that has a single tool, search_tickets. Step through it and watch the panel headed "what the model receives": it shows the contents of each request, with every part marked new or re-sent. The tickets are invented. The parts and their order follow Anthropic's Messages API, with the assistant's tool request and the tool result written out as plain text rather than exact JSON. The figures are characters of this example's text, counted as you go. They are not tokens. How text becomes tokens, and why the same text counts differently on different models, is the next chapter's subject. With JavaScript off, a table shows the same three requests, and request 3 with the tool result dropped.

Request What it carries Ends with Characters
1 system prompt, tool definitions, your question tool_use: run the search 480
2 all of request 1, the model's tool request, the tool result end_turn: the answer 878
3 all of request 2, the answer, your follow-up end_turn: "Network Ops" 1,040
3, tool result dropped system prompt, tool definitions, your question, the answer, your follow-up tool_use: run the same search again, so a fourth request follows 642

You typed two messages and read two answers. The model received three requests totalling 2,398 characters, and 57% of those characters had already been sent before. In the third answer the model names the ticket's owner without searching again. It seems to remember. It does not: the harness put the first search's raw result back into request 3. Leave that result out, as the toggle on the last step does, and the model has never seen it.


The Model Remembers Nothing

Anthropic's Messages API guide says the API "is stateless, which means that you always send the full conversational history." OpenAI's conversation-state guide opens from the same fact, that "each text generation request is independent and stateless."

OpenAI also offers server-side state. You can chain responses with previous_response_id, or keep a durable conversation object with the Conversations API, and your code stops resending the history. The history is still in the model's input, and still billed: the same guide says that even with previous_response_id, "all previous input tokens for responses in the chain are billed as input tokens." Nor does everything carry over. The API reference says a previous response's instructions "will not be carried over to the next response," and the function-calling guide says functions are "usually declared in the tools parameter of each API request." Who resends the history varies by API. That all of it is in the model's input on every call does not.

Three consequences follow, whichever side does the resending.

Cost and latency scale with the history, not with the new message. Request 3 above exists to deliver an 18-character question and carries 1,040 characters to do it. Every call pays for the system prompt and every tool definition again. Give the agent forty tools and let one turn take twelve calls, and those forty definitions are in the model's input twelve times before anyone sees an answer.

A tool result is not read once. The ticket data in request 2 rides along in every later call of the conversation. If a tool returns customer records or an employee's details, that data now sits in every subsequent request until the harness drops it. Data minimization for an agent is a question about what each tool returns, because whatever it returns is re-sent.

The transcript the model sees is whatever your code sends. The same Anthropic page notes that earlier turns "don't necessarily need to actually originate from Claude." Harnesses use that to trim, summarize or rewrite history, and that is often the right call. It also means the chat log a user sees is not the record of what the model was told. For an audit, the record is what the model received: the request payload when your code sends the history, or the stored chain or conversation when the provider keeps it.

A Turn Ends on a Stop Reason

If one message can mean several calls, something has to decide when the turn is over. It is a field in the response. Anthropic's stop-reason reference lists seven values. Three matter most for this loop: tool_use, "Claude is calling a tool"; end_turn, "Claude completed its response naturally"; and max_tokens, "The response reached your max_tokens limit."

So the harness's inner loop has three main branches. On tool_use, run the tool, append the result and call again; the turn is paused, not finished. On end_turn, show the answer. On max_tokens, you have a cut-off answer, and a harness that treats any reply as the end will show it as if it were complete. The other four still need a branch. pause_turn means a provider-run tool loop hit its iteration limit, and the reference's instruction is to "send the assistant content back to continue." stop_sequence means one of your stop strings fired. Neither refusal nor model_context_window_exceeded is a finished answer. On a refusal, read stop_details, then retry on a fallback model where policy allows. The reference says to treat a full context window "as truncated."

The model decides, through that field, when its own turn ends; it must not decide when the task ends. That is a different stop with a different owner; Loop on the Gap, Not the Try-Count covers that outer stop.

When the Abstraction Wins

The strongest objection is that this is plumbing. SDKs ship tool runners that run the loop for you; Anthropic's own tool-handling page says the manual handling it describes "is automatically managed by Tool Runner." Some APIs keep the conversation on the server, so your code stops resending the history. Prompt caching makes the repeated prefix cheap. Why should a builder think in requests at all?

For a prototype, a short chat or an agent with small tool results, they should not. Use the runner and spend the time on the task. It stops serving you when you need to debug, budget or audit, because each of those starts from what the model actually received.

Server-side state changes who stores the history, not what is in the model's input or what you are billed for, as OpenAI's own note above says. Caching changes the price, not the presence: Anthropic's prompt caching page prices cache reads at a tenth of the base input price, or less on some current models. The cached text is still in the model's input and still fills the context window on every call. Neither feature makes the model remember. Both make it cheaper to remind it.


What to Do Next

  • Log one full request, not the chat transcript. Take the largest request your agent sent yesterday and split it into the five parts above, and note which part is biggest.
  • Count calls per turn. Record stop_reason on every response. The ratio of model calls to user messages is your real unit of cost and latency, and it moves when someone adds a tool.
  • Find your heaviest tool result and ask how long it rides. If it carries records nobody needs after the next step, return less or have the harness drop it once it has been used.
  • Make the stop branches explicit. Loop on tool_use, continue on pause_turn, stop on end_turn or a stop_sequence you set, on a refusal read stop_details, then retry on a fallback model where policy allows, and treat max_tokens and a full context window as not done, never as a finished answer.
  • Decide what your audit record is. If compliance asks what the agent was told, the answer is what the model received: the request payload, or the stored chain if the provider keeps state. Keep it, with the same retention rules as the data inside it.

Related reading: The Agent Is a While Loop for the outer loop this chapter sits inside, What Compaction Actually Destroys for what to do when the re-sent history grows too long, and Your Tool Schemas Are the Bloat for the cost of the tool definitions that ride along on every call.