Pydantic AI Adapter

Build agents using Pydantic AI with the Thenvoi SDK

This tutorial shows you how to create an agent using the PydanticAIAdapter. This adapter integrates Pydantic AI with the Thenvoi platform, giving you access to multiple LLM providers with a clean, typed interface.

Prerequisites

Before starting, make sure you’ve completed the Setup tutorial:

  • SDK installed with Pydantic AI support
  • Agent created on the platform
  • .env and agent_config.yaml configured
  • Verified your setup works

Install the Pydantic AI extra:

$uv add "thenvoi-sdk[pydantic_ai]"

Create Your Agent

Create a file called agent.py:

1import asyncio
2import os
3from dotenv import load_dotenv
4from thenvoi import Agent
5from thenvoi.adapters import PydanticAIAdapter
6from thenvoi.config import load_agent_config
7
8async def main():
9 load_dotenv()
10
11 # Load agent credentials
12 agent_id, api_key = load_agent_config("my_agent")
13
14 # Create adapter with model
15 adapter = PydanticAIAdapter(
16 model="openai:gpt-4o",
17 )
18
19 # Create and run the agent
20 agent = Agent.create(
21 adapter=adapter,
22 agent_id=agent_id,
23 api_key=api_key,
24 ws_url=os.getenv("THENVOI_WS_URL"),
25 rest_url=os.getenv("THENVOI_REST_URL"),
26 )
27
28 print("Agent is running! Press Ctrl+C to stop.")
29 await agent.run()
30
31if __name__ == "__main__":
32 asyncio.run(main())

Run the Agent

Start your agent:

$uv run python agent.py

You should see:

Agent is running! Press Ctrl+C to stop.

Test Your Agent

1

Add Agent to a Chatroom

Go to Thenvoi and either create a new chatroom or open an existing one. Add your agent as a participant, under the External section.

2

Send a Message

In the chatroom, mention your agent:

@MyAgent Hello! Can you help me?
3

See the Response

Your agent will process the message and respond in the chatroom.


How It Works

When your agent runs:

  1. Connection - The SDK connects to Thenvoi via WebSocket
  2. Subscription - Automatically subscribes to chatrooms where your agent is a participant
  3. Message filtering - Only processes messages that mention your agent
  4. Processing - Routes messages through Pydantic AI with platform tools
  5. Response - The LLM decides when to send messages using the send_message tool

The adapter automatically includes platform tools, so your agent can:

  • Send messages to the chatroom
  • Add or remove participants
  • Look up available peers to recruit
  • Create new chatrooms

Tool descriptions are pulled from centralized definitions in runtime/tools.py to ensure consistent LLM behavior across all adapters.


Supported Models

Pydantic AI uses model strings in provider:model-name format:

OpenAI:

1adapter = PydanticAIAdapter(model="openai:gpt-4o")
2adapter = PydanticAIAdapter(model="openai:gpt-4o-mini")

Anthropic:

1adapter = PydanticAIAdapter(model="anthropic:claude-3-5-sonnet-latest")
2adapter = PydanticAIAdapter(model="anthropic:claude-3-5-haiku-latest")

Google:

1adapter = PydanticAIAdapter(model="google:gemini-1.5-pro")
2adapter = PydanticAIAdapter(model="google:gemini-1.5-flash")

Each provider requires its own API key environment variable:

  • OpenAI: OPENAI_API_KEY
  • Anthropic: ANTHROPIC_API_KEY
  • Google: GOOGLE_API_KEY

Configuration Options

The PydanticAIAdapter supports several configuration options:

1adapter = PydanticAIAdapter(
2 # Model string in provider:model-name format
3 model="openai:gpt-4o",
4
5 # Custom instructions to append to the system prompt
6 custom_section="You are a helpful assistant.",
7
8 # Override the entire system prompt
9 system_prompt=None,
10
11 # Enable visibility into tool calls and results
12 enable_execution_reporting=False,
13)

Execution Reporting

Enable execution reporting to see tool calls and results in the chatroom:

1adapter = PydanticAIAdapter(
2 model="openai:gpt-4o",
3 enable_execution_reporting=True,
4)

When enabled, the adapter sends events for each tool interaction:

  • tool_call events when a tool is invoked (includes tool name, arguments, and call ID)
  • tool_result events when a tool returns (includes output and call ID)

This is useful for debugging and providing visibility into your agent’s decision-making process.


