Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:16:40 +08:00
commit f125e90b9f
370 changed files with 67769 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
# Changelog
## 0.2.0
- Refactored to Anthropic progressive disclosure pattern
- Updated description with "Use PROACTIVELY when..." format
- Removed version/author/category/tags from frontmatter
## 0.1.0
- Initial release of Strict Tool Implementer skill
- Complete workflow covering tool schema design, multi-tool agents, and production deployment
- Multi-tool agent implementation patterns
- Error handling for tool failures and refusals
- Testing strategies for agentic workflows
- Travel booking agent example (multi-tool workflow)

View File

@@ -0,0 +1,81 @@
# Strict Tool Implementer
Specialized skill for implementing strict tool use mode with guaranteed parameter validation.
## Purpose
This skill handles **end-to-end implementation** of strict tool use mode (`strict: true`), ensuring tool input parameters strictly follow your schema. Essential for building reliable agentic workflows with type-safe tool execution.
## Use Cases
- **Multi-Tool Agents**: Travel booking, research assistants, etc.
- **Validated Function Calls**: Ensure parameters match expected types
- **Complex Tool Schemas**: Tools with nested properties
- **Critical Operations**: Financial transactions, booking systems
- **Tool Composition**: Sequential and parallel tool execution
## Prerequisites
- Routed here by `structured-outputs-advisor`
- Model: Claude Sonnet 4.5 or Opus 4.1
- Beta header: `structured-outputs-2025-11-13`
## Quick Start
**Python:**
```python
response = client.beta.messages.create(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
messages=[{"role": "user", "content": "Search for flights..."}],
tools=[{
"name": "search_flights",
"description": "Search for available flights",
"strict": True, # Enable strict validation
"input_schema": {
"type": "object",
"properties": {
"origin": {"type": "string"},
"destination": {"type": "string"},
"travelers": {"type": "integer", "enum": [1, 2, 3, 4, 5, 6]}
},
"required": ["origin", "destination", "travelers"],
"additionalProperties": False
}
}]
)
# Tool inputs GUARANTEED to match schema
for block in response.content:
if block.type == "tool_use":
execute_tool(block.name, block.input) # Type-safe!
```
## What You'll Learn
1. **Tool Schema Design** - With `strict: true` and proper validation
2. **Multi-Tool Workflows** - Sequential and parallel tool execution
3. **Agent Patterns** - Stateful agents, retry logic, validation
4. **Error Handling** - Tool failures, refusals, edge cases
5. **Production Deployment** - Monitoring, testing, reliability
## Examples
- [travel-booking-agent.py](./examples/travel-booking-agent.py) - Multi-tool agent workflow
## Related Skills
- [`structured-outputs-advisor`](../structured-outputs-advisor/) - Choose the right mode
- [`json-outputs-implementer`](../json-outputs-implementer/) - For data extraction
## Reference Materials
- [JSON Schema Limitations](../reference/json-schema-limitations.md)
- [Best Practices](../reference/best-practices.md)
- [API Compatibility](../reference/api-compatibility.md)
## Version
Current version: 0.1.0
See [CHANGELOG.md](./CHANGELOG.md) for version history.

View File

