Initial commit
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
import Anthropic from '@anthropic-ai/sdk';
|
||||
import type { Tool, ToolResult, Message, AgentConfig } from '../types/index.js';
|
||||
|
||||
export class Agent {
|
||||
private client: Anthropic;
|
||||
private config: AgentConfig;
|
||||
private tools: Map<string, Tool> = new Map();
|
||||
private conversationHistory: Message[] = [];
|
||||
|
||||
constructor(config: AgentConfig) {
|
||||
this.config = config;
|
||||
this.client = new Anthropic({
|
||||
apiKey: config.apiKey,
|
||||
});
|
||||
}
|
||||
|
||||
// 注册工具
|
||||
registerTool(tool: Tool): void {
|
||||
this.tools.set(tool.name, tool);
|
||||
}
|
||||
|
||||
// 获取所有工具定义(用于 Claude API)
|
||||
private getToolDefinitions(): Anthropic.Tool[] {
|
||||
return Array.from(this.tools.values()).map((tool) => ({
|
||||
name: tool.name,
|
||||
description: tool.description,
|
||||
input_schema: {
|
||||
type: 'object' as const,
|
||||
properties: Object.fromEntries(
|
||||
Object.entries(tool.parameters).map(([key, param]) => [
|
||||
key,
|
||||
{
|
||||
type: param.type,
|
||||
description: param.description,
|
||||
},
|
||||
])
|
||||
),
|
||||
required: Object.entries(tool.parameters)
|
||||
.filter(([, param]) => param.required)
|
||||
.map(([key]) => key),
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
// 执行工具
|
||||
private async executeTool(
|
||||
toolName: string,
|
||||
input: Record<string, unknown>
|
||||
): Promise<ToolResult> {
|
||||
const tool = this.tools.get(toolName);
|
||||
if (!tool) {
|
||||
return {
|
||||
success: false,
|
||||
output: '',
|
||||
error: `Tool "${toolName}" not found`,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
return await tool.execute(input);
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
output: '',
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 发送消息并处理响应
|
||||
async chat(
|
||||
userMessage: string,
|
||||
onStream?: (text: string) => void
|
||||
): Promise<string> {
|
||||
// 添加用户消息到历史
|
||||
this.conversationHistory.push({
|
||||
role: 'user',
|
||||
content: userMessage,
|
||||
});
|
||||
|
||||
const messages: Anthropic.MessageParam[] = this.conversationHistory.map(
|
||||
(msg) => ({
|
||||
role: msg.role,
|
||||
content: msg.content,
|
||||
})
|
||||
);
|
||||
|
||||
let fullResponse = '';
|
||||
|
||||
// 循环处理,直到没有工具调用
|
||||
while (true) {
|
||||
const response = await this.client.messages.create({
|
||||
model: this.config.model,
|
||||
max_tokens: this.config.maxTokens,
|
||||
system: this.config.systemPrompt,
|
||||
tools: this.getToolDefinitions(),
|
||||
messages,
|
||||
});
|
||||
|
||||
// 处理响应内容
|
||||
const textBlocks: string[] = [];
|
||||
const toolUseBlocks: Anthropic.ToolUseBlock[] = [];
|
||||
|
||||
for (const block of response.content) {
|
||||
if (block.type === 'text') {
|
||||
textBlocks.push(block.text);
|
||||
if (onStream) {
|
||||
onStream(block.text);
|
||||
}
|
||||
} else if (block.type === 'tool_use') {
|
||||
toolUseBlocks.push(block);
|
||||
}
|
||||
}
|
||||
|
||||
fullResponse += textBlocks.join('');
|
||||
|
||||
// 如果没有工具调用,结束循环
|
||||
if (toolUseBlocks.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 添加 assistant 消息
|
||||
messages.push({
|
||||
role: 'assistant',
|
||||
content: response.content,
|
||||
});
|
||||
|
||||
// 处理工具调用
|
||||
const toolResults: Anthropic.ToolResultBlockParam[] = [];
|
||||
|
||||
for (const toolUse of toolUseBlocks) {
|
||||
if (onStream) {
|
||||
onStream(`\n[调用工具: ${toolUse.name}]\n`);
|
||||
}
|
||||
|
||||
const result = await this.executeTool(
|
||||
toolUse.name,
|
||||
toolUse.input as Record<string, unknown>
|
||||
);
|
||||
|
||||
if (onStream) {
|
||||
onStream(
|
||||
result.success ? `[结果: ${result.output}]\n` : `[错误: ${result.error}]\n`
|
||||
);
|
||||
}
|
||||
|
||||
toolResults.push({
|
||||
type: 'tool_result',
|
||||
tool_use_id: toolUse.id,
|
||||
content: result.success ? result.output : `Error: ${result.error}`,
|
||||
});
|
||||
}
|
||||
|
||||
// 添加工具结果
|
||||
messages.push({
|
||||
role: 'user',
|
||||
content: toolResults,
|
||||
});
|
||||
}
|
||||
|
||||
// 保存助手响应到历史
|
||||
this.conversationHistory.push({
|
||||
role: 'assistant',
|
||||
content: fullResponse,
|
||||
});
|
||||
|
||||
return fullResponse;
|
||||
}
|
||||
|
||||
// 清空对话历史
|
||||
clearHistory(): void {
|
||||
this.conversationHistory = [];
|
||||
}
|
||||
|
||||
// 获取对话历史
|
||||
getHistory(): Message[] {
|
||||
return [...this.conversationHistory];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user