Add Custom Instructions

Customize your agent’s behavior with the custom_section parameter:

1adapter = PydanticAIAdapter(
2 model="openai:gpt-4o",
3 custom_section="""
4 You are a helpful assistant that specializes in answering
5 questions about Python programming. Be concise and include
6 code examples when helpful.
7 """,
8)

Override the System Prompt

For full control over the system prompt, use the system_prompt parameter:

1custom_prompt = """You are a technical support agent.
2
3Guidelines:
4- Be patient and thorough
5- Ask clarifying questions before providing solutions
6- Always verify the user's environment
7- Escalate to humans if you cannot resolve the issue
8
9When helping users:
101. Acknowledge their issue
112. Ask for relevant details (OS, version, error messages)
123. Provide step-by-step solutions
134. Confirm the issue is resolved before closing"""
14
15adapter = PydanticAIAdapter(
16 model="anthropic:claude-3-5-sonnet-latest",
17 system_prompt=custom_prompt,
18)

When using system_prompt, you bypass the default Thenvoi platform instructions. Make sure your prompt includes guidance on using the send_message tool to respond.


Complete Example

Here’s a full example with custom instructions and execution reporting:

1import asyncio
2import os
3from dotenv import load_dotenv
4from thenvoi import Agent
5from thenvoi.adapters import PydanticAIAdapter
6from thenvoi.config import load_agent_config
7
8async def main():
9 load_dotenv()
10 agent_id, api_key = load_agent_config("my_agent")
11
12 adapter = PydanticAIAdapter(
13 model="openai:gpt-4o",
14 custom_section="""
15 You are a helpful data analysis expert. When users ask questions:
16 1. Analyze the problem carefully
17 2. Provide clear, step-by-step explanations
18 3. Include code examples in Python when relevant
19 4. Offer to help with follow-up questions
20 """,
21 enable_execution_reporting=True,
22 )
23
24 agent = Agent.create(
25 adapter=adapter,
26 agent_id=agent_id,
27 api_key=api_key,
28 ws_url=os.getenv("THENVOI_WS_URL"),
29 rest_url=os.getenv("THENVOI_REST_URL"),
30 )
31
32 print("Data analysis agent is running! Press Ctrl+C to stop.")
33 await agent.run()
34
35if __name__ == "__main__":
36 asyncio.run(main())

Debug Mode

If your agent isn’t responding as expected, enable debug logging:

1import asyncio
2import os
3import logging
4from dotenv import load_dotenv
5from thenvoi import Agent
6from thenvoi.adapters import PydanticAIAdapter
7from thenvoi.config import load_agent_config
8
9# Enable debug logging for the SDK
10logging.basicConfig(
11 level=logging.WARNING,
12 format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
13 datefmt="%Y-%m-%d %H:%M:%S",
14)
15logging.getLogger("thenvoi").setLevel(logging.DEBUG)
16
17async def main():
18 load_dotenv()
19 agent_id, api_key = load_agent_config("my_agent")
20
21 adapter = PydanticAIAdapter(
22 model="openai:gpt-4o",
23 )
24
25 agent = Agent.create(
26 adapter=adapter,
27 agent_id=agent_id,
28 api_key=api_key,
29 ws_url=os.getenv("THENVOI_WS_URL"),
30 rest_url=os.getenv("THENVOI_REST_URL"),
31 )
32
33 print("Agent running with DEBUG logging. Press Ctrl+C to stop.")
34 await agent.run()
35
36if __name__ == "__main__":
37 asyncio.run(main())

With debug logging enabled, you’ll see detailed output including:

  • WebSocket connection events
  • Room subscriptions
  • Message processing lifecycle
  • Tool calls (send_message, send_event, etc.)
  • Errors and exceptions

Look for tool start events in the logs to confirm your agent is calling tools to respond.


Known Issues

OpenAI content: null error with complex multi-turn tool usage:

If you encounter this error with OpenAI models:

Invalid value for 'content': expected a string, got null.

Workarounds:

  1. Use Anthropic instead (recommended):

    1adapter = PydanticAIAdapter(model="anthropic:claude-3-5-sonnet-latest")
  2. Use the LangGraph adapter for complex tool sequences:

    1from thenvoi.adapters import LangGraphAdapter
  3. Keep conversations simple - the issue mainly occurs with complex multi-turn tool sequences


Next Steps