@@ -0,0 +1,92 @@
---
name: strict-tool-implementer
description: >-
Use PROACTIVELY when building multi-step agentic workflows with validated tool parameters.
Implements Anthropic's strict tool use mode for guaranteed schema compliance.
Covers tool schema design, multi-tool agent workflows, error handling, testing, and production patterns.
Not for data extraction or classification tasks (use json-outputs-implementer instead).
---
# Strict Tool Implementer
## Overview
This skill implements Anthropic's strict tool use mode for reliable agentic systems. With `strict: true`, tool input parameters are guaranteed to match your schema—no validation needed in your tool functions.
**What This Skill Provides:**
- Production-ready tool schema design
- Multi-tool workflow patterns
- Agentic system architecture
- Validation and error handling
- Complete agent implementation examples
**Prerequisites:**
- Decision made via `structured-outputs-advisor`
- Model: Claude Sonnet 4.5 or Opus 4.1
- Beta header: `structured-outputs-2025-11-13`
## When to Use This Skill
**Use for:**
- Building multi-step agentic workflows
- Validating function call parameters
- Ensuring type-safe tool execution
- Complex tools with nested properties
- Critical operations requiring guaranteed types
**NOT for:**
- Extracting data from text/images → `json-outputs-implementer`
- Formatting API responses → `json-outputs-implementer`
- Classification tasks → `json-outputs-implementer`
## Response Style
- **Tool-focused**: Design tools with clear, validated schemas
- **Agent-aware**: Consider multi-tool workflows and composition
- **Type-safe**: Guarantee parameter types for downstream functions
- **Production-ready**: Handle errors, retries, and monitoring
- **Example-driven**: Provide complete agent implementations
## Workflow
| Phase | Description | Details |
|-------|-------------|---------|
| 1 | Tool Schema Design | → [workflow/phase-1-schema-design.md](workflow/phase-1-schema-design.md) |
| 2 | Multi-Tool Agent Implementation | → [workflow/phase-2-implementation.md](workflow/phase-2-implementation.md) |
| 3 | Error Handling & Validation | → [workflow/phase-3-error-handling.md](workflow/phase-3-error-handling.md) |
| 4 | Testing Agent Workflows | → [workflow/phase-4-testing.md](workflow/phase-4-testing.md) |
| 5 | Production Agent Patterns | → [workflow/phase-5-production.md](workflow/phase-5-production.md) |
## Quick Reference
### Schema Template
```python
{
"name": "tool_name",
"description": "Clear description",
"strict": True,
"input_schema": {
"type": "object",
"properties": {...},
"required": [...],
"additionalProperties": False
}
}
```
### Supported Schema Features
✅ Basic types, enums, format strings, nested objects/arrays, required fields
❌ Recursive schemas, min/max constraints, string length, complex regex
## Reference Materials
- [Common Agentic Patterns](reference/common-patterns.md)
- [Success Criteria](reference/success-criteria.md)
## Related Skills
- `structured-outputs-advisor` - Choose the right mode
- `json-outputs-implementer` - For data extraction use cases

View File

