Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:24:01 +08:00
commit 7ca465850c
24 changed files with 5512 additions and 0 deletions

310
templates/tool-use-basic.ts Normal file
View File

@@ -0,0 +1,310 @@
import Anthropic from '@anthropic-ai/sdk';
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY || '',
});
// Define tools
const tools: Anthropic.Tool[] = [
{
name: 'get_weather',
description: 'Get the current weather in a given location',
input_schema: {
type: 'object',
properties: {
location: {
type: 'string',
description: 'The city and state, e.g. San Francisco, CA',
},
unit: {
type: 'string',
enum: ['celsius', 'fahrenheit'],
description: 'The unit of temperature, either "celsius" or "fahrenheit"',
},
},
required: ['location'],
},
},
{
name: 'get_time',
description: 'Get the current time in a given timezone',
input_schema: {
type: 'object',
properties: {
timezone: {
type: 'string',
description: 'The IANA timezone name, e.g. America/Los_Angeles',
},
},
required: ['timezone'],
},
},
];
// Mock tool implementations
function executeWeatherTool(location: string, unit?: string): string {
// In production, call actual weather API
const temp = unit === 'celsius' ? 22 : 72;
return `The weather in ${location} is sunny and ${temp}°${unit === 'celsius' ? 'C' : 'F'}`;
}
function executeTimeTool(timezone: string): string {
// In production, get actual time for timezone
const time = new Date().toLocaleTimeString('en-US', { timeZone: timezone });
return `The current time in ${timezone} is ${time}`;
}
// Example 1: Basic tool use detection
async function basicToolUse() {
const message = await anthropic.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
tools,
messages: [
{
role: 'user',
content: 'What is the weather like in San Francisco?',
},
],
});
console.log('Stop reason:', message.stop_reason);
if (message.stop_reason === 'tool_use') {
console.log('\nClaude wants to use tools:');
for (const block of message.content) {
if (block.type === 'tool_use') {
console.log(`- Tool: ${block.name}`);
console.log(` ID: ${block.id}`);
console.log(` Input:`, block.input);
}
}
}
return message;
}
// Example 2: Tool execution loop
async function toolExecutionLoop(userMessage: string) {
const messages: Anthropic.MessageParam[] = [
{ role: 'user', content: userMessage },
];
while (true) {
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
tools,
messages,
});
console.log('\nStop reason:', response.stop_reason);
// Add assistant response to messages
messages.push({
role: 'assistant',
content: response.content,
});
// Check if Claude wants to use tools
if (response.stop_reason === 'tool_use') {
const toolResults: Anthropic.ToolResultBlockParam[] = [];
// Execute each tool
for (const block of response.content) {
if (block.type === 'tool_use') {
console.log(`\nExecuting tool: ${block.name}`);
console.log('Input:', block.input);
let result: string;
// Execute the appropriate tool
if (block.name === 'get_weather') {
result = executeWeatherTool(
block.input.location as string,
block.input.unit as string | undefined
);
} else if (block.name === 'get_time') {
result = executeTimeTool(block.input.timezone as string);
} else {
result = `Unknown tool: ${block.name}`;
}
console.log('Result:', result);
toolResults.push({
type: 'tool_result',
tool_use_id: block.id,
content: result,
});
}
}
// Add tool results to messages
messages.push({
role: 'user',
content: toolResults,
});
} else {
// Final response - no more tools needed
const textBlock = response.content.find(block => block.type === 'text');
if (textBlock && textBlock.type === 'text') {
console.log('\nFinal response:', textBlock.text);
return textBlock.text;
}
break;
}
}
}
// Example 3: Multiple tools in one turn
async function multipleToolsInOneTurn() {
const messages: Anthropic.MessageParam[] = [
{
role: 'user',
content: 'What is the weather in New York and what time is it in Tokyo?',
},
];
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
tools,
messages,
});
console.log('Claude requested', response.content.filter(b => b.type === 'tool_use').length, 'tools');
if (response.stop_reason === 'tool_use') {
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type === 'tool_use') {
console.log(`\n- ${block.name}:`, block.input);
let result: string;
if (block.name === 'get_weather') {
result = executeWeatherTool(block.input.location as string);
} else if (block.name === 'get_time') {
result = executeTimeTool(block.input.timezone as string);
} else {
result = 'Unknown tool';
}
toolResults.push({
type: 'tool_result',
tool_use_id: block.id,
content: result,
});
}
}
// Continue conversation with tool results
messages.push({ role: 'assistant', content: response.content });
messages.push({ role: 'user', content: toolResults });
const finalResponse = await anthropic.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
tools,
messages,
});
const textBlock = finalResponse.content.find(b => b.type === 'text');
if (textBlock && textBlock.type === 'text') {
console.log('\nFinal answer:', textBlock.text);
}
}
}
// Example 4: Error handling in tool execution
async function toolExecutionWithErrorHandling(userMessage: string) {
const messages: Anthropic.MessageParam[] = [
{ role: 'user', content: userMessage },
];
try {
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
tools,
messages,
});
messages.push({ role: 'assistant', content: response.content });
if (response.stop_reason === 'tool_use') {
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type === 'tool_use') {
try {
let result: string;
if (block.name === 'get_weather') {
result = executeWeatherTool(block.input.location as string);
} else if (block.name === 'get_time') {
result = executeTimeTool(block.input.timezone as string);
} else {
throw new Error(`Unknown tool: ${block.name}`);
}
toolResults.push({
type: 'tool_result',
tool_use_id: block.id,
content: result,
});
} catch (error) {
// Return error to Claude
toolResults.push({
type: 'tool_result',
tool_use_id: block.id,
content: `Error executing tool: ${error.message}`,
is_error: true,
});
}
}
}
messages.push({ role: 'user', content: toolResults });
// Get final response
const finalResponse = await anthropic.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
tools,
messages,
});
const textBlock = finalResponse.content.find(b => b.type === 'text');
if (textBlock && textBlock.type === 'text') {
console.log('Final response:', textBlock.text);
}
}
} catch (error) {
console.error('API error:', error);
throw error;
}
}
// Run examples
if (require.main === module) {
console.log('=== Basic Tool Use ===\n');
basicToolUse()
.then(() => {
console.log('\n\n=== Tool Execution Loop ===\n');
return toolExecutionLoop('What is the weather in London and what time is it there?');
})
.then(() => {
console.log('\n\n=== Multiple Tools ===\n');
return multipleToolsInOneTurn();
})
.then(() => {
console.log('\n\n=== Error Handling ===\n');
return toolExecutionWithErrorHandling('What is the weather in Mars?');
})
.catch(console.error);
}
export { basicToolUse, toolExecutionLoop, multipleToolsInOneTurn, toolExecutionWithErrorHandling };