# 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.