@@ -0,0 +1,289 @@
"""
Travel Booking Agent Example
Multi-tool agent using strict tool use mode for guaranteed parameter validation.
Demonstrates validated tool inputs in agentic workflows.
"""
from anthropic import Anthropic
from typing import Dict, Any, List
import json
import os
client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
# Define tools with strict mode
TOOLS = [
{
"name": "search_flights",
"description": "Search for available flights between two cities",
"strict": True, # Enable strict parameter validation
"input_schema": {
"type": "object",
"properties": {
"origin": {
"type": "string",
"description": "Departure city (e.g., 'San Francisco, CA')"
},
"destination": {
"type": "string",
"description": "Arrival city (e.g., 'Paris, France')"
},
"departure_date": {
"type": "string",
"format": "date",
"description": "Departure date in YYYY-MM-DD format"
},
"return_date": {
"type": "string",
"format": "date",
"description": "Return date in YYYY-MM-DD format (optional for one-way)"
},
"travelers": {
"type": "integer",
"enum": [1, 2, 3, 4, 5, 6],
"description": "Number of travelers"
}
},
"required": ["origin", "destination", "departure_date", "travelers"],
"additionalProperties": False # Required for strict mode
}
},
{
"name": "book_flight",
"description": "Book a selected flight",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"flight_id": {
"type": "string",
"description": "Flight identifier from search results"
},
"passenger_names": {
"type": "array",
"items": {"type": "string"},
"description": "Full names of all passengers"
},
"contact_email": {
"type": "string",
"format": "email",
"description": "Contact email for booking confirmation"
}
},
"required": ["flight_id", "passenger_names", "contact_email"],
"additionalProperties": False
}
},
{
"name": "search_hotels",
"description": "Search for hotels in a city",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "City name"
},
"check_in": {
"type": "string",
"format": "date",
"description": "Check-in date in YYYY-MM-DD format"
},
"check_out": {
"type": "string",
"format": "date",
"description": "Check-out date in YYYY-MM-DD format"
},
"guests": {
"type": "integer",
"enum": [1, 2, 3, 4],
"description": "Number of guests"
}
},
"required": ["city", "check_in", "check_out", "guests"],
"additionalProperties": False
}
}
]
# Mock tool implementations
def search_flights(origin: str, destination: str, departure_date: str,
travelers: int, return_date: str = None) -> Dict:
"""Mock flight search - would call real API."""
print(f"🔍 Searching flights: {origin}{destination}")
print(f" Departure: {departure_date}, Travelers: {travelers}")
return {
"flights": [
{
"id": "FL123",
"airline": "Air France",
"departure": f"{departure_date} 10:00",
"arrival": f"{departure_date} 23:00",
"price": 850.00,
"class": "Economy"
},
{
"id": "FL456",
"airline": "United",
"departure": f"{departure_date} 14:30",
"arrival": f"{departure_date} 03:30+1",
"price": 920.00,
"class": "Economy"
}
]
}
def book_flight(flight_id: str, passenger_names: List[str],
contact_email: str) -> Dict:
"""Mock flight booking - would call real API."""
print(f"✈️ Booking flight {flight_id}")
print(f" Passengers: {', '.join(passenger_names)}")
print(f" Email: {contact_email}")
return {
"confirmation": "ABC123XYZ",
"status": "confirmed",
"total_price": 850.00 * len(passenger_names)
}
def search_hotels(city: str, check_in: str, check_out: str, guests: int) -> Dict:
"""Mock hotel search - would call real API."""
print(f"🏨 Searching hotels in {city}")
print(f" Check-in: {check_in}, Check-out: {check_out}, Guests: {guests}")
return {
"hotels": [
{
"id": "HTL789",
"name": "Grand Hotel Paris",
"rating": 4.5,
"price_per_night": 200.00,
"amenities": ["WiFi", "Breakfast", "Gym"]
},
{
"id": "HTL101",
"name": "Budget Inn",
"rating": 3.5,
"price_per_night": 80.00,
"amenities": ["WiFi"]
}
]
}
# Tool registry
TOOL_FUNCTIONS = {
"search_flights": search_flights,
"book_flight": book_flight,
"search_hotels": search_hotels,
}
def run_travel_agent(user_request: str, max_turns: int = 10):
"""
Run travel booking agent with strict tool validation.
With strict mode enabled, all tool inputs are GUARANTEED to match
the schema - no validation needed in tool functions!
"""
messages = [{"role": "user", "content": user_request}]
print("=" * 70)
print(f"User Request: {user_request}")
print("=" * 70)
for turn in range(max_turns):
print(f"\n🤖 Agent Turn {turn + 1}")
response = client.beta.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
betas=["structured-outputs-2025-11-13"],
messages=messages,
tools=TOOLS,
)
# Check stop reason
if response.stop_reason == "end_turn":
# Agent finished
final_text = ""
for block in response.content:
if hasattr(block, "text"):
final_text += block.text
print(f"\n✅ Agent Complete:")
print(f"{final_text}")
return final_text
if response.stop_reason == "tool_use":
# Execute tools
tool_results = []
for block in response.content:
if block.type == "text":
print(f"\n💭 Agent: {block.text}")
elif block.type == "tool_use":
tool_name = block.name
tool_input = block.input # GUARANTEED to match schema!
print(f"\n🔧 Tool Call: {tool_name}")
print(f" Input: {json.dumps(tool_input, indent=2)}")
# Execute tool with validated inputs
tool_function = TOOL_FUNCTIONS[tool_name]
result = tool_function(**tool_input) # Type-safe!
print(f" Result: {json.dumps(result, indent=2)}")
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result)
})
# Add to conversation
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
else:
print(f"⚠️ Unexpected stop reason: {response.stop_reason}")
break
print("\n⚠️ Max turns reached without completion")
return None
def main():
"""Run travel agent examples."""
examples = [
"Book a round trip from San Francisco to Paris for 2 people, "
"departing May 15, 2024 and returning May 22, 2024. "
"Passengers are John Smith and Jane Doe. "
"Email confirmation to john.smith@example.com. "
"Also find a hotel in Paris for those dates.",
"Find flights from New York to London for 1 traveler on June 1, 2024.",
"Search for hotels in Tokyo for 2 guests, checking in July 10 "
"and checking out July 15.",
]
for i, request in enumerate(examples, 1):
print(f"\n\n{'='*70}")
print(f"EXAMPLE {i}")
print(f"{'='*70}")
run_travel_agent(request)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,48 @@
# Common Agentic Patterns
## Pattern 1: Sequential Workflow
Tools execute in sequence (search → book → confirm):
```python
# User: "Book a flight to Paris"
# Agent executes:
1. search_flights(origin="SF", destination="Paris", ...)
2. book_flight(flight_id="F1", passengers=[...])
3. send_confirmation(confirmation_id="ABC123")
```
## Pattern 2: Parallel Tool Execution
Multiple independent tools (flights + hotels):
```python
# User: "Find flights and hotels for Paris trip"
# Agent can call in parallel (if your implementation supports it):
1. search_flights(destination="Paris", ...)
2. search_hotels(city="Paris", ...)
```
## Pattern 3: Conditional Branching
Tool selection based on context:
```python
# User: "Plan my trip"
# Agent decides which tools to call based on conversation:
if budget_conscious:
search_flights(class="economy")
else:
search_flights(class="business")
```
## Important Reminders
1. **Always set `strict: true`** - This enables validation
2. **Require `additionalProperties: false`** - Enforced by strict mode
3. **Use enums for constrained values** - Better than free text
4. **Clear descriptions matter** - Claude uses these to decide when to call tools
5. **Tool inputs are guaranteed valid** - No validation needed in tool functions
6. **Handle tool execution failures** - External APIs can fail
7. **Test multi-step workflows** - Edge cases appear in tool composition
8. **Monitor agent behavior** - Track tool usage patterns and failures

