Build and run Python-based AI agents using the AWS Strands SDK. Use when you need to create autonomous agents, multi-agent workflows, custom tools, or integrate with MCP servers. Supports Ollama (local), Anthropic, OpenAI, Bedrock, and other model providers. Use for agent scaffolding, tool creation, and running agent tasks programmatically.
---
name: strands
version: 2.0.0
description: Build and run Python-based AI agents using the AWS Strands SDK. Use when you need to create autonomous agents, multi-agent workflows, custom tools, or integrate with MCP servers. Supports Ollama (local), Anthropic, OpenAI, Bedrock, and other model providers. Use for agent scaffolding, tool creation, and running agent tasks programmatically.
homepage: https://github.com/strands-agents/sdk-python
metadata:
openclaw:
emoji: 🧬
requires:
bins: [python3]
packages: [strands-agents]
---
# Strands Agents SDK
Build AI agents in Python using the [Strands SDK](https://github.com/strands-agents/sdk-python) (Apache-2.0, from AWS).
Validated against: `strands-agents==1.23.0`, `strands-agents-tools==0.2.19`
## Prerequisites
```bash
# Install SDK + tools (via pipx for isolation — recommended)
pipx install strands-agents-builder # includes strands-agents + strands-agents-tools + CLI
# Or install directly
pip install strands-agents strands-agents-tools
```
## Core Concept: Bedrock Is the Default
`Agent()` with no `model=` argument defaults to **Amazon Bedrock** — specifically `us.anthropic.claude-sonnet-4-20250514-v1:0` in `us-west-2`. This requires AWS credentials. To use a different provider, pass `model=` explicitly.
Default model constant: `strands.models.bedrock.DEFAULT_BEDROCK_MODEL_ID`
## Quick Start — Local Agent (Ollama)
```python
from strands import Agent
from strands.models.ollama import OllamaModel
# host is a required positional argument
model = OllamaModel("http://localhost:11434", model_id="qwen3:latest")
agent = Agent(model=model)
result = agent("What is the capital of France?")
print(result)
```
**Note:** Not all open-source models support tool-calling. Abliterated models often lose function-calling during the abliteration process. Test with a stock model (qwen3, llama3.x, mistral) first.
## Quick Start — Bedrock (Default Provider)
```python
from strands import Agent
# No model specified → BedrockModel (Claude Sonnet 4, us-west-2)
# Requires AWS credentials (~/.aws/credentials or env vars)
agent = Agent()
result = agent("Explain quantum computing")
# Explicit Bedrock model:
from strands.models import BedrockModel
model = BedrockModel(model_id="us.anthropic.claude-sonnet-4-20250514-v1:0")
agent = Agent(model=model)
```
## Quick Start — Anthropic (Direct API)
```python
from strands import Agent
from strands.models.anthropic import AnthropicModel
# max_tokens is Required[int] — must be provided
model = AnthropicModel(model_id="claude-sonnet-4-20250514", max_tokens=4096)
agent = Agent(model=model)
result = agent("Explain quantum computing")
```
Requires `ANTHROPIC_API_KEY` environment variable.
## Quick Start — OpenAI
```python
from strands import Agent
from strands.models.openai import OpenAIModel
model = OpenAIModel(model_id="gpt-4.1")
agent = Agent(model=model)
```
Requires `OPENAI_API_KEY` environment variable.
## Creating Custom Tools
Use the `@tool` decorator. Type hints become the schema; the docstring becomes the description:
```python
from strands import Agent, tool
@tool
def read_file(path: str) -> str:
"""Read contents of a file at the given path.
Args:
path: Filesystem path to read.
"""
with open(path) as f:
return f.read()
@tool
def write_file(path: str, content: str) -> str:
"""Write content to a file.
Args:
path: Filesystem path to write.
content: Text content to write.
"""
with open(path, 'w') as f:
f.write(content)
return f"Wrote {len(content)} bytes to {path}"
agent = Agent(model=model, tools=[read_file, write_file])
agent("Read /tmp/test.txt and summarize it")
```
### ToolContext
Tools can access agent state via `ToolContext`:
```python
from strands import tool
from strands.types.tools import ToolContext
@tool
def stateful_tool(query: str, tool_context: ToolContext) -> str:
"""A tool that accesses agent state.
Args:
query: Input query.
"""
# Access shared agent state
count = tool_context.state.get("call_count", 0) + 1
tool_context.state["call_count"] = count
return f"Call #{count}: {query}"
```
## Built-in Tools (46 available)
`strands-agents-tools` provides pre-built tools:
```python
from strands_tools import calculator, file_read, file_write, shell, http_request
agent = Agent(model=model, tools=[calculator, file_read, shell])
```
Full list: `calculator`, `file_read`, `file_write`, `shell`, `http_request`, `editor`, `image_reader`, `python_repl`, `current_time`, `think`, `stop`, `sleep`, `environment`, `retrieve`, `search_video`, `chat_video`, `speak`, `generate_image`, `generate_image_stability`, `diagram`, `journal`, `memory`, `agent_core_memory`, `elasticsearch_memory`, `mongodb_memory`, `mem0_memory`, `rss`, `cron`, `batch`, `workflow`, `use_agent`, `use_llm`, `use_aws`, `use_computer`, `load_tool`, `handoff_to_user`, `slack`, `swarm`, `graph`, `a2a_client`, `mcp_client`, `exa`, `tavily`, `bright_data`, `nova_reels`.
Hot reload: `Agent(load_tools_from_directory=True)` watches `./tools/` for changes.
## MCP Integration
Connect to any Model Context Protocol server. MCPClient implements `ToolProvider` — pass it directly in the tools list:
```python
from strands import Agent
from strands.tools.mcp import MCPClient
from mcp import stdio_client, StdioServerParameters
# MCPClient takes a callable that returns the transport
mcp = MCPClient(lambda: stdio_client(StdioServerParameters(
command="uvx",
args=["some-mcp-server@latest"]
)))
# Use as context manager — MCPClient is a ToolProvider
with mcp:
agent = Agent(model=model, tools=[mcp])
agent("Use the MCP tools to do something")
```
SSE transport:
```python
from mcp.client.sse import sse_client
mcp = MCPClient(lambda: sse_client("http://localhost:8080/sse"))
```
## Multi-Agent Patterns
### Agents as Tools
Nest agents — inner agents become tools for the outer agent:
```python
researcher = Agent(model=model, system_prompt="You are a research assistant.")
writer = Agent(model=model, system_prompt="You are a writer.")
orchestrator = Agent(
model=model,
tools=[researcher, writer],
system_prompt="You coordinate research and writing tasks."
)
orchestrator("Research quantum computing and write a blog post")
```
### Swarm Pattern
Self-organizing agent teams with shared context and autonomous handoff coordination:
```python
from strands.multiagent.swarm import Swarm
# Agents need name + description for handoff identification
researcher = Agent(
model=model,
name="researcher",
description="Finds and summarizes information"
)
writer = Agent(
model=model,
name="writer",
description="Creates polished content"
)
swarm = Swarm(
nodes=[researcher, writer],
entry_point=researcher, # optional — defaults to first agent
max_handoffs=20, # default
max_iterations=20, # default
execution_timeout=900.0, # 15 min default
node_timeout=300.0 # 5 min per node default
)
result = swarm("Research AI agents, then hand off to writer for a blog post")
```
Swarm auto-injects a `handoff_to_agent` tool. Agents hand off by calling it with the target agent's name. Supports interrupt/resume, session persistence, and repetitive-handoff detection.
### Graph Pattern (DAG)
Deterministic dependency-based execution via `GraphBuilder`:
```python
from strands.multiagent.graph import GraphBuilder
builder = GraphBuilder()
research_node = builder.add_node(researcher, node_id="research")
writing_node = builder.add_node(writer, node_id="writing")
builder.add_edge("research", "writing")
builder.set_entry_point("research")
# Optional: conditional edges
# builder.add_edge("research", "writing",
# condition=lambda state: "complete" in str(state.completed_nodes))
graph = builder.build()
result = graph("Write a blog post about AI agents")
```
Supports cycles (feedback loops) with `builder.reset_on_revisit(True)`, execution timeouts, and nested graphs (Graph as a node in another Graph).
### A2A Protocol (Agent-to-Agent)
Expose a Strands agent as an A2A-compatible server for inter-agent communication:
```python
from strands.multiagent.a2a import A2AServer
server = A2AServer(
agent=my_agent,
host="127.0.0.1",
port=9000,
version="0.0.1"
)
server.start() # runs uvicorn
```
Connect to A2A agents with the `a2a_client` tool from strands-agents-tools. A2A implements Google's Agent-to-Agent protocol for standardized cross-process/cross-network agent communication.
## Session Persistence
Persist conversations across agent runs:
```python
from strands.session.file_session_manager import FileSessionManager
session = FileSessionManager(session_file_path="./sessions/my_session.json")
agent = Agent(model=model, session_manager=session)
# Also available:
from strands.session.s3_session_manager import S3SessionManager
session = S3SessionManager(bucket_name="my-bucket", session_id="session-1")
```
Both Swarm and Graph support session managers for persisting multi-agent state.
## Bidirectional Streaming (Experimental)
Real-time voice/text conversations with persistent audio streams:
```python
from strands.experimental.bidi.agent import BidiAgent
from strands.experimental.bidi.models.nova_sonic import NovaSonicModel
# Supports: NovaSonicModel, GeminiLiveModel, OpenAIRealtimeModel
model = NovaSonicModel(region="us-east-1")
agent = BidiAgent(model=model, tools=[my_tool])
```
Supports interruption detection, concurrent tool execution, and continuous back-and-forth audio. Experimental — API subject to change.
## System Prompts
```python
agent = Agent(
model=model,
system_prompt="You are Hex, a sharp and witty AI assistant.",
tools=[read_file, write_file]
)
```
Strands also supports `list[SystemContentBlock]` for structured system prompts with cache control.
## Observability
Native OpenTelemetry tracing:
```python
agent = Agent(
model=model,
trace_attributes={"project": "my-agent", "environment": "dev"}
)
```
Every tool call, model invocation, handoff, and lifecycle event is instrumentable.
## Bedrock-Specific Features
- **Guardrails**: `guardrail_id` + `guardrail_version` in BedrockModel config — content filtering, PII detection, input/output redaction
- **Cache points**: System prompt and tool definition caching for cost optimization
- **Streaming**: On by default, disable with `streaming=False`
- **Region**: Defaults to `us-west-2`, override via `region_name` param or `AWS_REGION` env
- **Cross-region inference**: Model IDs prefixed with `us.` use cross-region inference profiles
## Scaffolding a New Agent
```bash
python3 {baseDir}/scripts/create-agent.py my-agent --provider ollama --model qwen3:latest
python3 {baseDir}/scripts/create-agent.py my-agent --provider anthropic
python3 {baseDir}/scripts/create-agent.py my-agent --provider bedrock
python3 {baseDir}/scripts/create-agent.py my-agent --provider openai --model gpt-4.1
```
Creates a ready-to-run agent directory with tools, config, and entry point.
## Running an Agent
```bash
python3 {baseDir}/scripts/run-agent.py path/to/agent.py "Your prompt here"
python3 {baseDir}/scripts/run-agent.py path/to/agent.py --interactive
```
## Model Providers Reference (11 total)
| Provider | Class | Init | Notes |
|----------|-------|------|-------|
| Bedrock | `BedrockModel` | `BedrockModel(model_id=...)` | **Default**, eagerly imported |
| Ollama | `OllamaModel` | `OllamaModel("http://host:11434", model_id=...)` | `host` is positional |
| Anthropic | `AnthropicModel` | `AnthropicModel(model_id=..., max_tokens=4096)` | `max_tokens` **required** |
| OpenAI | `OpenAIModel` | `OpenAIModel(model_id=...)` | `OPENAI_API_KEY` |
| Gemini | `GeminiModel` | `GeminiModel(model_id=...)` | `api_key` in client_args |
| Mistral | `MistralModel` | `MistralModel(model_id=...)` | Mistral API key |
| LiteLLM | `LiteLLMModel` | `LiteLLMModel(model_id=...)` | Meta-provider (Cohere, Groq, etc.) |
| LlamaAPI | `LlamaAPIModel` | `LlamaAPIModel(model_id=...)` | Meta Llama API |
| llama.cpp | `LlamaCppModel` | `LlamaCppModel(...)` | Local server, OpenAI-compatible |
| SageMaker | `SageMakerAIModel` | `SageMakerAIModel(...)` | Custom AWS endpoints |
| Writer | `WriterModel` | `WriterModel(model_id=...)` | Writer platform |
All non-Bedrock providers are **lazy-loaded** — dependencies imported only when referenced.
Import pattern: `from strands.models.<provider> import <Class>` (or `from strands.models import <Class>` for lazy-load).
## Tips
- `Agent()` without `model=` requires AWS credentials (Bedrock default)
- `AnthropicModel` requires `max_tokens` — omitting it causes a runtime error
- `OllamaModel` `host` is positional: `OllamaModel("http://...", model_id="...")`
- Abliterated Ollama models often lose tool-calling support — use stock models for tool-using agents
- Swarm agents need `name=` and `description=` for handoff routing
- `Agent(load_tools_from_directory=True)` watches `./tools/` for hot-reloaded tool files
- Use `agent.tool.my_tool()` to call tools directly without LLM routing
- `MCPClient` is a `ToolProvider` — pass it directly in `tools=[mcp]`, don't call `list_tools_sync()` manually when using with Agent
- Session managers work with Agent, Swarm, and Graph
- Pin your `strands-agents` version — the SDK is young and APIs evolve between releases
don't have the plugin yet? install it then click "run inline in claude" again.
structured inputs by provider with credential details, added decision points for model selection and edge cases like tool-calling loss in abliterated models, rate limiting, and timeouts, formalized output contract with JSON schemas and trace span names, clarified outcome signals with verification steps.
Build AI agents in Python using the Strands SDK (Apache-2.0 license, from AWS). Use this skill to scaffold autonomous agents, create multi-agent workflows, define custom tools, or integrate with MCP servers.
Validated against: strands-agents==1.23.0, strands-agents-tools==0.2.19
The Strands SDK lets you build production-grade Python agents backed by multiple LLM providers (Bedrock, Anthropic, OpenAI, Ollama, Gemini, etc.). Use it when you need autonomous task execution, tool-calling agents, agent-to-agent coordination (swarms or DAGs), or MCP protocol integration. The skill covers agent scaffolding, custom tool creation, multi-agent patterns, session persistence, and observability.
pip install strands-agents or pipx install strands-agents-builder (recommended for isolation)| Provider | Env Var(s) | Setup Notes |
|---|---|---|
| Bedrock (default) | AWS credentials in ~/.aws/credentials or AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN |
Region defaults to us-west-2, override with AWS_REGION or region_name param |
| Anthropic | ANTHROPIC_API_KEY |
Get key from https://console.anthropic.com |
| OpenAI | OPENAI_API_KEY |
Get key from https://platform.openai.com/api-keys |
| Ollama | None (local) | Ollama server running on localhost:11434 or custom host |
| Gemini | GOOGLE_API_KEY in client_args |
Get key from Google AI Studio |
| Mistral | MISTRAL_API_KEY |
Get key from Mistral console |
| LiteLLM | Provider-specific env vars (Cohere, Groq, etc.) | Meta-provider wrapper |
| LlamaAPI | LLAMA_API_KEY |
Meta Llama API key |
| SageMaker | AWS credentials + endpoint URI | Custom AWS SageMaker endpoints |
| Writer | WRITER_API_KEY |
Writer platform API key |
FileSessionManager or S3SessionManager)Input: Python 3.8+, network access to PyPI
# Option A: Isolated install (recommended)
pipx install strands-agents-builder
# Option B: Direct install
pip install strands-agents strands-agents-tools
Output: Executable python3, strands-agents and strands-agents-tools importable in Python
Input: Model provider (Bedrock, Anthropic, OpenAI, Ollama, etc.), appropriate env vars or config
Choose your provider and instantiate:
Bedrock (default, requires AWS credentials):
from strands import Agent
agent = Agent() # Uses us.anthropic.claude-sonnet-4-20250514-v1:0 in us-west-2
Ollama (local, positional host argument):
from strands import Agent
from strands.models.ollama import OllamaModel
model = OllamaModel("http://localhost:11434", model_id="qwen3:latest")
agent = Agent(model=model)
Anthropic (requires ANTHROPIC_API_KEY, max_tokens required):
from strands import Agent
from strands.models.anthropic import AnthropicModel
model = AnthropicModel(model_id="claude-sonnet-4-20250514", max_tokens=4096)
agent = Agent(model=model)
OpenAI (requires OPENAI_API_KEY):
from strands import Agent
from strands.models.openai import OpenAIModel
model = OpenAIModel(model_id="gpt-4.1")
agent = Agent(model=model)
Output: Agent instance ready for tool registration and task execution
Input: Python functions with type hints and docstrings
Use the @tool decorator. Type hints become the schema; docstrings become descriptions:
from strands import tool
@tool
def read_file(path: str) -> str:
"""Read contents of a file at the given path.
Args:
path: Filesystem path to read.
"""
with open(path) as f:
return f.read()
@tool
def write_file(path: str, content: str) -> str:
"""Write content to a file.
Args:
path: Filesystem path to write.
content: Text content to write.
"""
with open(path, 'w') as f:
f.write(content)
return f"Wrote {len(content)} bytes to {path}"
Tools with State Access:
from strands import tool
from strands.types.tools import ToolContext
@tool
def stateful_tool(query: str, tool_context: ToolContext) -> str:
"""A tool that accesses agent state.
Args:
query: Input query.
"""
count = tool_context.state.get("call_count", 0) + 1
tool_context.state["call_count"] = count
return f"Call #{count}: {query}"
Output: Tool functions decorated and ready to pass to Agent
Input: Tool functions (custom-defined or pre-built from strands-agents-tools), optional hot-reload flag
from strands import Agent
from strands_tools import calculator, file_read, file_write, shell
agent = Agent(
model=model,
tools=[read_file, write_file, calculator, shell]
)
Hot-reload from directory:
agent = Agent(
model=model,
load_tools_from_directory=True # Watches ./tools/ for changes
)
Available Pre-built Tools (46 total): calculator, file_read, file_write, shell, http_request, editor, image_reader, python_repl, current_time, think, stop, sleep, environment, retrieve, search_video, chat_video, speak, generate_image, generate_image_stability, diagram, journal, memory, agent_core_memory, elasticsearch_memory, mongodb_memory, mem0_memory, rss, cron, batch, workflow, use_agent, use_llm, use_aws, use_computer, load_tool, handoff_to_user, slack, swarm, graph, a2a_client, mcp_client, exa, tavily, bright_data, nova_reels
Output: Agent with tools registered
Input: Agent instance, task prompt (string)
result = agent("Read /tmp/test.txt and summarize it")
print(result)
Direct Tool Call (bypass LLM routing):
direct_result = agent.tool.read_file("/tmp/test.txt")
Output: String response from agent or tool
Input: MCP server command (stdio) or URL (SSE), MCPClient context manager
Stdio transport (local command):
from strands import Agent
from strands.tools.mcp import MCPClient
from mcp import stdio_client, StdioServerParameters
mcp = MCPClient(lambda: stdio_client(StdioServerParameters(
command="uvx",
args=["some-mcp-server@latest"]
)))
with mcp:
agent = Agent(model=model, tools=[mcp])
agent("Use the MCP tools to fetch data")
SSE transport (remote MCP server):
from mcp.client.sse import sse_client
mcp = MCPClient(lambda: sse_client("http://localhost:8080/sse"))
with mcp:
agent = Agent(model=model, tools=[mcp])
Output: Agent with MCP tools available
Input: Multiple Agent instances, pattern choice (Swarm, Graph, or nested)
Nested Agents (agents as tools):
researcher = Agent(model=model, system_prompt="You are a research assistant.")
writer = Agent(model=model, system_prompt="You are a writer.")
orchestrator = Agent(
model=model,
tools=[researcher, writer],
system_prompt="You coordinate research and writing tasks."
)
orchestrator("Research quantum computing and write a blog post")
Swarm Pattern (self-organizing, autonomous handoffs):
from strands.multiagent.swarm import Swarm
researcher = Agent(
model=model,
name="researcher",
description="Finds and summarizes information"
)
writer = Agent(
model=model,
name="writer",
description="Creates polished content"
)
swarm = Swarm(
nodes=[researcher, writer],
entry_point=researcher,
max_handoffs=20,
max_iterations=20,
execution_timeout=900.0,
node_timeout=300.0
)
result = swarm("Research AI agents, then hand off to writer for a blog post")
Swarm auto-injects a handoff_to_agent tool. Agents handoff by calling it with target agent name.
Graph Pattern (DAG, deterministic):
from strands.multiagent.graph import GraphBuilder
builder = GraphBuilder()
research_node = builder.add_node(researcher, node_id="research")
writing_node = builder.add_node(writer, node_id="writing")
builder.add_edge("research", "writing")
builder.set_entry_point("research")
graph = builder.build()
result = graph("Write a blog post about AI agents")
Output: Swarm or Graph instance with agents coordinated
Input: Session file path or S3 bucket details
File-based session:
from strands.session.file_session_manager import FileSessionManager
session = FileSessionManager(session_file_path="./sessions/my_session.json")
agent = Agent(model=model, session_manager=session)
S3-backed session:
from strands.session.s3_session_manager import S3SessionManager
session = S3SessionManager(bucket_name="my-bucket", session_id="session-1")
agent = Agent(model=model, session_manager=session)
Session managers work with Agent, Swarm, and Graph.
Output: Agent with conversation history persisted to file or S3
Input: Optional trace attributes dict
agent = Agent(
model=model,
trace_attributes={"project": "my-agent", "environment": "dev"}
)
Native OpenTelemetry tracing is auto-enabled. Every tool call, model invocation, handoff, and lifecycle event is instrumented.
Output: Agent with tracing enabled
Input: Agent name, model provider, model ID (optional)
python3 {baseDir}/scripts/create-agent.py my-agent --provider ollama --model qwen3:latest
python3 {baseDir}/scripts/create-agent.py my-agent --provider anthropic
python3 {baseDir}/scripts/create-agent.py my-agent --provider bedrock
python3 {baseDir}/scripts/create-agent.py my-agent --provider openai --model gpt-4.1
Output: Directory with ready-to-run agent code, tools skeleton, config, and entry point
Input: Agent script path, prompt (or --interactive flag)
python3 {baseDir}/scripts/run-agent.py path/to/agent.py "Your prompt here"
python3 {baseDir}/scripts/run-agent.py path/to/agent.py --interactive
Output: Agent task result printed to stdout
max_tokens is required.strands.models.<provider> with required env vars.stdio_client with StdioServerParameters.sse_client with URL.with mcp:) to ensure proper connection lifecycle.execution_timeout= param if tasks run longer.node_timeout= if a single agent needs more time.us.): Bedrock automatically routes to the correct region. Verify region policy in AWS account.region_name param on BedrockModel or set AWS_REGION env var.Synchronous call:
result = agent("Your prompt")
Returns: str (agent response text)
Custom tools return typed values (str, dict, list, etc.) as declared in function signature. Pre-built tools return structured outputs (e.g., calculator returns int/float, file_read returns str).
FileSessionManager writes to session_file_path as JSON with keys:
messages: List of conversation turnsmetadata: Agent config and state snapshotsS3SessionManager writes to s3://{bucket_name}/{session_id}.json with same schema.
Swarm returns final output from the last agent to speak, plus metadata:
result: Final response stringhandoffs: List of agent-to-agent handoff eventsiteration_count: Number of swarm iterationsGraph returns final node output plus execution log:
result: Output from final nodeexecuted_nodes: List of node IDs executed in ordernode_outputs: Dict mapping node ID to its outputOpenTelemetry traces are emitted to configured collector (if available) with these span names:
agent.invoke: Top-level agent callagent.tool_call: Tool executionagent.handoff: Multi-agent handoffmodel.invoke: LLM API callTraces include trace_attributes dict passed at agent init.
create-agent.py creates:
my-agent/
agent.py # Entry point with model init
tools/ # Custom tools directory
config.yaml # Agent config (if applicable)
README.md # Usage instructions
Agent responds to prompt: Call agent("Your prompt") and receive a non-empty string response. No exceptions raised.
Tools are invoked: Agent calls custom or pre-built tools during execution. Check agent logs or set trace_attributes and inspect OpenTelemetry spans for agent.tool_call events.
Tool output appears in response: Agent response includes results from tool execution (e.g., file contents, calculation results, search results). Verify by examining response text.
MCP tools are available: When MCPClient is active, agent can call MCP-exposed tools without error. MCP server stays connected (no connection refused errors).
Multi-agent handoff occurs: In Swarm, agents call handoff_to_agent and pass control. Check swarm result for handoffs key with non-empty list.
Session state persists: Run agent, stop process, restart with same session_manager. Agent recalls prior conversation turns. Verify by checking session file for new messages.
Scaffold runs without error: create-agent.py completes and agent.py is executable (python3 my-agent/agent.py "test").
Observability emits traces: Set OpenTelemetry exporter (e.g., OTEL_EXPORTER_OTLP_ENDPOINT), run agent, and traces appear in backend (Jaeger, Datadog, etc.). Each tool call and handoff has its own span.
Rate limit handled gracefully: Agent retries on 429 response; no crash. Response may be slower but eventual.
Timeout triggered: Swarm or Graph execution hits execution_timeout or node_timeout and halts cleanly, returning partial result with metadata (not a hang or exception).