docs: replace all placeholder content with real documentation

MCP docs:
- quickstart.md - Installation, basic usage, transport modes
- configuration.md - CLI options, env vars, config files
- vscode.md - VS Code, Cursor, Windsurf integration

Agent SDK docs:
- agents.md - Creating and configuring agents
- running_agents.md - Runner, RunConfig, async/sync
- tools.md - Function tools, context, custom tools
- guardrails.md - Input/output validation
- handoffs.md - Agent delegation patterns
- streaming.md - Stream events and responses
- tracing.md - Observability and debugging
- context.md - Mutable run context
- config.md - RunConfig and ModelSettings
- results.md - RunResult, items, usage
- models.md - Providers and model selection
- multi_agent.md - Complex multi-agent patterns
This commit is contained in:
2026-01-05 18:37:11 -08:00
parent 7a5285e545
commit e8695ee79d
14 changed files with 2561 additions and 28 deletions
+170 -2
View File
@@ -1,2 +1,170 @@
# config
Documentation coming soon.
# Configuration
Configure agent behavior with `RunConfig` and `ModelSettings`.
## RunConfig
Global settings for an agent run:
```python
from agents import Runner, RunConfig, ModelSettings
config = RunConfig(
model="gpt-4o",
model_settings=ModelSettings(temperature=0.7),
max_turns=20,
)
result = await Runner.run(agent, "Hello!", run_config=config)
```
## RunConfig Options
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `model` | `str \| Model` | None | Override all agent models |
| `model_provider` | `ModelProvider` | OpenAI | Model provider |
| `model_settings` | `ModelSettings` | None | Global model settings |
| `max_turns` | `int` | 10 | Max conversation turns |
| `input_guardrails` | `list` | None | Global input guardrails |
| `output_guardrails` | `list` | None | Global output guardrails |
| `handoff_input_filter` | `HandoffInputFilter` | None | Global handoff filter |
| `tracing_disabled` | `bool` | False | Disable tracing |
## ModelSettings
Fine-tune model behavior:
```python
from agents import Agent, ModelSettings
settings = ModelSettings(
temperature=0.7,
top_p=0.9,
max_tokens=1000,
presence_penalty=0.0,
frequency_penalty=0.0,
)
agent = Agent(
name="creative",
instructions="Be creative.",
model_settings=settings,
)
```
## ModelSettings Options
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `temperature` | `float` | 1.0 | Randomness (0-2) |
| `top_p` | `float` | 1.0 | Nucleus sampling |
| `max_tokens` | `int` | None | Max output tokens |
| `presence_penalty` | `float` | 0.0 | Presence penalty |
| `frequency_penalty` | `float` | 0.0 | Frequency penalty |
| `stop` | `list[str]` | None | Stop sequences |
## Model Selection
### By String
```python
agent = Agent(name="gpt4", model="gpt-4o")
agent = Agent(name="claude", model="claude-3-5-sonnet-20241022")
```
### Override at Runtime
```python
config = RunConfig(model="gpt-4o-mini")
result = await Runner.run(agent, "Hello!", run_config=config)
```
## Model Providers
### OpenAI (default)
```python
from agents import OpenAIProvider
provider = OpenAIProvider(
api_key="sk-...",
base_url="https://api.openai.com/v1",
)
config = RunConfig(model_provider=provider)
```
### Hanzo Node
```python
from agents import create_hanzo_node_provider
provider = create_hanzo_node_provider(
api_key="your-hanzo-key",
base_url="https://api.hanzo.ai/v1",
)
config = RunConfig(model_provider=provider)
```
### Custom Provider
```python
from agents import ModelProvider, Model
class MyProvider(ModelProvider):
def get_model(self, model_name: str) -> Model:
return MyCustomModel(model_name)
```
## Environment Variables
| Variable | Description |
|----------|-------------|
| `OPENAI_API_KEY` | OpenAI API key |
| `ANTHROPIC_API_KEY` | Anthropic API key |
| `HANZO_API_KEY` | Hanzo API key |
## Default Model
Set a default model for all agents:
```python
import agents
# Set default
agents.set_default_model("gpt-4o")
# All agents use gpt-4o unless overridden
agent = Agent(name="default", instructions="...")
```
## Configuration Hierarchy
Settings are applied in order (later overrides earlier):
1. Default settings
2. Agent-level settings (`agent.model_settings`)
3. RunConfig settings (`config.model_settings`)
```python
# Agent settings
agent = Agent(
model_settings=ModelSettings(temperature=0.5),
)
# RunConfig overrides
config = RunConfig(
model_settings=ModelSettings(temperature=0.9),
)
# Result uses temperature=0.9
result = await Runner.run(agent, "Hello!", run_config=config)
```
## See Also
- [Agents](agents.md) - Agent configuration
- [Models](models.md) - Model details
- [Running Agents](running_agents.md) - Using RunConfig
+187 -2
View File
@@ -1,2 +1,187 @@
# context
Documentation coming soon.
# Context
The context is a mutable object passed throughout an agent run.
## Basic Context
```python
from dataclasses import dataclass
from agents import Agent, Runner
@dataclass
class MyContext:
user_id: str
session_id: str
request_count: int = 0
context = MyContext(user_id="123", session_id="abc")
result = await Runner.run(agent, "Hello!", context=context)
```
## Accessing Context in Tools
```python
from agents import function_tool, RunContextWrapper
@function_tool
def get_user_data(ctx: RunContextWrapper[MyContext]) -> str:
"""Get data for the current user."""
user_id = ctx.context.user_id
return f"Data for user {user_id}"
@function_tool
def increment_count(ctx: RunContextWrapper[MyContext]) -> str:
"""Increment request count."""
ctx.context.request_count += 1
return f"Count: {ctx.context.request_count}"
```
## Context in Instructions
Dynamic instructions based on context:
```python
from agents import Agent, RunContextWrapper
def dynamic_instructions(ctx: RunContextWrapper[MyContext], agent: Agent) -> str:
user = ctx.context.user_id
count = ctx.context.request_count
return f"""You are helping user {user}.
This is request #{count} in this session.
Be concise and helpful."""
agent = Agent(
name="contextual",
instructions=dynamic_instructions,
)
```
## Context in Guardrails
```python
from agents import input_guardrail, InputGuardrailResult, RunContextWrapper
@input_guardrail
async def check_permissions(
ctx: RunContextWrapper[MyContext],
agent,
input_text: str
) -> InputGuardrailResult:
"""Check user permissions."""
if ctx.context.user_id not in allowed_users:
return InputGuardrailResult(
tripwire_triggered=True,
output_info="User not authorized."
)
return InputGuardrailResult(tripwire_triggered=False)
```
## Context in Handoffs
```python
from agents import handoff, Handoff, RunContextWrapper
@handoff
def conditional_handoff(ctx: RunContextWrapper[MyContext]) -> Handoff | None:
"""Hand off based on context."""
if ctx.context.user_id.startswith("vip_"):
return Handoff(target=vip_agent)
return None
```
## RunContextWrapper
The wrapper provides additional functionality:
```python
from agents import RunContextWrapper
@function_tool
def example(ctx: RunContextWrapper[MyContext]) -> str:
# Access your context
user = ctx.context.user_id
# Access run metadata
run_id = ctx.run_id
# Check current agent
agent_name = ctx.current_agent.name
return f"User: {user}, Run: {run_id}, Agent: {agent_name}"
```
## Context Types
### Dataclass (Recommended)
```python
from dataclasses import dataclass, field
@dataclass
class AppContext:
user_id: str
permissions: list[str] = field(default_factory=list)
metadata: dict = field(default_factory=dict)
```
### Pydantic Model
```python
from pydantic import BaseModel
class AppContext(BaseModel):
user_id: str
permissions: list[str] = []
class Config:
extra = "allow" # Allow additional fields
```
### Simple Dict
```python
# Works but not type-safe
context = {"user_id": "123", "data": {}}
result = await Runner.run(agent, "Hello!", context=context)
```
## Context Mutation
Context can be modified during the run:
```python
@function_tool
def update_context(ctx: RunContextWrapper[MyContext], key: str, value: str) -> str:
"""Update context metadata."""
ctx.context.metadata[key] = value
return f"Updated {key}"
```
## Context Persistence
For multi-turn conversations:
```python
# Store context between requests
contexts: dict[str, MyContext] = {}
async def handle_message(session_id: str, message: str):
# Get or create context
if session_id not in contexts:
contexts[session_id] = MyContext(
user_id="user_123",
session_id=session_id,
)
context = contexts[session_id]
result = await Runner.run(agent, message, context=context)
# Context is updated in place
return result.final_output
```
## See Also
- [Tools](tools.md) - Using context in tools
- [Guardrails](guardrails.md) - Context in guardrails
- [Running Agents](running_agents.md) - Passing context
+185 -2
View File
@@ -1,2 +1,185 @@
# guardrails
Documentation coming soon.
# Guardrails
Guardrails validate agent inputs and outputs to ensure safety and quality.
## Input Guardrails
Validate user input before the agent processes it:
```python
from agents import Agent, input_guardrail, InputGuardrailResult
@input_guardrail
async def check_input_length(ctx, agent, input_text: str) -> InputGuardrailResult:
"""Reject inputs that are too long."""
if len(input_text) > 10000:
return InputGuardrailResult(
tripwire_triggered=True,
output_info="Input too long. Please shorten your message."
)
return InputGuardrailResult(tripwire_triggered=False)
agent = Agent(
name="guarded",
instructions="Be helpful.",
input_guardrails=[check_input_length],
)
```
## Output Guardrails
Validate agent output before returning to user:
```python
from agents import Agent, output_guardrail, OutputGuardrailResult
@output_guardrail
async def check_pii(ctx, agent, output: str) -> OutputGuardrailResult:
"""Block outputs containing PII."""
pii_patterns = ["SSN:", "credit card:", "password:"]
for pattern in pii_patterns:
if pattern.lower() in output.lower():
return OutputGuardrailResult(
tripwire_triggered=True,
output_info="Response contained sensitive information."
)
return OutputGuardrailResult(tripwire_triggered=False)
agent = Agent(
name="safe_agent",
instructions="Help users with their accounts.",
output_guardrails=[check_pii],
)
```
## Guardrail Results
### Input Guardrail Result
```python
@dataclass
class InputGuardrailResult:
tripwire_triggered: bool # True to block
output_info: str | None = None # Reason for blocking
```
### Output Guardrail Result
```python
@dataclass
class OutputGuardrailResult:
tripwire_triggered: bool # True to block
output_info: str | None = None # Reason for blocking
```
## Guardrail with Context
```python
from dataclasses import dataclass
from agents import input_guardrail, InputGuardrailResult, RunContextWrapper
@dataclass
class AppContext:
user_tier: str
rate_limit: int
@input_guardrail
async def rate_limit_check(
ctx: RunContextWrapper[AppContext],
agent,
input_text: str
) -> InputGuardrailResult:
"""Check rate limits based on user tier."""
if ctx.context.user_tier == "free" and ctx.context.rate_limit <= 0:
return InputGuardrailResult(
tripwire_triggered=True,
output_info="Rate limit exceeded. Please upgrade."
)
return InputGuardrailResult(tripwire_triggered=False)
```
## LLM-Based Guardrails
Use another LLM to check content:
```python
from agents import input_guardrail, InputGuardrailResult, Agent, Runner
moderation_agent = Agent(
name="moderator",
instructions="Return 'SAFE' or 'UNSAFE: reason' for the given text.",
)
@input_guardrail
async def llm_moderation(ctx, agent, input_text: str) -> InputGuardrailResult:
"""Use an LLM to moderate content."""
result = await Runner.run(moderation_agent, input_text)
if result.final_output.startswith("UNSAFE"):
return InputGuardrailResult(
tripwire_triggered=True,
output_info=result.final_output
)
return InputGuardrailResult(tripwire_triggered=False)
```
## Global Guardrails
Apply guardrails to all runs:
```python
from agents import Runner, RunConfig
config = RunConfig(
input_guardrails=[check_input_length, rate_limit_check],
output_guardrails=[check_pii],
)
result = await Runner.run(agent, user_input, run_config=config)
```
## Handling Tripwires
```python
from agents import (
Runner,
InputGuardrailTripwireTriggered,
OutputGuardrailTripwireTriggered,
)
try:
result = await Runner.run(agent, user_input)
except InputGuardrailTripwireTriggered as e:
print(f"Input blocked: {e.guardrail_result.output_info}")
except OutputGuardrailTripwireTriggered as e:
print(f"Output blocked: {e.guardrail_result.output_info}")
```
## Multiple Guardrails
Guardrails run in order. First tripwire stops execution:
```python
agent = Agent(
name="multi_guard",
instructions="...",
input_guardrails=[
check_length, # Runs first
check_language, # Runs second
check_content, # Runs third
],
output_guardrails=[
check_pii,
check_formatting,
],
)
```
## See Also
- [Agents](agents.md) - Creating agents
- [Running Agents](running_agents.md) - Execution
- [Tracing](tracing.md) - Debug guardrails
+155 -2
View File
@@ -1,2 +1,155 @@
# handoffs
Documentation coming soon.
# Handoffs
Handoffs allow agents to delegate tasks to specialized sub-agents.
## Basic Handoffs
```python
from agents import Agent
# Specialist agents
billing_agent = Agent(
name="billing",
instructions="Handle billing inquiries, refunds, and payments.",
handoff_description="Handles billing, payments, and refunds.",
)
tech_agent = Agent(
name="tech_support",
instructions="Help with technical issues and troubleshooting.",
handoff_description="Handles technical support and troubleshooting.",
)
# Main agent with handoffs
main_agent = Agent(
name="support",
instructions="Route customers to the appropriate specialist.",
handoffs=[billing_agent, tech_agent],
)
```
## Handoff Decorator
For more control over handoff behavior:
```python
from agents import Agent, handoff, Handoff
@handoff
def to_billing(context) -> Handoff:
"""Transfer to billing specialist."""
return Handoff(
target=billing_agent,
input_filter=lambda items: items[-5:], # Last 5 messages
)
main_agent = Agent(
name="support",
instructions="Route to specialists as needed.",
handoffs=[to_billing],
)
```
## Handoff Input Filter
Control what conversation history transfers:
```python
from agents import Handoff, HandoffInputFilter
def last_n_messages(n: int) -> HandoffInputFilter:
"""Only send last N messages to new agent."""
def filter_fn(items):
return items[-n:]
return filter_fn
billing_handoff = Handoff(
target=billing_agent,
input_filter=last_n_messages(3),
)
```
## Conditional Handoffs
```python
from agents import Agent, handoff, Handoff, RunContextWrapper
@handoff
def smart_handoff(ctx: RunContextWrapper) -> Handoff | None:
"""Conditionally hand off based on context."""
if ctx.context.get("is_vip"):
return Handoff(target=vip_agent)
elif ctx.context.get("issue_type") == "billing":
return Handoff(target=billing_agent)
return None # No handoff
```
## Handoff Data
Pass data to the new agent:
```python
from agents import Handoff, HandoffInputData
handoff = Handoff(
target=specialist_agent,
input_data=HandoffInputData(
summary="Customer needs help with order #12345",
metadata={"order_id": "12345", "priority": "high"},
),
)
```
## Tracking Handoffs
```python
from agents import Runner, RunHooks
class HandoffTracker(RunHooks):
async def on_handoff(self, context, from_agent, to_agent):
print(f"Handoff: {from_agent.name} -> {to_agent.name}")
result = await Runner.run(
main_agent,
"I need help with my bill",
run_hooks=HandoffTracker(),
)
# Check which agent completed the run
print(f"Handled by: {result.last_agent.name}")
```
## Recursive Handoffs
Agents can hand off to agents that also have handoffs:
```python
level1 = Agent(name="level1", handoffs=[level2])
level2 = Agent(name="level2", handoffs=[level3])
level3 = Agent(name="level3", instructions="Final handler")
```
## Preventing Infinite Loops
Use `max_turns` to prevent circular handoffs:
```python
from agents import Runner, RunConfig
config = RunConfig(max_turns=10)
result = await Runner.run(agent, input_text, run_config=config)
```
## Handoff vs Tools
| Feature | Handoffs | Tools |
|---------|----------|-------|
| Control flow | Transfers to new agent | Returns to same agent |
| Context | New agent takes over | Same agent continues |
| Use case | Specialization | Actions/data retrieval |
## See Also
- [Agents](agents.md) - Creating agents
- [Multi-Agent](multi_agent.md) - Complex workflows
- [Running Agents](running_agents.md) - Execution
+203 -2
View File
@@ -1,2 +1,203 @@
# models
Documentation coming soon.
# Models
Configure and use different LLM providers.
## Supported Models
### OpenAI
```python
from agents import Agent
# GPT-4o (recommended)
agent = Agent(name="gpt4", model="gpt-4o")
# GPT-4o mini (faster, cheaper)
agent = Agent(name="mini", model="gpt-4o-mini")
# GPT-4 Turbo
agent = Agent(name="turbo", model="gpt-4-turbo")
```
### Anthropic (via Hanzo)
```python
agent = Agent(name="claude", model="claude-3-5-sonnet-20241022")
agent = Agent(name="opus", model="claude-3-opus-20240229")
```
### Other Providers
```python
# Gemini
agent = Agent(name="gemini", model="gemini-pro")
# Mistral
agent = Agent(name="mistral", model="mistral-large")
```
## Model Providers
### OpenAI Provider (default)
```python
from agents import OpenAIProvider, RunConfig
provider = OpenAIProvider(
api_key="sk-...", # Or use OPENAI_API_KEY env var
)
config = RunConfig(model_provider=provider)
```
### Hanzo Node Provider
```python
from agents import create_hanzo_node_provider, RunConfig
provider = create_hanzo_node_provider(
api_key="your-key", # Or use HANZO_API_KEY env var
)
config = RunConfig(model_provider=provider)
result = await Runner.run(agent, "Hello!", run_config=config)
```
### Custom Base URL
```python
from agents import OpenAIProvider
# Use Azure OpenAI
provider = OpenAIProvider(
api_key="azure-key",
base_url="https://your-resource.openai.azure.com/",
)
# Use local model (Ollama, vLLM, etc.)
provider = OpenAIProvider(
api_key="not-needed",
base_url="http://localhost:11434/v1",
)
```
## Custom Model Implementation
```python
from agents import Model, ModelProvider
class MyModel(Model):
async def complete(
self,
messages: list[dict],
tools: list[dict] | None = None,
**kwargs,
) -> dict:
# Your implementation
response = await my_api_call(messages, tools)
return {
"content": response.text,
"tool_calls": response.tool_calls,
}
class MyProvider(ModelProvider):
def get_model(self, model_name: str) -> Model:
return MyModel(model_name)
```
## Model Settings
```python
from agents import Agent, ModelSettings
agent = Agent(
name="creative",
model="gpt-4o",
model_settings=ModelSettings(
temperature=0.9, # More creative
top_p=0.95,
max_tokens=2000,
presence_penalty=0.1,
frequency_penalty=0.1,
),
)
agent = Agent(
name="precise",
model="gpt-4o",
model_settings=ModelSettings(
temperature=0.1, # More deterministic
max_tokens=500,
),
)
```
## Model Tracing
Enable detailed model tracing:
```python
from agents import ModelTracing
class TracedModel(Model):
tracing: ModelTracing = ModelTracing.ENABLED
async def complete(self, messages, tools=None, **kwargs):
# Automatically traced
...
```
## Response Models
### Chat Completions
Standard OpenAI-compatible response:
```python
from agents import OpenAIChatCompletionsModel
model = OpenAIChatCompletionsModel("gpt-4o")
```
### Responses API
For models supporting the newer responses format:
```python
from agents import OpenAIResponsesModel
model = OpenAIResponsesModel("gpt-4o")
```
## Model Selection Strategy
```python
from agents import Agent, RunConfig
# Development: faster, cheaper
dev_config = RunConfig(model="gpt-4o-mini")
# Production: best quality
prod_config = RunConfig(model="gpt-4o")
# Use based on environment
import os
config = prod_config if os.environ.get("ENV") == "prod" else dev_config
result = await Runner.run(agent, "Hello!", run_config=config)
```
## Environment Variables
| Variable | Description |
|----------|-------------|
| `OPENAI_API_KEY` | OpenAI API key |
| `OPENAI_BASE_URL` | Custom OpenAI-compatible endpoint |
| `ANTHROPIC_API_KEY` | Anthropic API key |
| `HANZO_API_KEY` | Hanzo API key |
## See Also
- [Configuration](config.md) - Model settings
- [Agents](agents.md) - Using models with agents
- [Running Agents](running_agents.md) - Runtime model selection
+227 -2
View File
@@ -1,2 +1,227 @@
# multi agent
Documentation coming soon.
# Multi-Agent Systems
Build complex workflows with multiple cooperating agents.
## Agent Teams
Create specialized agents that work together:
```python
from agents import Agent
# Specialist agents
researcher = Agent(
name="researcher",
instructions="Research topics thoroughly and provide facts.",
handoff_description="Researches information and facts.",
)
writer = Agent(
name="writer",
instructions="Write clear, engaging content based on research.",
handoff_description="Writes content and articles.",
)
editor = Agent(
name="editor",
instructions="Review and improve written content.",
handoff_description="Edits and improves content quality.",
)
# Coordinator
coordinator = Agent(
name="coordinator",
instructions="""Coordinate the team to produce quality content.
1. Use researcher for facts
2. Use writer to draft content
3. Use editor to polish""",
handoffs=[researcher, writer, editor],
)
```
## Sequential Workflow
Agents pass work in sequence:
```python
from agents import Agent, handoff, Handoff
@handoff
def to_next_stage(ctx) -> Handoff:
"""Move to the next processing stage."""
stages = ctx.context.get("stages", [])
current = ctx.context.get("current_stage", 0)
if current < len(stages):
ctx.context["current_stage"] = current + 1
return Handoff(target=stages[current])
return None
stage1 = Agent(name="stage1", handoffs=[to_next_stage])
stage2 = Agent(name="stage2", handoffs=[to_next_stage])
stage3 = Agent(name="stage3", instructions="Final stage.")
```
## Parallel Execution
Run multiple agents simultaneously:
```python
import asyncio
from agents import Agent, Runner
agents = [
Agent(name="analyst1", instructions="Analyze from perspective A"),
Agent(name="analyst2", instructions="Analyze from perspective B"),
Agent(name="analyst3", instructions="Analyze from perspective C"),
]
async def parallel_analysis(prompt: str):
tasks = [Runner.run(agent, prompt) for agent in agents]
results = await asyncio.gather(*tasks)
return [r.final_output for r in results]
# Combine results
outputs = await parallel_analysis("Analyze this data")
```
## Supervisor Pattern
One agent oversees others:
```python
from agents import Agent, function_tool, Runner
workers = {
"data": Agent(name="data_worker", instructions="Process data."),
"analysis": Agent(name="analysis_worker", instructions="Analyze results."),
}
@function_tool
async def delegate(task_type: str, task: str) -> str:
"""Delegate a task to a worker agent."""
if task_type not in workers:
return f"Unknown worker type: {task_type}"
result = await Runner.run(workers[task_type], task)
return result.final_output
supervisor = Agent(
name="supervisor",
instructions="Coordinate workers to complete complex tasks.",
tools=[delegate],
)
```
## Debate Pattern
Agents discuss and reach consensus:
```python
from agents import Agent, Runner
pro_agent = Agent(
name="pro",
instructions="Argue in favor of the proposition.",
)
con_agent = Agent(
name="con",
instructions="Argue against the proposition.",
)
judge_agent = Agent(
name="judge",
instructions="Evaluate arguments and reach a conclusion.",
)
async def debate(topic: str, rounds: int = 3):
history = [f"Topic: {topic}"]
for _ in range(rounds):
# Pro argument
pro_result = await Runner.run(pro_agent, "\n".join(history))
history.append(f"Pro: {pro_result.final_output}")
# Con argument
con_result = await Runner.run(con_agent, "\n".join(history))
history.append(f"Con: {con_result.final_output}")
# Final judgment
verdict = await Runner.run(judge_agent, "\n".join(history))
return verdict.final_output
```
## Router Pattern
Route requests to appropriate specialists:
```python
from agents import Agent
specialists = {
"billing": Agent(name="billing", instructions="Handle billing."),
"technical": Agent(name="technical", instructions="Handle tech issues."),
"sales": Agent(name="sales", instructions="Handle sales inquiries."),
}
router = Agent(
name="router",
instructions="""Route customer requests to the right specialist:
- Billing questions → billing
- Technical issues → technical
- Purchase inquiries → sales""",
handoffs=list(specialists.values()),
)
```
## Shared Context
Agents share state through context:
```python
from dataclasses import dataclass, field
from agents import Agent, Runner, function_tool
@dataclass
class SharedState:
findings: list[str] = field(default_factory=list)
decisions: list[str] = field(default_factory=list)
@function_tool
def add_finding(ctx, finding: str) -> str:
"""Add a finding to shared state."""
ctx.context.findings.append(finding)
return f"Added finding: {finding}"
@function_tool
def add_decision(ctx, decision: str) -> str:
"""Record a decision."""
ctx.context.decisions.append(decision)
return f"Recorded: {decision}"
state = SharedState()
result = await Runner.run(coordinator, "Analyze and decide", context=state)
print(f"Findings: {state.findings}")
print(f"Decisions: {state.decisions}")
```
## Error Recovery
Handle agent failures:
```python
from agents import Runner, AgentsException
async def run_with_fallback(primary: Agent, fallback: Agent, prompt: str):
try:
return await Runner.run(primary, prompt)
except AgentsException:
return await Runner.run(fallback, prompt)
```
## See Also
- [Agents](agents.md) - Creating agents
- [Handoffs](handoffs.md) - Agent delegation
- [Context](context.md) - Shared state
+183 -2
View File
@@ -1,2 +1,183 @@
# results
Documentation coming soon.
# Results
Understanding and working with agent run results.
## RunResult
The result of a completed agent run:
```python
from agents import Agent, Runner
agent = Agent(name="assistant", instructions="Be helpful.")
result = await Runner.run(agent, "Hello!")
# Access the result
print(result.final_output) # Final text output
print(result.last_agent) # Agent that produced output
print(result.new_items) # All conversation items
print(result.usage) # Token usage
```
## RunResult Properties
| Property | Type | Description |
|----------|------|-------------|
| `final_output` | `str` | Final text response |
| `last_agent` | `Agent` | Agent that completed the run |
| `new_items` | `list[RunItem]` | All items from the run |
| `usage` | `Usage` | Token usage statistics |
| `input_guardrail_results` | `list` | Input guardrail results |
| `output_guardrail_results` | `list` | Output guardrail results |
## Conversation Items
Access all items from the conversation:
```python
from agents.items import (
MessageOutputItem,
ToolCallItem,
ToolCallOutputItem,
HandoffCallItem,
)
for item in result.new_items:
match item:
case MessageOutputItem(content=content):
print(f"Message: {content}")
case ToolCallItem(tool_name=name, arguments=args):
print(f"Tool call: {name}({args})")
case ToolCallOutputItem(output=output):
print(f"Tool result: {output}")
case HandoffCallItem(target_agent=agent):
print(f"Handoff to: {agent.name}")
```
## Token Usage
```python
usage = result.usage
print(f"Input tokens: {usage.input_tokens}")
print(f"Output tokens: {usage.output_tokens}")
print(f"Total tokens: {usage.total_tokens}")
```
## Structured Output
When using output schemas:
```python
from pydantic import BaseModel
from agents import Agent, Runner
class Response(BaseModel):
answer: str
confidence: float
agent = Agent(
name="structured",
instructions="Always provide confidence.",
output_type=Response,
)
result = await Runner.run(agent, "What is 2+2?")
# Parsed output
response: Response = result.final_output_parsed
print(response.answer) # "4"
print(response.confidence) # 0.99
```
## Guardrail Results
```python
# Input guardrail results
for gr in result.input_guardrail_results:
print(f"Guardrail: {gr.guardrail_name}")
print(f"Triggered: {gr.tripwire_triggered}")
print(f"Info: {gr.output_info}")
# Output guardrail results
for gr in result.output_guardrail_results:
print(f"Guardrail: {gr.guardrail_name}")
print(f"Triggered: {gr.tripwire_triggered}")
```
## Streaming Results
For streaming runs:
```python
from agents import Runner
stream = Runner.run_streamed(agent, "Hello!")
# Collect events
async for event in stream:
print(event)
# Get final result
result = stream.result
print(result.final_output)
```
## Multi-Agent Results
When handoffs occur:
```python
result = await Runner.run(main_agent, "Help with billing")
# Which agent finished?
print(f"Completed by: {result.last_agent.name}")
# Trace the path
agents_involved = set()
for item in result.new_items:
if hasattr(item, "agent"):
agents_involved.add(item.agent.name)
print(f"Agents involved: {agents_involved}")
```
## Error Results
Handle errors gracefully:
```python
from agents import Runner, MaxTurnsExceeded
try:
result = await Runner.run(agent, user_input)
print(result.final_output)
except MaxTurnsExceeded as e:
# Partial result available
partial = e.partial_result
print(f"Partial output: {partial.final_output}")
print(f"Turns used: {len(partial.new_items)}")
```
## Result Serialization
```python
# To dict
result_dict = {
"output": result.final_output,
"agent": result.last_agent.name,
"usage": {
"input": result.usage.input_tokens,
"output": result.usage.output_tokens,
},
}
# To JSON
import json
json.dumps(result_dict)
```
## See Also
- [Running Agents](running_agents.md) - Get results
- [Streaming](streaming.md) - Streaming results
- [Tracing](tracing.md) - Debug results
+178 -2
View File
@@ -1,2 +1,178 @@
# running agents
Documentation coming soon.
# Running Agents
Execute agents with the `Runner` class.
## Basic Usage
### Synchronous
```python
from agents import Agent, Runner
agent = Agent(name="assistant", instructions="Be helpful.")
result = Runner.run_sync(agent, "Hello!")
print(result.final_output)
```
### Asynchronous
```python
import asyncio
from agents import Agent, Runner
agent = Agent(name="assistant", instructions="Be helpful.")
async def main():
result = await Runner.run(agent, "Hello!")
print(result.final_output)
asyncio.run(main())
```
## Run Configuration
```python
from agents import Runner, RunConfig, ModelSettings
config = RunConfig(
model="gpt-4o",
model_settings=ModelSettings(temperature=0.5),
max_turns=20,
tracing_disabled=False,
)
result = await Runner.run(agent, "Hello!", run_config=config)
```
## RunConfig Options
| Parameter | Default | Description |
|-----------|---------|-------------|
| `model` | None | Override agent model |
| `model_provider` | OpenAI | Model provider |
| `model_settings` | None | Global model settings |
| `max_turns` | 10 | Maximum conversation turns |
| `input_guardrails` | None | Global input guardrails |
| `output_guardrails` | None | Global output guardrails |
| `tracing_disabled` | False | Disable tracing |
## Context
Pass custom context to tools and guardrails:
```python
from dataclasses import dataclass
from agents import Agent, Runner, function_tool
@dataclass
class MyContext:
user_id: str
permissions: list[str]
@function_tool
def get_user_data(ctx: MyContext) -> str:
return f"Data for user {ctx.user_id}"
agent = Agent(
name="contextual",
instructions="Access user data as needed.",
tools=[get_user_data],
)
context = MyContext(user_id="123", permissions=["read"])
result = await Runner.run(agent, "Get my data", context=context)
```
## Run Result
The `RunResult` contains:
```python
result = await Runner.run(agent, "Hello!")
# Final output text
print(result.final_output)
# All conversation items
for item in result.new_items:
print(item)
# Last agent that ran (for handoffs)
print(result.last_agent.name)
# Input/output guardrail results
print(result.input_guardrail_results)
print(result.output_guardrail_results)
# Token usage
print(result.usage)
```
## Max Turns
Limit conversation turns to prevent infinite loops:
```python
from agents import Runner, RunConfig
config = RunConfig(max_turns=5)
try:
result = await Runner.run(agent, "Complex task", run_config=config)
except MaxTurnsExceeded:
print("Agent hit max turns limit")
```
## Run Hooks
Monitor run lifecycle:
```python
from agents import Runner, RunHooks
class MyRunHooks(RunHooks):
async def on_agent_start(self, context, agent):
print(f"Starting: {agent.name}")
async def on_tool_start(self, context, agent, tool):
print(f"Calling tool: {tool.name}")
async def on_handoff(self, context, from_agent, to_agent):
print(f"Handoff: {from_agent.name} -> {to_agent.name}")
result = await Runner.run(
agent,
"Hello!",
run_hooks=MyRunHooks(),
)
```
## Error Handling
```python
from agents import (
Runner,
AgentsException,
MaxTurnsExceeded,
InputGuardrailTripwireTriggered,
OutputGuardrailTripwireTriggered,
)
try:
result = await Runner.run(agent, user_input)
except MaxTurnsExceeded:
print("Too many turns")
except InputGuardrailTripwireTriggered as e:
print(f"Input blocked: {e}")
except OutputGuardrailTripwireTriggered as e:
print(f"Output blocked: {e}")
except AgentsException as e:
print(f"Agent error: {e}")
```
## See Also
- [Agents](agents.md) - Creating agents
- [Streaming](streaming.md) - Stream responses
- [Tracing](tracing.md) - Debug runs
+156 -2
View File
@@ -1,2 +1,156 @@
# streaming
Documentation coming soon.
# Streaming
Stream agent responses for real-time output.
## Basic Streaming
```python
from agents import Agent, Runner
agent = Agent(name="assistant", instructions="Be helpful.")
async def stream_response():
async for event in Runner.run_streamed(agent, "Tell me a story"):
if event.type == "raw_response_event":
# Token-by-token output
print(event.data, end="", flush=True)
elif event.type == "agent_updated_event":
# Agent changed (handoff)
print(f"\n[Agent: {event.new_agent.name}]")
```
## Stream Events
| Event Type | Description |
|------------|-------------|
| `raw_response_event` | Raw LLM response chunks |
| `agent_updated_event` | Agent changed (handoff) |
| `tool_call_event` | Tool being called |
| `tool_output_event` | Tool returned result |
| `run_item_event` | New run item added |
## Processing Events
```python
from agents import Runner
from agents.stream_events import (
RawResponsesStreamEvent,
AgentUpdatedStreamEvent,
)
async for event in Runner.run_streamed(agent, user_input):
match event:
case RawResponsesStreamEvent(data=chunk):
# Handle text chunk
print(chunk, end="")
case AgentUpdatedStreamEvent(new_agent=new_agent):
# Handle agent switch
print(f"\n[Switched to: {new_agent.name}]")
```
## Streaming with Context
```python
from dataclasses import dataclass
from agents import Agent, Runner
@dataclass
class MyContext:
user_id: str
context = MyContext(user_id="123")
async for event in Runner.run_streamed(
agent,
"Hello!",
context=context,
):
print(event)
```
## Streaming Result
Get the final result after streaming:
```python
from agents import Runner, RunResultStreaming
stream = Runner.run_streamed(agent, "Hello!")
result: RunResultStreaming = None
async for event in stream:
print(event)
result = stream.result
# After streaming completes
print(f"Final output: {result.final_output}")
print(f"Usage: {result.usage}")
```
## Buffered Streaming
Collect output while streaming:
```python
from agents import Runner
buffer = []
async for event in Runner.run_streamed(agent, "Hello!"):
if event.type == "raw_response_event":
buffer.append(event.data)
print(event.data, end="")
full_response = "".join(buffer)
```
## Streaming with Tools
Tool calls appear as events:
```python
from agents import Runner
async for event in Runner.run_streamed(agent, "What's the weather?"):
match event.type:
case "tool_call_event":
print(f"Calling: {event.tool_name}")
case "tool_output_event":
print(f"Result: {event.output}")
case "raw_response_event":
print(event.data, end="")
```
## Streaming with Handoffs
```python
from agents import Runner
current_agent = None
async for event in Runner.run_streamed(main_agent, "Help me"):
if event.type == "agent_updated_event":
current_agent = event.new_agent
print(f"\n--- Transferred to {current_agent.name} ---\n")
elif event.type == "raw_response_event":
print(event.data, end="")
```
## Error Handling in Streams
```python
from agents import Runner, AgentsException
try:
async for event in Runner.run_streamed(agent, user_input):
print(event)
except AgentsException as e:
print(f"Stream error: {e}")
```
## See Also
- [Running Agents](running_agents.md) - Non-streaming execution
- [Tracing](tracing.md) - Debug streams
- [Results](results.md) - Result handling
+190 -2
View File
@@ -1,2 +1,190 @@
# tools
Documentation coming soon.
# Tools
Tools give agents the ability to take actions and access external data.
## Function Tools
The simplest way to create a tool:
```python
from agents import Agent, function_tool
@function_tool
def get_weather(city: str) -> str:
"""Get current weather for a city.
Args:
city: The city name to get weather for
"""
# Your implementation
return f"Weather in {city}: Sunny, 72°F"
agent = Agent(
name="weather_bot",
instructions="Help users with weather information.",
tools=[get_weather],
)
```
## Async Tools
```python
@function_tool
async def fetch_data(url: str) -> str:
"""Fetch data from a URL."""
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
```
## Tools with Context
Access the run context in tools:
```python
from dataclasses import dataclass
from agents import function_tool, RunContextWrapper
@dataclass
class AppContext:
user_id: str
api_key: str
@function_tool
def get_user_profile(ctx: RunContextWrapper[AppContext]) -> str:
"""Get the current user's profile."""
user_id = ctx.context.user_id
# Fetch profile using user_id
return f"Profile for user {user_id}"
```
## Tool Parameters
Pydantic models for complex parameters:
```python
from pydantic import BaseModel, Field
from agents import function_tool
class SearchParams(BaseModel):
query: str = Field(description="Search query")
max_results: int = Field(default=10, description="Max results to return")
include_metadata: bool = Field(default=False)
@function_tool
def search(params: SearchParams) -> str:
"""Search the knowledge base."""
# Use params.query, params.max_results, etc.
return f"Found results for: {params.query}"
```
## Custom Tool Class
For more control, extend the `Tool` class:
```python
from agents import Tool
class DatabaseTool(Tool):
name = "query_database"
description = "Query the application database"
def __init__(self, connection_string: str):
self.conn = connect(connection_string)
async def run(self, query: str) -> str:
result = await self.conn.execute(query)
return str(result)
@property
def parameters_schema(self) -> dict:
return {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "SQL query to execute"
}
},
"required": ["query"]
}
```
## Tool Return Types
### String (default)
```python
@function_tool
def simple() -> str:
return "Hello"
```
### Structured (Pydantic)
```python
class ToolResult(BaseModel):
success: bool
data: dict
@function_tool
def structured() -> ToolResult:
return ToolResult(success=True, data={"key": "value"})
```
### List/Dict
```python
@function_tool
def get_items() -> list[str]:
return ["item1", "item2", "item3"]
```
## Error Handling
```python
from agents import function_tool, ToolError
@function_tool
def risky_operation(param: str) -> str:
"""An operation that might fail."""
try:
result = do_something(param)
return result
except Exception as e:
raise ToolError(f"Operation failed: {e}")
```
## Tool Metadata
```python
@function_tool(
name="custom_name", # Override function name
description="Custom description", # Override docstring
)
def my_tool(x: int) -> int:
return x * 2
```
## Multiple Tools
```python
from agents import Agent
agent = Agent(
name="multi_tool",
instructions="Use available tools to help users.",
tools=[
get_weather,
search_web,
calculate,
send_email,
],
)
```
## See Also
- [Agents](agents.md) - Creating agents
- [Running Agents](running_agents.md) - Execution
- [Context](context.md) - Run context
+210 -2
View File
@@ -1,2 +1,210 @@
# tracing
Documentation coming soon.
# Tracing
Built-in observability for debugging and monitoring agent runs.
## Automatic Tracing
Tracing is enabled by default:
```python
from agents import Agent, Runner
agent = Agent(name="assistant", instructions="Be helpful.")
result = await Runner.run(agent, "Hello!")
# Traces are automatically collected
```
## Trace Structure
Each run creates a trace with spans:
```
Trace (run_id)
├── Agent Span (assistant)
│ ├── LLM Call
│ ├── Tool Call (get_weather)
│ └── LLM Call
└── Agent Span (specialist) # if handoff
└── LLM Call
```
## Custom Spans
Add custom spans for your code:
```python
from agents import trace, Span
@trace("my_operation")
async def my_function():
# Automatically traced
pass
# Or manually
async def manual_trace():
with Span("custom_span") as span:
span.set_attribute("key", "value")
# Your code here
```
## Span Attributes
```python
from agents import Span
with Span("process_data") as span:
span.set_attribute("input_size", len(data))
span.set_attribute("user_id", user_id)
result = process(data)
span.set_attribute("output_size", len(result))
```
## Error Tracking
```python
from agents import Span, SpanError
with Span("risky_operation") as span:
try:
result = risky_call()
except Exception as e:
span.record_error(SpanError(
message=str(e),
type=type(e).__name__,
))
raise
```
## Agent Span Data
Access agent-specific span data:
```python
from agents.tracing.span_data import AgentSpanData
# In hooks or custom code
span_data = AgentSpanData(
agent_name="assistant",
model="gpt-4o",
input_tokens=100,
output_tokens=50,
)
```
## Accessing Current Trace
```python
from agents import get_current_trace
trace = get_current_trace()
if trace:
print(f"Trace ID: {trace.trace_id}")
print(f"Spans: {len(trace.spans)}")
```
## Trace Export
### Console (default)
```python
from agents import Runner, RunConfig
config = RunConfig(
tracing_disabled=False, # Default
)
```
### Custom Exporter
```python
from agents.tracing import TraceExporter
class MyExporter(TraceExporter):
async def export(self, trace):
# Send to your observability platform
await send_to_datadog(trace)
# Register exporter
from agents.tracing import register_exporter
register_exporter(MyExporter())
```
## Disabling Tracing
```python
from agents import Runner, RunConfig
# Disable for a single run
config = RunConfig(tracing_disabled=True)
result = await Runner.run(agent, "Hello!", run_config=config)
# Disable globally
import agents
agents.tracing.disable()
```
## Trace Context
Propagate trace context across services:
```python
from agents import get_current_trace
# Get context to pass to another service
trace = get_current_trace()
context = {
"trace_id": trace.trace_id,
"span_id": trace.current_span.span_id,
}
# In the other service
from agents import trace_from_context
with trace_from_context(context):
# Operations here are linked to parent trace
pass
```
## Performance
Tracing adds minimal overhead:
| Operation | Overhead |
|-----------|----------|
| Span creation | ~1μs |
| Attribute set | ~0.5μs |
| Export (async) | Non-blocking |
## Integration
### OpenTelemetry
```python
from agents.tracing.otel import OTelExporter
exporter = OTelExporter(
endpoint="http://localhost:4317",
service_name="my-agent-app",
)
register_exporter(exporter)
```
### LangSmith
```python
from agents.tracing.langsmith import LangSmithExporter
exporter = LangSmithExporter(
api_key=os.environ["LANGSMITH_API_KEY"],
project="my-project",
)
register_exporter(exporter)
```
## See Also
- [Running Agents](running_agents.md) - Execution
- [Streaming](streaming.md) - Stream with traces
- [Results](results.md) - Access trace data in results