View File

@@ -0,0 +1,23 @@
# Success Criteria
## Implementation Checklist
- [ ] Tool schemas designed with `strict: true`
- [ ] All tools have `additionalProperties: false`
- [ ] Clear descriptions for tools and parameters
- [ ] Required fields properly specified
- [ ] Multi-tool workflow implemented
- [ ] Error handling for tool failures
- [ ] Refusal scenarios handled
- [ ] Agent tested with realistic scenarios
- [ ] Production patterns applied (retry, validation)
- [ ] Monitoring in place
## Official Documentation
https://docs.anthropic.com/en/docs/build-with-claude/structured-outputs
## Related Skills
- `structured-outputs-advisor` - Choose the right mode
- `json-outputs-implementer` - For data extraction use cases

View File

@@ -0,0 +1,125 @@
# Phase 1: Tool Schema Design
**Objective**: Design validated tool schemas for your agent
## Steps
### 1. Identify Required Tools
Ask the user:
- "What actions should the agent be able to perform?"
- "What external systems will the agent interact with?"
- "What parameters does each tool need?"
**Example agent**: Travel booking
- `search_flights` - Find available flights
- `book_flight` - Reserve a flight
- `search_hotels` - Find hotels
- `book_hotel` - Reserve accommodation
### 2. Design Tool Schema with `strict: true`
**Template:**
```python
{
"name": "tool_name",
"description": "Clear description of what this tool does",
"strict": True, # ← Enables strict mode
"input_schema": {
"type": "object",
"properties": {
"param_name": {
"type": "string",
"description": "Clear parameter description"
}
},
"required": ["param_name"],
"additionalProperties": False # ← Required
}
}
```
**Example: Flight Search Tool**
```python
{
"name": "search_flights",
"description": "Search for available flights between two cities",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"origin": {
"type": "string",
"description": "Departure city (e.g., 'San Francisco, CA')"
},
"destination": {
"type": "string",
"description": "Arrival city (e.g., 'Paris, France')"
},
"departure_date": {
"type": "string",
"format": "date",
"description": "Departure date in YYYY-MM-DD format"
},
"return_date": {
"type": "string",
"format": "date",
"description": "Return date in YYYY-MM-DD format (optional)"
},
"travelers": {
"type": "integer",
"enum": [1, 2, 3, 4, 5, 6],
"description": "Number of travelers"
},
"class": {
"type": "string",
"enum": ["economy", "premium", "business", "first"],
"description": "Flight class preference"
}
},
"required": ["origin", "destination", "departure_date", "travelers"],
"additionalProperties": False
}
}
```
### 3. Apply JSON Schema Limitations
**✅ Supported:**
- All basic types (object, array, string, integer, number, boolean)
- `enum` for constrained values
- `format` for strings (date, email, uri, uuid, etc.)
- Nested objects and arrays
- `required` fields
- `additionalProperties: false` (required!)
**❌ NOT Supported:**
- Recursive schemas
- Numerical constraints (minimum, maximum)
- String length constraints
- Complex regex patterns
### 4. Add Clear Descriptions
Good descriptions help Claude:
- Understand when to call the tool
- Know what values to provide
- Format parameters correctly
```python
# ✅ Good: Clear and specific
"origin": {
"type": "string",
"description": "Departure city and state/country (e.g., 'San Francisco, CA')"
}
# ❌ Vague: Not helpful
"origin": {
"type": "string",
"description": "Origin"
}
```
## Output
Well-designed tool schemas ready for implementation.

