import type { BaseLLM } from '../models/base/llm.js'; import type { Message } from '../types.js'; import { getTools, getTool, getToolSchemasForLLM } from '../tools/registry.js'; import type { AgentContext } from '../tools/types.js'; import { MASTER_SYSTEM_PROMPT } from '../prompts/master.js'; export type MasterAgentInput = { task: string; chatHistory?: [string, string][]; context: AgentContext; maxSteps?: number; }; export type MasterAgentOutput = { content: string; steps: number; } export async function runMasterAgent( llm: BaseLLM, input: MasterAgentInput, ): Promise { const maxSteps = input.maxSteps ?? 15; const tools = getTools(); const toolSchemas = getToolSchemasForLLM(); const historyStr = input.chatHistory?.length ? input.chatHistory .slice(-6) .map(([role, content]) => `${role === 'human' ? 'User' : 'Assistant'}: ${content}`) .join('\n') : ''; const userContent = historyStr ? `\n${historyStr}\n\n\n\n${input.task}\n` : input.task; const messages: Message[] = [ { role: 'system', content: MASTER_SYSTEM_PROMPT }, { role: 'user', content: userContent }, ]; let steps = 0; while (steps < maxSteps) { steps += 1; const result = await llm.generateText({ messages, tools: toolSchemas, }); if (result.toolCalls.length === 0) { return { content: result.content.trim() || 'Нет ответа.', steps, }; } messages.push({ role: 'assistant', content: result.content, tool_calls: result.toolCalls, }); for (const tc of result.toolCalls) { const tool = getTool(tc.name); if (!tool) { messages.push({ role: 'tool', id: tc.id, name: tc.name, content: JSON.stringify({ error: `Unknown tool: ${tc.name}` }), }); continue; } let toolResult: string; try { toolResult = await tool.execute(tc.arguments, input.context); } catch (err) { toolResult = JSON.stringify({ error: err instanceof Error ? err.message : String(err), }); } messages.push({ role: 'tool', id: tc.id, name: tc.name, content: toolResult.length > 12000 ? toolResult.slice(0, 12000) + '\n...[truncated]' : toolResult, }); } } const finalResult = await llm.generateText({ messages, tools: [], }); return { content: finalResult.content.trim() || 'Достигнут лимит шагов. Попробуйте уточнить запрос.', steps, }; }