UNPKG

@unified-llm/core

Version:
312 lines 13.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AnthropicProvider = void 0; const sdk_1 = __importDefault(require("@anthropic-ai/sdk")); const base_provider_1 = __importDefault(require("../base-provider")); const validation_1 = require("../../utils/validation"); // Anthropic実装 class AnthropicProvider extends base_provider_1.default { constructor({ apiKey, model, tools }) { super({ model, tools }); this.client = new sdk_1.default({ apiKey }); } async chat(request) { (0, validation_1.validateChatRequest)(request); try { const anthropicRequest = await this.convertToAnthropicFormat(request); let response = await this.client.messages.create(anthropicRequest); let messages = [...anthropicRequest.messages]; // stop_reason が 'tool_use' の場合、ツールを実行して結果を返す while (response.stop_reason === 'tool_use' && this.tools) { const toolUseBlocks = response.content.filter(block => block.type === 'tool_use'); const toolResults = []; for (const toolBlock of toolUseBlocks) { const customFunction = this.tools.find(func => func.function.name === toolBlock.name); if (customFunction) { try { // CustomFunctionのargsとtool_useのinputをマージ const mergedArgs = { ...(customFunction.args || {}), ...toolBlock.input }; const result = await customFunction.handler(mergedArgs); toolResults.push({ type: 'tool_result', tool_use_id: toolBlock.id, content: typeof result === 'string' ? result : JSON.stringify(result), }); } catch (error) { toolResults.push({ type: 'tool_result', tool_use_id: toolBlock.id, is_error: true, content: error instanceof Error ? error.message : 'Unknown error', }); } } } // ツール実行結果を含めて再度リクエスト if (toolResults.length > 0) { messages = [ ...messages, { role: 'assistant', content: response.content, }, { role: 'user', content: toolResults, }, ]; const followUpRequest = { ...anthropicRequest, messages: messages, }; response = await this.client.messages.create(followUpRequest); } else { // ツール結果がない場合はループを抜ける break; } } return this.convertFromAnthropicFormat(response); } catch (error) { throw this.handleError(error); } } async *stream(request) { (0, validation_1.validateChatRequest)(request); const anthropicRequest = await this.convertToAnthropicFormat(request); const stream = await this.client.messages.create({ ...anthropicRequest, stream: true, }); for await (const chunk of stream) { if (chunk.type === 'content_block_delta' && chunk.delta.type === 'text_delta') { yield this.convertStreamChunk(chunk); } } } async convertToAnthropicFormat(request) { var _a, _b, _c, _d, _e, _f; if (!request.model && !this.model) { throw new Error('Model is required for Anthropic requests'); } const systemMessage = request.messages.find(m => m.role === 'system'); const otherMessages = request.messages.filter(m => m.role !== 'system'); const messages = await Promise.all(otherMessages.map(async (msg) => { const content = this.normalizeContent(msg.content); const anthropicContent = await Promise.all(content.map(async (c) => { var _a, _b; switch (c.type) { case 'text': return { type: 'text', text: c.text }; case 'image': return { type: 'image', source: { type: (c.source.url ? 'url' : 'base64'), media_type: c.source.media_type || 'image/jpeg', data: c.source.data, url: c.source.url, }, }; case 'tool_use': { // customFunctionsからツールを検索して実行 const customFunction = (_a = this.tools) === null || _a === void 0 ? void 0 : _a.find(func => func.function.name === c.name); if (customFunction) { try { // CustomFunctionのargsとtool_useのinputをマージ const mergedArgs = { ...(customFunction.args || {}), ...c.input }; const result = await customFunction.handler(mergedArgs); return { type: 'tool_result', tool_use_id: c.id, is_error: false, content: [{ type: 'text', text: typeof result === 'string' ? result : JSON.stringify(result), }], }; } catch (error) { return { type: 'tool_result', tool_use_id: c.id, is_error: true, content: [{ type: 'text', text: error instanceof Error ? error.message : 'Unknown error', }], }; } } return { type: 'tool_use', id: c.id, name: c.name, input: c.input, }; } case 'tool_result': return { type: 'tool_result', tool_use_id: c.tool_use_id, is_error: c.is_error, content: ((_b = c.content) === null || _b === void 0 ? void 0 : _b.map(tc => ({ type: 'text', text: tc.type === 'text' ? tc.text : '[Unsupported content]', }))) || [], }; default: return { type: 'text', text: '[Unsupported content type]' }; } })); return { role: msg.role === 'assistant' ? 'assistant' : 'user', content: anthropicContent, }; })); // toolsの結合: request.toolsとcustomFunctionsを統合 const tools = [ ...(((_a = request.tools) === null || _a === void 0 ? void 0 : _a.map(tool => ({ name: tool.function.name, description: tool.function.description || '', input_schema: { type: 'object', ...tool.function.parameters || {}, }, }))) || []), ...(this.tools ? this.tools.map((func) => ({ name: func.function.name, description: func.function.description || '', input_schema: { type: 'object', ...func.function.parameters || {}, }, })) : []), ]; return { model: request.model || this.model, messages: messages, system: systemMessage ? this.extractTextFromContent(systemMessage.content) : undefined, max_tokens: ((_b = request.generation_config) === null || _b === void 0 ? void 0 : _b.max_tokens) || 4096, temperature: (_c = request.generation_config) === null || _c === void 0 ? void 0 : _c.temperature, top_p: (_d = request.generation_config) === null || _d === void 0 ? void 0 : _d.top_p, top_k: (_e = request.generation_config) === null || _e === void 0 ? void 0 : _e.top_k, stop_sequences: (_f = request.generation_config) === null || _f === void 0 ? void 0 : _f.stop_sequences, tools: tools.length > 0 ? tools : undefined, }; } convertFromAnthropicFormat(response) { const content = response.content.map(block => { switch (block.type) { case 'text': return { type: 'text', text: block.text }; case 'tool_use': return { type: 'tool_use', id: block.id, name: block.name, input: block.input, }; default: return { type: 'text', text: '[Unknown content type]' }; } }); const unifiedMessage = { id: response.id, role: response.role, content, created_at: new Date(), }; const usage = { input_tokens: response.usage.input_tokens, output_tokens: response.usage.output_tokens, total_tokens: response.usage.input_tokens + response.usage.output_tokens, }; return { id: response.id, model: response.model, provider: 'anthropic', message: unifiedMessage, usage, finish_reason: response.stop_reason, created_at: new Date(), raw_response: response, }; } convertStreamChunk(chunk) { if (!this.model) { throw new Error('Model is required for streaming responses'); } const content = [{ type: 'text', text: chunk.delta.text, }]; const unifiedMessage = { id: this.generateMessageId(), role: 'assistant', content, created_at: new Date(), }; return { id: this.generateMessageId(), model: this.model, provider: 'anthropic', message: unifiedMessage, created_at: new Date(), raw_response: chunk, }; } extractTextFromContent(content) { if (typeof content === 'string') return content; const textContent = content.find(c => c.type === 'text'); return (textContent === null || textContent === void 0 ? void 0 : textContent.text) || ''; } handleError(error) { var _a; if (error instanceof sdk_1.default.APIError) { const errorBody = (_a = error.error) === null || _a === void 0 ? void 0 : _a.error; return { code: (errorBody === null || errorBody === void 0 ? void 0 : errorBody.type) || 'anthropic_error', message: (errorBody === null || errorBody === void 0 ? void 0 : errorBody.message) || error.message, type: this.mapErrorType(error.status), status_code: error.status, provider: 'anthropic', details: error, }; } return { code: 'unknown_error', message: error.message || 'Unknown error occurred', type: 'api_error', provider: 'anthropic', details: error, }; } mapErrorType(status) { if (!status) return 'api_error'; if (status === 429) return 'rate_limit'; if (status === 401) return 'authentication'; if (status >= 400 && status < 500) return 'invalid_request'; if (status >= 500) return 'server_error'; return 'api_error'; } } exports.AnthropicProvider = AnthropicProvider; //# sourceMappingURL=provider.js.map