From 6047368080c5c5e6d3d6199edcd6d4a25063693b Mon Sep 17 00:00:00 2001 From: uxname Date: Sat, 24 May 2025 15:09:24 +0300 Subject: [PATCH] feat: Implement tool calls and error handling in pipeline execution --- src/index.ts | 85 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 19 deletions(-) diff --git a/src/index.ts b/src/index.ts index b1d48a7..32b4c32 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,8 @@ -import { HumanMessage, SystemMessage } from '@langchain/core/messages'; +import { + HumanMessage, + SystemMessage, + ToolMessage, +} from '@langchain/core/messages'; import { Runnable } from '@langchain/core/runnables'; import { DynamicStructuredTool } from '@langchain/core/tools'; import { ChatOpenAI } from '@langchain/openai'; @@ -23,6 +27,7 @@ class MockMcpToolsService { description: 'Возвращает введенную строку.', schema: z.object({ input: z.string().describe('Строка для эхо.') }), func: async (input: { input: string }) => { + console.log(`Вызов инструмента 'echo' с входом: ${input.input}`); return input.input; }, }); @@ -32,6 +37,7 @@ class MockMcpToolsService { description: 'Возвращает текущую дату в формате ISO.', schema: z.object({}), func: async () => { + console.log('Вызов инструмента "get_current_date"'); return new Date().toISOString(); }, }); @@ -82,15 +88,14 @@ class PipelineExecutor { async executeChain(params: { pipeline: Pipeline; - variables: Record; - systemPrompts: string[]; + variables?: Record; + systemPrompts?: string[]; openAIApiKey: string; }): Promise { - const variables = params.variables === undefined ? {} : params.variables; - const systemPrompts = - params.systemPrompts === undefined ? [] : params.systemPrompts; + const variables = params.variables ?? {}; + const systemPrompts = params.systemPrompts ?? []; const chain = await this.initChain(params.openAIApiKey); - const messages = this.buildMessages( + const initialMessages = this.buildMessages( [params.pipeline.systemPrompt, ...systemPrompts], variables, ); @@ -98,10 +103,48 @@ class PipelineExecutor { for (const { prompt } of params.pipeline.steps) { const renderedPrompt = this.renderPrompt(prompt, variables); - console.log({ renderedPrompt }); - const stepMessages = [...messages, new HumanMessage(renderedPrompt)]; - const response = await chain.invoke(stepMessages); - results.push(response?.content ?? ''); + const currentMessages = [ + ...initialMessages, + new HumanMessage(renderedPrompt), + ]; + let response = await chain.invoke(currentMessages); + + while (response.tool_calls && response.tool_calls.length > 0) { + const toolCalls = response.tool_calls; + currentMessages.push(response); + + for (const toolCall of toolCalls) { + try { + const tools = await this.mcpToolsService.getTools(); + const tool = tools.find((t) => t.name === toolCall.name); + + if (!tool) { + throw new Error(`Tool ${toolCall.name} not found`); + } + + const toolResult = await tool.func(toolCall.args); + currentMessages.push( + new ToolMessage({ + tool_call_id: toolCall.id, + content: JSON.stringify(toolResult), + }), + ); + } catch (error) { + console.error( + `Ошибка выполнения инструмента ${toolCall.name}:`, + error, + ); + currentMessages.push( + new ToolMessage({ + tool_call_id: toolCall.id, + content: `Error: ${error.message}`, + }), + ); + } + } + response = await chain.invoke(currentMessages); + } + results.push(response?.content ?? ''); } return results; } @@ -138,7 +181,7 @@ async function main() { name: 'Получение даты', prompt: 'Какая сейчас дата? Используй инструмент `get_current_date`.', }, - { name: 'Завершение', prompt: 'Подтверди, что все шаги выполнены.' }, + { name: 'Завершение', prompt: 'Напиши резюме, что ты сделал' }, ], }; @@ -148,13 +191,17 @@ async function main() { const systemPrompts = ['Отвечай кратко и по существу.']; - const results = await pipelineExecutor.executeChain({ - pipeline: testPipeline, - variables: variables, - systemPrompts: systemPrompts, - openAIApiKey: openAIApiKey, - }); - console.log('Результаты выполнения пайплайна:', results); + try { + const results = await pipelineExecutor.executeChain({ + pipeline: testPipeline, + variables: variables, + systemPrompts: systemPrompts, + openAIApiKey: openAIApiKey, + }); + console.log('Результаты выполнения пайплайна:', results); + } catch (error) { + console.error('Ошибка при выполнении пайплайна:', error); + } } main().catch(console.error);