View File

@@ -0,0 +1,222 @@
# Phase 2: Multi-Tool Agent Implementation
**Objective**: Implement agent with multiple validated tools
## Python Implementation
```python
from anthropic import Anthropic
from typing import Dict, Any, List
client = Anthropic()
# Define tools
TOOLS = [
{
"name": "search_flights",
"description": "Search for available flights",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"origin": {"type": "string", "description": "Departure city"},
"destination": {"type": "string", "description": "Arrival city"},
"departure_date": {"type": "string", "format": "date"},
"travelers": {"type": "integer", "enum": [1, 2, 3, 4, 5, 6]}
},
"required": ["origin", "destination", "departure_date", "travelers"],
"additionalProperties": False
}
},
{
"name": "book_flight",
"description": "Book a selected flight",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"flight_id": {"type": "string", "description": "Flight identifier"},
"passengers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"passport": {"type": "string"}
},
"required": ["name", "passport"],
"additionalProperties": False
}
}
},
"required": ["flight_id", "passengers"],
"additionalProperties": False
}
},
{
"name": "search_hotels",
"description": "Search for hotels in a city",
"strict": True,
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"},
"check_in": {"type": "string", "format": "date"},
"check_out": {"type": "string", "format": "date"},
"guests": {"type": "integer", "enum": [1, 2, 3, 4]}
},
"required": ["city", "check_in", "check_out", "guests"],
"additionalProperties": False
}
}
]
# Tool execution functions
def search_flights(origin: str, destination: str, departure_date: str, travelers: int) -> Dict:
"""Execute flight search - calls actual API."""
# Implementation here
return {"flights": [...]}
def book_flight(flight_id: str, passengers: List[Dict]) -> Dict:
"""Book the flight - calls actual API."""
# Implementation here
return {"confirmation": "ABC123", "status": "confirmed"}
def search_hotels(city: str, check_in: str, check_out: str, guests: int) -> Dict:
"""Search hotels - calls actual API."""
# Implementation here
return {"hotels": [...]}
# Tool registry
TOOL_FUNCTIONS = {
"search_flights": search_flights,
"book_flight": book_flight,
"search_hotels": search_hotels,
}
# Agent loop
def run_agent(user_request: str, max_turns: int = 10):
"""Run agent with tool validation."""
messages = [{"role": "user", "content": user_request}]
for turn in range(max_turns):
response = client.beta.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
betas=["structured-outputs-2025-11-13"],
messages=messages,
tools=TOOLS,
)
# Process response
if response.stop_reason == "end_turn":
# Agent finished
return extract_final_answer(response)
if response.stop_reason == "tool_use":
# Execute tools
tool_results = []
for block in response.content:
if block.type == "tool_use":
# Tool input is GUARANTEED to match schema
tool_name = block.name
tool_input = block.input # Already validated!
# Execute tool
tool_function = TOOL_FUNCTIONS[tool_name]
result = tool_function(**tool_input) # Type-safe!
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": str(result)
})
# Add assistant response and tool results to conversation
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
else:
raise Exception(f"Unexpected stop reason: {response.stop_reason}")
raise Exception("Max turns reached")
# Usage
result = run_agent("Book a flight from SF to Paris for 2 people, departing May 15")
print(result)
```
## TypeScript Implementation
```typescript
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const TOOLS: Anthropic.Tool[] = [
{
name: "search_flights",
description: "Search for available flights",
strict: true,
input_schema: {
type: "object",
properties: {
origin: { type: "string", description: "Departure city" },
destination: { type: "string", description: "Arrival city" },
departure_date: { type: "string", format: "date" },
travelers: { type: "integer", enum: [1, 2, 3, 4, 5, 6] }
},
required: ["origin", "destination", "departure_date", "travelers"],
additionalProperties: false
}
},
// ... other tools
];
async function runAgent(userRequest: string, maxTurns: number = 10) {
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: userRequest }
];
for (let turn = 0; turn < maxTurns; turn++) {
const response = await client.beta.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 2048,
betas: ["structured-outputs-2025-11-13"],
messages,
tools: TOOLS,
});
if (response.stop_reason === "end_turn") {
return extractFinalAnswer(response);
}
if (response.stop_reason === "tool_use") {
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type === "tool_use") {
// Input guaranteed to match schema!
const result = await executeTool(block.name, block.input);
toolResults.push({
type: "tool_result",
tool_use_id: block.id,
content: JSON.stringify(result)
});
}
}
messages.push({ role: "assistant", content: response.content });
messages.push({ role: "user", content: toolResults });
}
}
throw new Error("Max turns reached");
}
```
## Output
Working multi-tool agent with validated tool schemas.

