Pydantic Ai Dependency Injection

v1.0.0

Implement dependency injection in PydanticAI agents using RunContext and deps_type. Use when agents need database connections, API clients, user context, or...

0· 122·1 current·1 all-time
byKevin Anderson@anderskev
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
The name and description (dependency injection for PydanticAI) match the SKILL.md content—examples, types, and RunContext usage directly implement that feature. The skill does not request unrelated binaries, credentials, or config paths.
Instruction Scope
Instructions are limited to code patterns and examples for providing deps via RunContext, creating dataclass/Pydantic types, and testing overrides. The examples reference network calls (a weather API) only as illustrative usage; the document does not instruct reading arbitrary files, scanning system state, or exfiltrating data.
Install Mechanism
There is no install spec and no code files—this is instruction-only, so nothing is written to disk or downloaded as part of the skill.
Credentials
The skill declares no required environment variables or credentials. Examples show passing API keys or initialized clients into deps at runtime, which is appropriate for the pattern (and the docs even recommend passing initialized clients rather than raw credentials).
Persistence & Privilege
The skill does not request persistent presence (always:false) or modify system/other-skill configs. It uses normal autonomous-invocation defaults but does not request elevated privileges.
Assessment
This is a documentation-only skill that shows how to pass typed dependencies into PydanticAI agents. It's internally coherent, but pay attention to how you use it: avoid embedding long-lived secrets directly in example code, prefer initialized client objects or short-lived credentials, and scope/close connections per request as suggested. Also ensure your runtime environment and agent policies protect any secrets you place into deps, since the agent will receive those objects at runtime.

Like a lobster shell, security has layers — review code before you run it.

latestvk97f6vxp4e7ypn1p8adgm8ewqx838kgr
122downloads
0stars
1versions
Updated 1mo ago
v1.0.0
MIT-0

PydanticAI Dependency Injection

Core Pattern

Dependencies flow through RunContext:

from dataclasses import dataclass
from pydantic_ai import Agent, RunContext

@dataclass
class Deps:
    db: DatabaseConn
    api_client: HttpClient
    user_id: int

agent = Agent(
    'openai:gpt-4o',
    deps_type=Deps,  # Type for static analysis
)

@agent.tool
async def get_user_balance(ctx: RunContext[Deps]) -> float:
    """Get the current user's account balance."""
    return await ctx.deps.db.get_balance(ctx.deps.user_id)

# At runtime, provide deps
result = await agent.run(
    'What is my balance?',
    deps=Deps(db=db_conn, api_client=client, user_id=123)
)

Defining Dependencies

Use dataclasses or Pydantic models:

from dataclasses import dataclass
from pydantic import BaseModel

# Dataclass (recommended for simplicity)
@dataclass
class Deps:
    db: DatabaseConnection
    cache: CacheClient
    user_context: UserContext

# Pydantic model (if you need validation)
class Deps(BaseModel):
    api_key: str
    endpoint: str
    timeout: int = 30

Accessing Dependencies

In tools and instructions:

@agent.tool
async def query_database(ctx: RunContext[Deps], query: str) -> list[dict]:
    """Run a database query."""
    return await ctx.deps.db.execute(query)

@agent.instructions
async def add_user_context(ctx: RunContext[Deps]) -> str:
    user = await ctx.deps.db.get_user(ctx.deps.user_id)
    return f"User name: {user.name}, Role: {user.role}"

@agent.system_prompt
def add_permissions(ctx: RunContext[Deps]) -> str:
    return f"User has permissions: {ctx.deps.permissions}"

Type Safety

Full type checking with generics:

# Explicit agent type annotation
agent: Agent[Deps, OutputModel] = Agent(
    'openai:gpt-4o',
    deps_type=Deps,
    output_type=OutputModel,
)

# Now these are type-checked:
# - ctx.deps in tools is typed as Deps
# - result.output is typed as OutputModel
# - agent.run() requires deps: Deps

No Dependencies Pattern

When you don't need dependencies:

# Option 1: No deps_type (defaults to NoneType)
agent = Agent('openai:gpt-4o')
result = agent.run_sync('Hello')  # No deps needed

# Option 2: Explicit None for type checker
agent: Agent[None, str] = Agent('openai:gpt-4o')
result = agent.run_sync('Hello', deps=None)

# In tool_plain, no context access
@agent.tool_plain
def simple_calc(a: int, b: int) -> int:
    return a + b

Complete Example

from dataclasses import dataclass
from httpx import AsyncClient
from pydantic import BaseModel
from pydantic_ai import Agent, RunContext

@dataclass
class WeatherDeps:
    client: AsyncClient
    api_key: str

class WeatherReport(BaseModel):
    location: str
    temperature: float
    conditions: str

agent: Agent[WeatherDeps, WeatherReport] = Agent(
    'openai:gpt-4o',
    deps_type=WeatherDeps,
    output_type=WeatherReport,
    instructions='You are a weather assistant.',
)

@agent.tool
async def get_weather(
    ctx: RunContext[WeatherDeps],
    city: str
) -> dict:
    """Fetch weather data for a city."""
    response = await ctx.deps.client.get(
        f'https://api.weather.com/{city}',
        headers={'Authorization': ctx.deps.api_key}
    )
    return response.json()

async def main():
    async with AsyncClient() as client:
        deps = WeatherDeps(client=client, api_key='secret')
        result = await agent.run('Weather in London?', deps=deps)
        print(result.output.temperature)

Override for Testing

from pydantic_ai.models.test import TestModel

# Create mock dependencies
mock_deps = Deps(
    db=MockDatabase(),
    api_client=MockClient(),
    user_id=999
)

# Override model and deps for testing
with agent.override(model=TestModel(), deps=mock_deps):
    result = agent.run_sync('Test prompt')

Best Practices

  1. Keep deps immutable: Use frozen dataclasses or Pydantic models
  2. Pass connections, not credentials: Deps should hold initialized clients
  3. Type your agents: Use Agent[DepsType, OutputType] for full type safety
  4. Scope deps appropriately: Create deps at the start of a request, close after

Comments

Loading comments...