Pydantic AI Handoff: Pass Tasks and State Between Agents

Pydantic AI lets you delegate subtasks from one agent to another and pass the state each agent needs. Here is how to structure that delegation, verify completion, and keep a durable task record in fenbs that survives model or session changes.

Updated 6 min read

Pydantic AI supports multi-agent workflows where one agent delegates a subtask to another and receives a typed result. Getting that handoff right means passing enough state for the receiving agent to do the work, defining a clear completion contract, and verifying the result before the calling agent continues. For the durable task record that lives beyond any single run, tools like fenbs provide the where-we-left-off and context that let a resumed or replacement agent start from the right place.

The handoff problem in multi-agent systems is not just about passing data. It is about passing the right data: enough for the receiving agent to act correctly, without leaking private state or context it does not need. Pydantic AI's typed models make that boundary explicit, which is one reason the framework is useful for structured delegation.

How delegation works in Pydantic AI

In Pydantic AI, an agent can call another agent as a tool. The calling agent passes a structured input (a Pydantic model), the called agent processes it and returns a typed result, and the calling agent uses that result to decide its next step. Because the input and output are typed, schema mismatches fail at construction time rather than silently during processing.

The agent being called does not have access to the calling agent's full context by default. It only sees what is in the input model. That is a useful constraint: it forces you to be explicit about what the receiving agent actually needs, and it prevents the called agent from reading or modifying state it was not given.

Pydantic AI also supports a RunContext that can carry shared dependencies across an agent run — a database session, an HTTP client, or a configuration object. That context is separate from the task input and travels through the dependency injection system, not through the prompt.

Structuring the state to pass

Define the input to the receiving agent as a Pydantic model with only the fields that agent genuinely needs. If the research agent needs a question and a list of allowed sources, those are the two fields. Do not pass the entire parent context, user history, or session state. The receiving agent should be able to do its job correctly from the input alone.

Minimal input model for a delegated subtask
from pydantic import BaseModel

class ResearchInput(BaseModel):
    question: str
    allowed_sources: list[str]

class ResearchResult(BaseModel):
    answer: str
    sources_used: list[str]
    confidence: str  # "high", "medium", "low"

Include a confidence or status field in the result. "high", "medium", "low" is coarser than a float, but it is easier to act on programmatically. The calling agent can decide to proceed, retry with different parameters, or escalate to a human based on the confidence level without parsing free text.

If the receiving agent needs to indicate partial completion — it found some results but could not finish — model that explicitly. A partial: bool field or a status enum is clearer than an empty list of results that the calling agent would have to interpret.

Verifying completion

Do not trust the receiving agent's own report that the task is complete. Validate the result model against your expectations: are the required fields populated? Are the sources in the allowed list? Is the confidence level consistent with the number of sources used? Pydantic validation handles type and constraint checks; you still need business-logic checks.

For tasks that have external effects — writing to a database, sending a message, calling an API — verify the effect separately from the agent's return value. Check the database record, call a status endpoint, or read a confirmation that does not come from the same agent that performed the action.

How fenbs helps

Keep the durable task record outside the agent run

Pydantic AI runs are ephemeral: when a run ends, the context it built up is gone. fenbs keeps the task, its current state, and the where-we-left-off note that the next run — or a different agent — can read. Connect Claude Code or another supported assistant over MCP, and the agent reads the task context before each run instead of starting blind.

Create a free account

Free for one person · No credit card · Works with Claude, ChatGPT, Cursor and more

Handling partial completions and retries

When a receiving agent returns a partial result, the calling agent needs to decide: retry with the same input, retry with modified parameters, pass the partial result upstream anyway, or stop and ask for human input. Model those branches explicitly in your agent graph rather than leaving them implicit in the calling agent's reasoning.

Retries should pass different parameters when the first attempt returned low confidence. Passing identical input to the same agent model will likely produce similar low-confidence output. Change the question framing, narrow the source list, or delegate to a different agent with different capabilities.

How to do this with fenbs

Add the multi-agent task to a fenbs project before the first run. Update it after each run with what completed and what is next, so a resumed or replacement agent reads the current state rather than starting over.

  1. Create a free account. Add the project that owns this multi-agent workflow with a description of its goal and the agents involved.
  2. Add the task for the workflow. Describe the input, the expected output, and the completion criteria a person can verify.
  3. Write any rules that govern the agents in Decisions and rules: which sources are allowed, what confidence threshold triggers human review, which actions require approval.
  4. Connect a supported assistant at Integrations. Ask it to read the project context and task before each run so it starts with the current state.
  5. After each run, update the task in fenbs with what the agents completed, what partial results are available, and what the next step is. If a run fails, record what failed and why before retrying.

Questions people ask.

What is an agent handoff in Pydantic AI?

A handoff is when one agent delegates a subtask to another and receives a typed result back. The calling agent passes a structured input model, the called agent processes it, and returns a typed result the calling agent uses to decide its next action.

How do I pass context between agents in Pydantic AI?

Task-specific data goes in a Pydantic input model with only the fields the receiving agent needs. Shared dependencies like database sessions or HTTP clients go through the RunContext dependency injection system, keeping them separate from the task input.

How should I handle a partial result from a delegated agent?

Model the partial state explicitly in the result type with a status or confidence field. The calling agent then decides whether to retry, pass the partial result upstream, or stop for human review based on that field rather than parsing free text.

Why keep a task record in fenbs if the run has its own state?

A Pydantic AI run ends when the process stops. The task record in fenbs persists so a resumed run, a different agent, or a team member can see what completed, what is still open, and what the next step is without replaying the entire run history.

More in Agent harness (for developers)

All Agent harness (for developers) articles

Start with one thing.

Free for one person · No credit card · Works with Claude, ChatGPT, Cursor and more

There is nothing to set up first. Write one line and you’ve started.