Chat traces¶
By default every delegation starts a subagent from nothing. A chat trace lets the next delegation continue where the last one stopped, so a follow-up does not have to restate the context.
from pydantic_ai import Agent
from subagents_pydantic_ai import SubAgentCapability, SubAgentConfig
agent = Agent(
"openai:gpt-4.1",
capabilities=[
SubAgentCapability(
default_model="openai:gpt-4.1",
subagents=[
SubAgentConfig(
name="analyst",
description="Analyses datasets",
instructions="You analyse datasets and explain your reasoning.",
),
],
)
],
)
result = await agent.run(
"Have the analyst look at Q3 revenue, then ask the same analyst "
"to compare it with Q2 without re-reading Q3."
)
What the model sees¶
Every result from a continuable delegation ends with the trace id:
Passing that id back continues the same conversation:
task(description="Now compare with Q2", subagent_type="analyst",
chat_trace_id="4f2c8a1e9b7d4c5eab3f")
Omitting it starts a fresh one. The tool description tells the model to continue intentionally -- a follow-up that genuinely builds on the previous answer, not every call to the same subagent.
The rules¶
A trace belongs to one subagent and one task at a time.
- Same subagent only. A trace records one agent's messages; replaying them into a different agent produces a conversation that agent never had. Continuing with the wrong subagent returns an error.
- One task at a time. A trace with a running task cannot be continued. Two
concurrent tasks would both save their history at the end, and the slower save
would silently discard the faster one's work. The error tells the model to wait
with
check_taskorwait_tasks. - Only successful runs are stored. A failed first run saves nothing, so its id
would resume an empty conversation. Neither the result text nor
check_taskadvertises a trace in that case. - One run only. A trace belongs to the run that started it, the same way a task
handle does. One toolset instance serves every run of its agent, and a trace
holds a whole subagent conversation, so a trace from another run reads exactly
like an unknown one — including while its task is still running, so the error
cannot be used to probe which ids exist. A trace created without a
run_idstays continuable by anyone.
Where history lives¶
Histories are kept in memory, bounded by an LRU:
from subagents_pydantic_ai import create_subagent_toolset
toolset = create_subagent_toolset(default_model="openai:gpt-4.1", max_chat_traces=100)
Reading a trace refreshes its recency, so a conversation the orchestrator keeps continuing is not evicted underneath it. Past the limit the least recently used trace is dropped, and continuing an evicted one returns an error telling the model to start a new conversation rather than silently starting one.
The store is readable from Python, keyed by (subagent_name, chat_trace_id):
for (subagent, trace_id), messages in toolset.message_history_store.items():
print(subagent, trace_id, len(messages))
In-process only
Traces live in the toolset instance. They do not survive a restart and are not
shared between workers. For a conversation that must outlive the process, keep
pydantic-ai's own message_history in your own store and pass it when you
construct the subagent.
One-shot specialists have no trace¶
delegate builds an ephemeral specialist that is never registered, so task
could not resolve it later. Handing out a trace id for it would promise a
continuation that cannot happen, so one-shot runs report no trace and store no
history -- which also stops them from consuming LRU slots that a continuable
conversation would use.
See Dynamic agents for the difference between create_agent
and delegate.
Background tasks¶
An async delegation reports its trace when the task starts, and check_task and
wait_tasks repeat it only once the task has completed -- a failed or still
running task has not saved this run's history yet, so advertising the id earlier
would invite the model to resume nothing.
Task started in background.
Task ID: a1b2c3d4
Subagent: analyst
Chat Trace ID: 4f2c8a1e9b7d4c5eab3f
Use check_task('a1b2c3d4') to check status.
Next steps¶
- Execution modes -- sync, background, and auto
- Observability --
chat_trace_idon the handle - Dynamic agents -- reusable versus one-shot specialists