Initial commit
This commit is contained in:
310
templates/tool-use-basic.ts
Normal file
310
templates/tool-use-basic.ts
Normal 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 };
|
||||
Reference in New Issue
Block a user