Skip to main content

Context window control

Keeping the prompt lean​

Context window control is how you decide what your agent re-reads on every turn. Parlant saves tool results to the conversation and replays them later, so a large result raises the cost of every reply that follows. You can make a result serve one reply and then disappear, or trim it to what the agent needs. Long sessions stay cheap.

What you'll learn
  • The three lifespans a tool result can have and when to choose each
  • What the size warnings mean and why to fix them
  • How to return only the fields the agent needs
  • What else lives in every prompt, and how to read the cost
Talk this page through with your coding agent

The purpose of context window control is to keep your agent's prompt focused on what the conversation currently needs, and to keep long sessions from growing more expensive with every turn.

Consider a large search result. It may help answer one question and add little to the rest of the conversation. But if it stays in the session's context, every later reply keeps paying to read it. Parlant lets you decide whether a tool result should serve one reply or remain available throughout the conversation.

This is what makes a tool result different from an ordinary return value: it's prompt material. An order history you explicitly keep for the session can be read again on later turns, even after the topic changes, until compaction summarizes it.

So this page is about three decisions: what stays in the conversation, what serves one reply and then disappears, and what never enters the prompt at all.

How long a result lives​

Let's start with the first decision. Unless you say otherwise, Parlant saves a tool result to the session as a tool event and replays it on later turns. The lifespan entry in the result's control decides how long it lives, and it takes one of three values:

import parlant.sdk as p


@p.tool
async def summarize_policy_document(topic: str) -> p.ToolResult:
return p.ToolResult(
data=await docs.render(topic),
control={"lifespan": "response"}, # serves this reply, then drops out of the session
)
ValueWhat happens
"response"The result serves the current reply and is not saved. It stays fully available for the rest of the turn, including later steps, so the agent can reason over it and call more tools. It doesn't come back on the next turn.
"session"The result is saved and replayed on later turns, so the agent still knows it without calling the tool again.
"auto"The default. Parlant estimates the result's size: over about 1,000 tokens it's treated as "response" and a warning is logged; smaller results are saved.

Reach for "response" when the result is large, or when it's only true right now: a rendered document, a search result set, today's queue. It's the answer to "my tool returns a lot of data." Your agent gets all of it for this turn's reasoning, and the conversation doesn't carry the weight afterwards.

Reach for "session" when the result is a small fact your agent should carry through the conversation, such as the account it just looked up.

Note that the default handles most tools well. Explicit values are for the cases where you know better than a size estimate.

The warnings, and why to treat them as real​

Once you've chosen a lifespan, Parlant checks whether the result actually fits it. The purpose of these warnings is to catch a heavy result before it quietly becomes a cost on every turn.

Parlant warns when a result looks too heavy for its lifespan: above 2,000 tokens for "response" and "auto", and above 1,000 for "session", where the cost repeats. A "session" warning also suggests the fix:

Tool local:fetch_report returned a session-lifespan result with 3,400 tokens.
Consider compacting it, or setting ToolResult(control={"lifespan": "response"})
to avoid excessive token accumulation throughout the session.

These warnings are the difference between a conversation that stays cheap and one whose prompt grows every turn. Treat them as bugs to fix, not noise to filter.

Return what the agent needs​

Now that you know when a result is too heavy, let's look at the most effective way to make it lighter. The cheapest token is one the tool never returns.

Most large results are raw payloads: a full API response where your agent needed three fields, or a whole record where it needed a status. Ask your coding agent to shape the result in the tool, before it reaches the model:

@p.tool
async def get_order(order_id: str) -> p.ToolResult:
order = await store.fetch_order(order_id)

return p.ToolResult(
data={
"status": order.status,
"eta": order.eta,
"items": [i.name for i in order.items],
},
)

What about data your frontend needs but the model doesn't? That belongs on metadata, which never enters the prompt. A receipt PDF's URL, an image, a chart payload: put them there, and the model reads only the sentence that says the receipt is ready.

Learn more about metadata

Rich output covers that channel.

The result size limit​

Beyond lifespans and warnings, there's also a hard boundary. A tool result travels to Parlant over HTTP, and Parlant caps one response at 16KB by default. A tool that returns more doesn't get truncated. It fails, with an error naming the limit:

url='http://localhost:8818/...', arguments='...', Response exceeds 16KB limit

Before raising the cap, try the fixes above: return fewer fields, use a narrower query, or store large files elsewhere and return their references. Note that metadata is part of the same HTTP payload, so moving the full data there won't avoid the size cap.

The difference matters. Those fixes make every turn cheaper; a bigger cap makes one tool work and every turn dearer.

Still, sometimes the data genuinely has to reach your agent whole, say, a long document it must quote from. In that case, raise the cap with an environment variable. Parlant reads it once at server startup:

export PARLANT_TOOL_RESULT_MAX_PAYLOAD_KB=64

Pair a result that large with a "response" lifespan, so that it serves the reply that needs it and doesn't repeat on every later turn.

Other things that live in every prompt​

Tool results aren't the only standing context in your agent's prompt. To see the whole picture, let's look at the other things that occupy it, and what keeps each one bounded.

Tool-backed variables​

Parlant refreshes tool-backed variables and renders them into every turn's prompt, and it warns when one exceeds about a thousand tokens. Keep them to the facts your agent needs on every turn, and use a tool the agent calls on demand for anything larger.

tip

Guests and customers covers variables.

Retrievers​

Retrievers are the one-reply alternative to a session-lifespan result. Parlant injects what a retriever returns for the current reply only and never writes it to the session. This means a knowledge-base lookup that runs on every turn costs its size once per turn, never cumulatively.

tip

Cross-session memory​

Cross-session memory is the other direction. Facts your agent should keep beyond this session live in a store of your own, and a retriever reads them back when relevant. So they never sit in the history at all.

tip

Compaction​

Compaction is the backstop for everything else. When the history grows past a threshold set by the turn's effort, Parlant summarizes the earlier part after the reply goes out. Later turns then read the summary plus what came after.

Note that compaction keeps a long session bounded, but a summary keeps less than the original. It's better to keep heavy results out of the history than to rely on compaction to remove them.

tip

Compacting long sessions covers the thresholds.

Reading the cost​

To bring it all together, how do you know whether your prompt is actually staying lean? Parlant exposes the numbers: GET /sessions/{id} returns a usage map keyed by trace id, with input, cached input, and output tokens for every turn. Within a turn, the counts are keyed by provider and model, such as anthropic:claude-sonnet-5-5.

Here's the pattern to look for. If input tokens climb turn over turn in a session that isn't getting longer in messages, Parlant is replaying a tool result.

The turn's diagnostic report shows the prompt that was actually sent.

Learn more

Debugging issues shows how to download it, and Spend management how to put a budget on it.