Agent¶
The agent module provides FastroAgent, a wrapper around PydanticAI's Agent with automatic cost calculation, distributed tracing, and a consistent response format.
FastroAgent¶
fastroai.agent.FastroAgent
¶
AI agent with usage tracking, cost calculation, and tracing.
Wraps PydanticAI's Agent to provide: - Automatic cost calculation in microcents - Optional distributed tracing - Streaming and non-streaming modes - Consistent ChatResponse format - Structured output support via output_type
The agent is STATELESS regarding conversation history. Callers load history from their storage and pass it to run().
Examples:
# Basic usage (returns string)
agent = FastroAgent(
model="openai:gpt-4o",
system_prompt="You are helpful.",
)
response = await agent.run("Hello!")
print(response.content)
print(f"Cost: ${response.cost_dollars:.6f}")
# With structured output
from pydantic import BaseModel
class Answer(BaseModel):
value: int
explanation: str
agent = FastroAgent(
model="openai:gpt-4o",
output_type=Answer,
)
response = await agent.run("What is 2+2?")
print(response.output.value) # 4
# With conversation history (you load it)
history = await my_memory_service.load(user_id)
response = await agent.run("Continue", message_history=history)
await my_memory_service.save(user_id, "Continue", response.content)
# With tracing
from fastroai import SimpleTracer
tracer = SimpleTracer()
response = await agent.run("Hello", tracer=tracer)
# With custom deps for tools
response = await agent.run("Search for news", deps=MyDeps(api_key="..."))
# Streaming
async for chunk in agent.run_stream("Tell me a story"):
if chunk.is_final:
print(f"\nCost: ${chunk.usage_data.cost_dollars:.6f}")
else:
print(chunk.content, end="", flush=True)
agent
property
¶
Access the underlying PydanticAI agent.
Returns:
| Type | Description |
|---|---|
Agent[Any, OutputT]
|
The wrapped PydanticAI Agent instance. |
__init__(config=None, agent=None, output_type=None, toolsets=None, cost_calculator=None, **kwargs)
¶
Initialize FastroAgent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
AgentConfig | None
|
Agent configuration. If None, creates from kwargs. |
None
|
agent
|
Agent[Any, OutputT] | None
|
Pre-configured PydanticAI Agent (escape hatch). If provided, config is only used for cost calculation. |
None
|
output_type
|
type[OutputT] | None
|
Pydantic model for structured output. Defaults to str. |
None
|
toolsets
|
list[AbstractToolset] | None
|
Tool sets available to the agent. |
None
|
cost_calculator
|
CostCalculator | None
|
Cost calculator. Default uses standard pricing. |
None
|
**kwargs
|
Any
|
Passed to AgentConfig if config is None. Common: model, system_prompt, temperature, max_tokens. |
{}
|
Examples:
# Using config object
config = AgentConfig(model="gpt-4o", temperature=0.3)
agent = FastroAgent(config=config)
# Using kwargs (simpler)
agent = FastroAgent(model="gpt-4o", temperature=0.5)
# With structured output
agent = FastroAgent(model="gpt-4o", output_type=MyResponseModel)
# Custom pricing override (e.g., volume discount)
calc = CostCalculator(pricing_overrides={
"gpt-4o": {"input_per_mtok": 2.00, "output_per_mtok": 8.00}
})
agent = FastroAgent(cost_calculator=calc)
# Escape hatch: your own PydanticAI agent
from pydantic_ai import Agent
pydantic_agent = Agent(model="gpt-4o", output_type=MyType)
agent = FastroAgent(agent=pydantic_agent)
run(message, deps=None, message_history=None, model_settings=None, tracer=None, **kwargs)
async
¶
Execute a single agent interaction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
User message to send. |
required |
deps
|
DepsT | None
|
Dependencies passed to tools. Can be any type. |
None
|
message_history
|
list[ModelMessage] | None
|
Previous messages (you load these from your storage). |
None
|
model_settings
|
ModelSettings | None
|
Runtime model config overrides. |
None
|
tracer
|
Tracer | None
|
Tracer for distributed tracing. |
None
|
**kwargs
|
Any
|
Passed to PydanticAI Agent.run(). |
{}
|
Returns:
| Type | Description |
|---|---|
ChatResponse[OutputT]
|
ChatResponse with content, usage, cost, and trace_id. |
Examples:
# Simple usage
response = await agent.run("Hello!")
print(response.content)
print(f"Cost: ${response.cost_dollars:.6f}")
# With conversation history
history = await memory.load(user_id)
response = await agent.run("Continue", message_history=history)
await memory.save(user_id, "Continue", response.content)
# With tracing
tracer = SimpleTracer()
response = await agent.run("Hello", tracer=tracer)
print(f"Trace ID: {response.trace_id}")
run_stream(message, deps=None, message_history=None, model_settings=None, tracer=None, **kwargs)
async
¶
Execute a streaming agent interaction.
Yields StreamChunk objects as the response is generated. The final chunk has is_final=True and includes complete usage data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
User message to send. |
required |
deps
|
DepsT | None
|
Dependencies passed to tools. |
None
|
message_history
|
list[ModelMessage] | None
|
Previous messages. |
None
|
model_settings
|
ModelSettings | None
|
Runtime model config overrides. |
None
|
tracer
|
Tracer | None
|
Tracer for distributed tracing. |
None
|
**kwargs
|
Any
|
Passed to PydanticAI Agent.run_stream(). |
{}
|
Yields:
| Type | Description |
|---|---|
AsyncGenerator[StreamChunk[OutputT], None]
|
StreamChunk objects. Final chunk has usage_data. |
Examples:
as_step(prompt)
¶
Turn this agent into a pipeline step.
Creates a BaseStep that runs this agent with the given prompt and returns the agent's output directly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prompt
|
Callable[[StepContext[DepsT]], str] | str
|
Either a static string or a function that builds the prompt from the step context. |
required |
Returns:
| Type | Description |
|---|---|
AgentStepWrapper[DepsT, OutputT]
|
A BaseStep that can be used in a Pipeline. |
Examples:
# Static prompt
agent = FastroAgent(model="gpt-4o", system_prompt="Summarize text.")
step = agent.as_step("Summarize the document.")
# Dynamic prompt from context
agent = FastroAgent(model="gpt-4o", system_prompt="Summarize text.")
step = agent.as_step(lambda ctx: f"Summarize: {ctx.get_input('doc')}")
# With structured output
agent = FastroAgent(model="gpt-4o", output_type=Summary)
step = agent.as_step(lambda ctx: f"Summarize: {ctx.get_input('doc')}")
# step returns Summary directly
# Use in pipeline
pipeline = Pipeline(
name="summarizer",
steps={"summarize": step},
)
AgentConfig¶
fastroai.agent.AgentConfig
¶
Configuration for FastroAgent instances.
All parameters have sensible defaults. Override as needed.
Examples:
# Minimal - uses all defaults
config = AgentConfig()
# Custom configuration
config = AgentConfig(
model="anthropic:claude-3-5-sonnet",
system_prompt="You are a financial advisor.",
temperature=0.3,
)
# Use with agent
agent = FastroAgent(config=config)
# Or pass kwargs directly to FastroAgent
agent = FastroAgent(model="openai:gpt-4o-mini", temperature=0.5)
get_effective_system_prompt()
¶
Get system prompt, using default if not set.
Returns:
| Type | Description |
|---|---|
str
|
The configured system prompt or DEFAULT_SYSTEM_PROMPT. |
ChatResponse¶
fastroai.agent.ChatResponse
¶
Response from an AI agent interaction.
Contains the response content plus comprehensive usage metrics for billing, analytics, and debugging.
Examples:
response = await agent.run("What is 2+2?")
print(f"Answer: {response.content}")
print(f"Cost: ${response.cost_dollars:.6f}")
print(f"Tokens: {response.total_tokens}")
# Check cache effectiveness
if response.cache_read_tokens > 0:
cache_ratio = response.cache_read_tokens / response.input_tokens
print(f"Cache hit ratio: {cache_ratio:.1%}")
if response.tool_calls:
for call in response.tool_calls:
print(f"Used tool: {call['tool_name']}")
# With structured output
from pydantic import BaseModel
class Answer(BaseModel):
value: int
explanation: str
agent = FastroAgent(output_type=Answer)
response = await agent.run("What is 2+2?")
print(response.output.value) # 4
print(response.output.explanation) # "2 plus 2 equals 4"
Note
Why microcents? Floating-point math has precision errors (0.1 + 0.2 = 0.30000000000000004). With integers, precision is exact. For billing systems, this matters.
cost_dollars
property
¶
Cost in dollars for display purposes.
Returns:
| Type | Description |
|---|---|
float
|
Cost as a float in dollars. |
Note
Use cost_microcents for calculations to avoid floating-point errors.
StreamChunk¶
fastroai.agent.StreamChunk
¶
A chunk in a streaming response.
Most chunks have content with is_final=False. The last chunk has is_final=True with complete usage data.
Examples:
async for chunk in agent.run_stream("Tell me a story"):
if chunk.is_final:
print(f"\nTotal cost: ${chunk.usage_data.cost_dollars:.6f}")
else:
print(chunk.content, end="", flush=True)
AgentStepWrapper¶
fastroai.agent.AgentStepWrapper
¶
Pipeline step wrapper for FastroAgent.
Created via FastroAgent.as_step(). Wraps an agent as a pipeline step.
The wrapper uses ctx.run() for automatic tracer/deps forwarding and usage tracking, and returns the agent's typed output directly.
Note
Use FastroAgent.as_step() to create instances rather than instantiating directly.
agent
property
¶
Access the underlying FastroAgent.
Returns:
| Type | Description |
|---|---|
FastroAgent[OutputT]
|
The wrapped FastroAgent instance. |
__init__(agent, prompt)
¶
Initialize the step wrapper.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent
|
FastroAgent[OutputT]
|
The FastroAgent to wrap. |
required |
prompt
|
Callable[[StepContext[DepsT]], str] | str
|
Static string or function that builds the prompt from context. |
required |
execute(context)
async
¶
Execute the agent with the configured prompt.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
StepContext[DepsT]
|
Step execution context with inputs, deps, and config. |
required |
Returns:
| Type | Description |
|---|---|
OutputT
|
The agent's typed output. |