UNPKG

@nomyx/assistant

Version:

A powerful assistant library and cli for your AI projects. works with Vertex AI (Claude and Gemini)

100 lines (88 loc) 3.67 kB
import axios from 'axios'; import { ChatMessage, ChatOptions, ProviderResponse } from '../../../types/chat'; import { StandardizedToolCall } from '../../../types/tool'; import { AnthropicConfig } from './config'; import { AnthropicChatRequestBody, AnthropicChatResponse, AnthropicMessageContent, AnthropicToolUseContent, Tool } from './types'; import { convertToolSchema, convertMessages } from './tools'; export async function chat( config: AnthropicConfig, messages: ChatMessage[], options: ChatOptions, tools?: Tool[] ): Promise<ProviderResponse> { const url = config.getApiUrl(); const convertedMessages = convertMessages(messages); const requestBody: AnthropicChatRequestBody = { model: config.model, messages: convertedMessages.filter(msg => msg.role !== 'system'), max_tokens: options.maxTokens || 4000, temperature: options.temperature, }; // Combine all system messages into a single system parameter const systemMessages = convertedMessages.filter(msg => msg.role === 'system'); if (systemMessages.length > 0) { requestBody.system = systemMessages.map(msg => msg.content).join('\n\n'); } if (tools && tools.length > 0) { const toolNames = tools.map(tool => tool.name).join(', '); requestBody.system = (requestBody.system || '') + `\n\nYou have access to the following tools: ${toolNames}. Use them when necessary.`; const convertedTools = tools.map(tool => convertToolSchema(tool.getSchema() as any)); requestBody.tools = convertedTools; } try { const response = await axios.post<AnthropicChatResponse>(url, requestBody, { headers: { 'Content-Type': 'application/json', 'x-api-key': config.apiKey, 'anthropic-version': '2023-06-01', }, }); return await createProviderResponse(response.data, tools || []); } catch (error) { if (axios.isAxiosError(error) && error.response) { throw new Error(`Anthropic API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`); } throw error; } } async function createProviderResponse(data: AnthropicChatResponse, tools: Tool[]): Promise<ProviderResponse> { const response: ProviderResponse = { content: '', toolCalls: [], usage: { promptTokens: data.usage?.input_tokens || 0, completionTokens: data.usage?.output_tokens || 0, totalTokens: (data.usage?.input_tokens || 0) + (data.usage?.output_tokens || 0) }, }; for (const item of data.content) { if (item.type === 'text') { response.content += item.text; } else if (item.type === 'tool_use') { const toolUse = item as AnthropicToolUseContent; const toolCall: StandardizedToolCall = { name: toolUse.name, arguments: toolUse.input, }; response.toolCalls && response.toolCalls.push(toolCall); const tool = tools.find(t => t.name === toolUse.name); if (tool) { try { const result = await tool.execute(toolUse.input, {} as any); response.content += `\n\nTool ${toolUse.name} result: ${typeof result === 'string' ? result : JSON.stringify(result)}`; } catch (error) { response.content += `\n\nError executing tool ${toolUse.name}: ${error}`; } } else { response.content += `\n\nError: Tool not found: ${toolUse.name}`; } } } // Update usage tokens with the latest data from the response response.usage = { promptTokens: data.usage?.input_tokens || 0, completionTokens: data.usage?.output_tokens || 0, totalTokens: (data.usage?.input_tokens || 0) + (data.usage?.output_tokens || 0) }; return response; }