View File

@@ -0,0 +1,58 @@
# Phase 3: Error Handling & Validation
**Objective**: Handle errors and edge cases in agent workflows
## Key Error Scenarios
### 1. Tool Execution Failures
```python
def execute_tool_safely(tool_name: str, tool_input: Dict) -> Dict:
"""Execute tool with error handling."""
try:
tool_function = TOOL_FUNCTIONS[tool_name]
result = tool_function(**tool_input)
return {"success": True, "data": result}
except Exception as e:
logger.error(f"Tool {tool_name} failed: {e}")
return {
"success": False,
"error": str(e),
"message": "Tool execution failed. Please try again."
}
```
### 2. Safety Refusals
```python
if response.stop_reason == "refusal":
logger.warning("Agent refused request")
# Don't retry - respect safety boundaries
return {"error": "Request cannot be completed"}
```
### 3. Max Turns Exceeded
```python
if turn >= max_turns:
logger.warning("Agent exceeded max turns")
return {
"error": "Task too complex",
"partial_progress": extract_progress(messages)
}
```
### 4. Invalid Tool Name
```python
# With strict mode, tool names are guaranteed valid
# But external factors can cause issues
if tool_name not in TOOL_FUNCTIONS:
logger.error(f"Unknown tool: {tool_name}")
return {"error": f"Tool {tool_name} not implemented"}
```
## Output
Robust error handling for production agent workflows.

View File

