2026-03-28 01:19:56 +08:00

149 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Socket } from "socket.io";
import { tool } from "ai";
import { z } from "zod";
import u from "@/utils";
import Memory from "@/utils/agent/memory";
import { useSkill } from "@/utils/agent/skillsTools";
import useTools from "@/agents/productionAgent/tools";
import ResTool from "@/socket/resTool";
export interface AgentContext {
socket: Socket;
isolationKey: string;
text: string;
userMessageTime?: number;
abortSignal?: AbortSignal;
resTool: ResTool;
msg: ReturnType<ResTool["newMessage"]>;
}
function buildSystemPrompt(skillPrompt: string, mem: Awaited<ReturnType<Memory["get"]>>): string {
let memoryContext = "";
if (mem.rag.length) {
memoryContext += `[相关记忆]\n${mem.rag.map((r) => r.content).join("\n")}`;
}
if (mem.summaries.length) {
if (memoryContext) memoryContext += "\n\n";
memoryContext += `[历史摘要]\n${mem.summaries.map((s, i) => `${i + 1}. ${s.content}`).join("\n")}`;
}
if (mem.shortTerm.length) {
if (memoryContext) memoryContext += "\n\n";
memoryContext += `[近期对话]\n${mem.shortTerm.map((m) => `${m.role}: ${m.content}`).join("\n")}`;
}
if (!memoryContext) return skillPrompt;
return `${skillPrompt}\n\n## Memory\n以下是你对用户的记忆可作为参考但不要主动提及\n${memoryContext}`;
}
const subAgentList = ["executionAI", "supervisionAI"] as const;
export async function decisionAI(ctx: AgentContext) {
const { isolationKey, text, abortSignal } = ctx;
const memory = new Memory("productionAgent", isolationKey);
await memory.add("user", text);
const [skill, mem] = await Promise.all([useSkill("production_agent_decision.md"), memory.get(text)]);
const systemPrompt = buildSystemPrompt(skill.prompt, mem);
const prefixSystem = `以用户当前指令为最终目标。默认直接推进执行仅当用户明确要求新增或修改拍摄计划时才调用set_flowData更新scriptPlan并与用户确认。需要执行任务时调用run_sub_agent运行**executionAI**。`;
const { textStream } = await u.Ai.Text("productionAgent").stream({
system: prefixSystem + systemPrompt,
messages: [{ role: "user", content: text }],
abortSignal,
tools: {
...skill.tools,
...memory.getTools(),
run_sub_agent: runSubAgent(ctx),
...useTools({ resTool: ctx.resTool, msg: ctx.msg }),
},
onFinish: async (completion) => {
await memory.add("assistant:decision", completion.text);
},
});
return textStream;
}
//====================== 执行层 ======================
export async function executionAI(ctx: AgentContext) {
const { text, abortSignal } = ctx;
const skill = await useSkill("production_agent_execution.md");
const subMsg = ctx.resTool.newMessage("assistant", "执行导演");
const { textStream } = await u.Ai.Text("productionAgent").stream({
system: skill.prompt,
messages: [{ role: "user", content: text }],
abortSignal,
tools: {
...skill.tools,
...useTools({ resTool: ctx.resTool, msg: subMsg }),
},
});
return { textStream, subMsg };
}
export async function supervisionAI(ctx: AgentContext) {
const { text, abortSignal } = ctx;
const skill = await useSkill("production_agent_supervision.md");
const subMsg = ctx.resTool.newMessage("assistant", "编辑");
const { textStream } = await u.Ai.Text("scriptAgent").stream({
system: skill.prompt,
messages: [{ role: "user", content: text }],
abortSignal,
tools: {
...skill.tools,
...useTools({
resTool: ctx.resTool,
msg: subMsg,
}),
},
});
return { textStream, subMsg };
}
//工具函数
function runSubAgent(parentCtx: AgentContext) {
const memory = new Memory("scriptAgent", parentCtx.isolationKey);
return tool({
description: "启动子Agent执行独立任务。可用子Agent:executionAI, decisionAI, supervisionAI",
inputSchema: z.object({
agent: z.enum(["executionAI", "supervisionAI"]).describe("子Agent名称"),
prompt: z.string().describe("交给子Agent的任务简约描述100字以内"),
}),
execute: async ({ agent, prompt }) => {
const fn = [executionAI, supervisionAI][subAgentList.indexOf(agent)];
// 先完成主Agent当前的消息
parentCtx.msg.complete();
// 子Agent用新消息回复
const { textStream: subTextStream, subMsg } = await fn({ ...parentCtx, text: prompt });
let text = subMsg.text();
let fullResponse = "";
for await (const chunk of subTextStream) {
text.append(chunk);
fullResponse += chunk;
}
text.complete();
subMsg.complete();
if (fullResponse.trim()) {
await memory.add(`assistant:${agent === "executionAI" ? "execution" : "supervision"}`, fullResponse, {
name: agent === "executionAI" ? "编剧" : "编辑",
createTime: new Date(subMsg.datetime).getTime(),
});
}
// 为主Agent后续输出创建新消息
parentCtx.msg = parentCtx.resTool.newMessage("assistant", "统筹");
return fullResponse;
},
});
}