UNPKG

@nomyx/assistant

Version:

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

132 lines (128 loc) 4.47 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.chat = chat; const axios_1 = __importDefault(require("axios")); const tools_1 = require("./tools"); const modelConfig_1 = require("./modelConfig"); async function chat(config, messages, options, tools) { const url = config.getApiUrl('chat/completions'); const model = config.model; const logger = config.getLogger(); const requestBody = { messages: (0, tools_1.convertMessages)(messages).map(msg => ({ ...msg, content: convertContentToOpenRouterFormat(msg.content) })), model: model, max_tokens: options.maxTokens || (0, modelConfig_1.getMaxTokens)(model), temperature: options.temperature, stream: false }; const modelSupportsTools = (0, modelConfig_1.supportsTools)(model); if (tools && tools.length > 0) { if (modelSupportsTools) { requestBody.tools = tools.map(tool => (0, tools_1.convertToolSchema)(tool.getSchema())); requestBody.tool_choice = 'auto'; } else { // Append instructions for using tools const toolInstructions = ` You have access to the following tools: ${tools.map(tool => `- ${tool.name}: ${tool.description}`).join('\n')} To use a tool, output a function call in a code block like this: \`\`\`function_call { "name": "tool_name", "arguments": { "arg1": "value1", "arg2": "value2" } } \`\`\` Replace "tool_name" with the actual tool name and provide the necessary arguments. For example, to use the "tool_name" tool with arguments "arg1" and "arg2": \`\`\`function_call { "name": "tool_name", "arguments": { "arg1": "value1", "arg2": "value2" } } \`\`\ `; requestBody.messages[requestBody.messages.length - 1].content += '\n\n' + toolInstructions; } } const headers = { ...config.getHeaders(), 'HTTP-Referer': config.httpReferer, 'X-Title': config.xTitle }; logger.debug('OpenRouter API request', { url, model, toolsCount: tools?.length }); try { const response = await axios_1.default.post(url, requestBody, { headers }); logger.debug('OpenRouter API response received', { status: response.status }); return createProviderResponse(response.data, modelSupportsTools, logger); } catch (error) { if (axios_1.default.isAxiosError(error)) { logger.error('OpenRouter API error', { status: error.response?.status, statusText: error.response?.statusText, data: error.response?.data }); } else { logger.error('OpenRouter API error', { error }); } throw error; } } function createProviderResponse(data, modelSupportsTools, logger) { const choice = data.choices[0]; if (!choice) { throw new Error('Unexpected response format from OpenRouter API'); } const message = choice.message || { role: 'assistant', content: '' }; let content = message.content || ''; let toolCalls = modelSupportsTools ? (0, tools_1.extractToolCalls)(message) : []; if (!modelSupportsTools) { const functionCallRegex = /```function_call\n([\s\S]*?)```/g; let match; while ((match = functionCallRegex.exec(content)) !== null) { try { const functionCall = JSON.parse(match[1]); toolCalls.push({ name: functionCall.name, arguments: functionCall.arguments }); } catch (error) { logger.error('Error parsing function call', { error }); } } content = content.replace(functionCallRegex, ''); } return { content: content.trim(), toolCalls: toolCalls, usage: { promptTokens: data.usage?.prompt_tokens || 0, completionTokens: data.usage?.completion_tokens || 0, totalTokens: data.usage?.total_tokens || 0 }, }; } function convertContentToOpenRouterFormat(content) { if (typeof content === 'string') { return content; } return content.map(part => ({ type: part.type, content: part[part.type] })); }