Files
gh-jezweb-claude-skills-ski…/templates/tool-use-advanced.ts
2025-11-30 08:24:01 +08:00

297 lines
8.1 KiB
TypeScript

import Anthropic from '@anthropic-ai/sdk';
import { betaZodTool } from '@anthropic-ai/sdk/helpers/zod';
import { z } from 'zod';
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY || '',
});
// Example 1: Using Zod schemas with betaZodTool
const weatherTool = betaZodTool({
name: 'get_weather',
inputSchema: z.object({
location: z.string().describe('The city and state, e.g. San Francisco, CA'),
unit: z.enum(['celsius', 'fahrenheit']).optional().describe('Temperature unit'),
}),
description: 'Get the current weather in a given location',
run: async (input) => {
// Mock implementation - replace with actual API call
console.log(`Fetching weather for ${input.location}...`);
const temp = input.unit === 'celsius' ? 22 : 72;
return `The weather in ${input.location} is sunny and ${temp}°${input.unit || 'F'}`;
},
});
const searchTool = betaZodTool({
name: 'search_web',
inputSchema: z.object({
query: z.string().describe('The search query'),
max_results: z.number().int().min(1).max(10).optional().describe('Maximum number of results'),
}),
description: 'Search the web for information',
run: async (input) => {
console.log(`Searching for: ${input.query}...`);
// Mock implementation
return `Found ${input.max_results || 5} results for "${input.query}":
1. Example result 1
2. Example result 2
3. Example result 3`;
},
});
const calculatorTool = betaZodTool({
name: 'calculate',
inputSchema: z.object({
expression: z.string().describe('Mathematical expression to evaluate'),
}),
description: 'Evaluate a mathematical expression',
run: async (input) => {
try {
// WARNING: eval is dangerous - this is just for demonstration
// In production, use a safe math parser like math.js
const result = eval(input.expression);
return `${input.expression} = ${result}`;
} catch (error) {
throw new Error(`Invalid expression: ${input.expression}`);
}
},
});
// Example 2: Using toolRunner for automatic execution
async function automaticToolExecution() {
const finalMessage = await anthropic.beta.messages.toolRunner({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1000,
messages: [
{
role: 'user',
content: 'What is the weather in Tokyo? Also, search for "best sushi restaurants in Tokyo"',
},
],
tools: [weatherTool, searchTool],
});
console.log('\nFinal response:');
for (const block of finalMessage.content) {
if (block.type === 'text') {
console.log(block.text);
}
}
return finalMessage;
}
// Example 3: Streaming with tools
async function streamingWithTools() {
const runner = anthropic.beta.messages.toolRunner({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1000,
messages: [
{
role: 'user',
content: 'Calculate 123 * 456, then tell me about the result',
},
],
tools: [calculatorTool],
stream: true,
});
console.log('Streaming response:');
// Iterate through messages as they arrive
for await (const messageStream of runner) {
// Each message can have multiple events
for await (const event of messageStream) {
if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
process.stdout.write(event.delta.text);
}
}
console.log('\n\nMessage completed');
}
// Get final result
const result = await runner;
console.log('\nFinal result:', result);
}
// Example 4: Complex tool chain
const databaseTool = betaZodTool({
name: 'query_database',
inputSchema: z.object({
query: z.string().describe('SQL query to execute'),
}),
description: 'Query the database',
run: async (input) => {
console.log(`Executing SQL: ${input.query}`);
// Mock database response
return JSON.stringify([
{ id: 1, name: 'Product A', price: 29.99 },
{ id: 2, name: 'Product B', price: 49.99 },
]);
},
});
const emailTool = betaZodTool({
name: 'send_email',
inputSchema: z.object({
to: z.string().email().describe('Recipient email address'),
subject: z.string().describe('Email subject'),
body: z.string().describe('Email body'),
}),
description: 'Send an email',
run: async (input) => {
console.log(`Sending email to ${input.to}...`);
// Mock email sending
return `Email sent successfully to ${input.to}`;
},
});
async function complexToolChain() {
const finalMessage = await anthropic.beta.messages.toolRunner({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 2000,
messages: [
{
role: 'user',
content:
'Query the database for all products, calculate their average price, and send me an email with the results to test@example.com',
},
],
tools: [databaseTool, calculatorTool, emailTool],
});
console.log('\nTool chain completed');
for (const block of finalMessage.content) {
if (block.type === 'text') {
console.log(block.text);
}
}
}
// Example 5: Tool with max iterations limit
async function toolsWithMaxIterations() {
try {
const finalMessage = await anthropic.beta.messages.toolRunner({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1000,
max_iterations: 3, // Limit tool execution loops
messages: [
{
role: 'user',
content: 'Search for "quantum computing" and then search for each result',
},
],
tools: [searchTool],
});
console.log('Completed with max_iterations limit');
for (const block of finalMessage.content) {
if (block.type === 'text') {
console.log(block.text);
}
}
} catch (error) {
console.error('Max iterations reached or error occurred:', error);
}
}
// Example 6: Custom tool runner with manual control
async function manualToolRunner() {
const runner = anthropic.beta.messages.toolRunner({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1000,
messages: [
{
role: 'user',
content: 'What is 15 * 27?',
},
],
tools: [calculatorTool],
});
// Manually iterate through messages
for await (const message of runner) {
console.log('\nReceived message');
console.log('Stop reason:', message.stop_reason);
// Generate tool response if needed
const toolResponse = await runner.generateToolResponse();
if (toolResponse) {
console.log('Tool results:', toolResponse.content);
}
// Can inspect and modify the conversation here
console.log('Current params:', runner.params);
}
// Wait for completion
const finalMessage = await runner.done();
console.log('\nFinal message:', finalMessage);
}
// Example 7: Error recovery in tools
const unreliableTool = betaZodTool({
name: 'unreliable_api',
inputSchema: z.object({
data: z.string(),
}),
description: 'An API that sometimes fails',
run: async (input) => {
// Randomly fail to demonstrate error handling
if (Math.random() < 0.3) {
throw new Error('API temporarily unavailable');
}
return `Processed: ${input.data}`;
},
});
async function toolWithErrorRecovery() {
try {
const finalMessage = await anthropic.beta.messages.toolRunner({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1000,
messages: [
{
role: 'user',
content: 'Process this data with the unreliable API: "test data"',
},
],
tools: [unreliableTool],
});
console.log('Success:', finalMessage.content);
} catch (error) {
console.error('Tool execution failed:', error);
// Implement retry logic or fallback
}
}
// Run examples
if (require.main === module) {
console.log('=== Automatic Tool Execution ===\n');
automaticToolExecution()
.then(() => {
console.log('\n\n=== Streaming with Tools ===\n');
return streamingWithTools();
})
.then(() => {
console.log('\n\n=== Complex Tool Chain ===\n');
return complexToolChain();
})
.then(() => {
console.log('\n\n=== Manual Tool Runner ===\n');
return manualToolRunner();
})
.catch(console.error);
}
export {
automaticToolExecution,
streamingWithTools,
complexToolChain,
toolsWithMaxIterations,
manualToolRunner,
toolWithErrorRecovery,
};