- localization-svc: defaultLocale ru, resolveLocale only by geo - web-svc: DEFAULT_LOCALE ru, layout lang=ru, embeddedTranslations fallback ru - countryToLocale: default ru when no country or unknown country Co-authored-by: Cursor <cursoragent@cursor.com>
107 lines
2.7 KiB
TypeScript
107 lines
2.7 KiB
TypeScript
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<MasterAgentOutput> {
|
|
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
|
|
? `<recent_conversation>\n${historyStr}\n</recent_conversation>\n\n<current_task>\n${input.task}\n</current_task>`
|
|
: 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,
|
|
};
|
|
}
|