@@ -0,0 +1,81 @@
# Phase 4: Testing Agent Workflows
**Objective**: Validate agent behavior with realistic scenarios
## Test Strategy
```python
import pytest
from unittest.mock import Mock, patch
@pytest.fixture
def mock_tool_functions():
"""Mock external tool functions."""
return {
"search_flights": Mock(return_value={"flights": [{"id": "F1", "price": 500}]}),
"book_flight": Mock(return_value={"confirmation": "ABC123"}),
"search_hotels": Mock(return_value={"hotels": [{"id": "H1", "price": 150}]}),
}
def test_simple_flight_search(mock_tool_functions):
"""Test agent handles simple flight search."""
with patch.dict('agent.TOOL_FUNCTIONS', mock_tool_functions):
result = run_agent("Find flights from SF to LA on May 15 for 2 people")
# Verify search_flights was called
mock_tool_functions["search_flights"].assert_called_once()
call_args = mock_tool_functions["search_flights"].call_args[1]
# Strict mode guarantees these match schema
assert call_args["origin"] == "San Francisco, CA" # or similar
assert call_args["destination"] == "Los Angeles, CA"
assert call_args["travelers"] == 2
assert "2024-05-15" in call_args["departure_date"]
def test_multi_step_booking(mock_tool_functions):
"""Test agent completes multi-step booking."""
with patch.dict('agent.TOOL_FUNCTIONS', mock_tool_functions):
result = run_agent(
"Book a round trip from SF to Paris for 2 people, "
"May 15-22, and find a hotel"
)
# Verify correct tool sequence
assert mock_tool_functions["search_flights"].called
assert mock_tool_functions["book_flight"].called
assert mock_tool_functions["search_hotels"].called
def test_tool_failure_handling(mock_tool_functions):
"""Test agent handles tool failures gracefully."""
mock_tool_functions["search_flights"].side_effect = Exception("API down")
with patch.dict('agent.TOOL_FUNCTIONS', mock_tool_functions):
result = run_agent("Find flights to Paris")
# Should handle error gracefully
assert "error" in result or "failed" in str(result).lower()
def test_parameter_validation():
"""Test that strict mode guarantees valid parameters."""
# With strict mode, parameters are guaranteed to match schema
# This test verifies the guarantee holds
response = client.beta.messages.create(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
messages=[{"role": "user", "content": "Search flights for 2 people"}],
tools=TOOLS,
)
for block in response.content:
if block.type == "tool_use":
# These assertions should NEVER fail with strict mode
assert isinstance(block.input, dict)
assert "travelers" in block.input
assert isinstance(block.input["travelers"], int)
assert block.input["travelers"] in [1, 2, 3, 4, 5, 6]
```
## Output
Comprehensive test coverage for agent workflows.

View File

@@ -0,0 +1,98 @@
# Phase 5: Production Agent Patterns
**Objective**: Production-ready agent architectures
## Pattern 1: Stateful Agent with Memory
```python
class StatefulTravelAgent:
"""Agent that maintains state across interactions."""
def __init__(self):
self.conversation_history: List[Dict] = []
self.booking_state: Dict[str, Any] = {}
def chat(self, user_message: str) -> str:
"""Process user message and return response."""
self.conversation_history.append({
"role": "user",
"content": user_message
})
response = client.beta.messages.create(
model="claude-sonnet-4-5",
betas=["structured-outputs-2025-11-13"],
max_tokens=2048,
messages=self.conversation_history,
tools=TOOLS,
)
# Process tools and update state
final_response = self._process_response(response)
self.conversation_history.append({
"role": "assistant",
"content": final_response
})
return final_response
def _process_response(self, response) -> str:
"""Process tool calls and maintain state."""
# Implementation...
pass
# Usage
agent = StatefulTravelAgent()
print(agent.chat("I want to go to Paris"))
print(agent.chat("For 2 people")) # Remembers context
print(agent.chat("May 15 to May 22")) # Continues booking
```
## Pattern 2: Tool Retry Logic
```python
def execute_tool_with_retry(
tool_name: str,
tool_input: Dict,
max_retries: int = 3
) -> Dict:
"""Execute tool with exponential backoff retry."""
import time
for attempt in range(max_retries):
try:
tool_func = TOOL_FUNCTIONS[tool_name]
result = tool_func(**tool_input)
return {"success": True, "data": result}
except Exception as e:
if attempt == max_retries - 1:
return {"success": False, "error": str(e)}
wait_time = 2 ** attempt # Exponential backoff
logger.warning(f"Tool {tool_name} failed, retrying in {wait_time}s")
time.sleep(wait_time)
```
## Pattern 3: Tool Result Validation
```python
def validate_tool_result(tool_name: str, result: Any) -> bool:
"""Validate tool execution result."""
validators = {
"search_flights": lambda r: "flights" in r and len(r["flights"]) > 0,
"book_flight": lambda r: "confirmation" in r,
"search_hotels": lambda r: "hotels" in r,
}
validator = validators.get(tool_name)
if validator:
return validator(result)
return True # No validator = assume valid
```
## Output
Production-ready agent patterns with state management, retry logic, and validation.