From de362e03128c81e38f9ddfd796dacf661eecab88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ACT=E4=B8=B6=E6=B5=81=E6=98=9F=E9=9B=A8?= <1340145680@qq.com> Date: Mon, 30 Mar 2026 23:45:58 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E8=AE=B0=E5=BF=86=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/test/test.ts | 2 +- src/socket/routes/productionAgent.ts | 87 +++++++++++++--------------- src/socket/routes/scriptAgent.ts | 85 +++++++++++++-------------- src/utils/ai.ts | 46 ++++++++++----- 4 files changed, 115 insertions(+), 105 deletions(-) diff --git a/src/routes/test/test.ts b/src/routes/test/test.ts index 21d4b99..58de179 100644 --- a/src/routes/test/test.ts +++ b/src/routes/test/test.ts @@ -23,7 +23,7 @@ function buildMemPrompt(mem: Awaited>): string { export default router.get("/", async (req, res) => { - const isolationKey = "test"; + const isolationKey = "1:productionAgent:1"; const input = "你好" const memory = new Memory("productionAgent", isolationKey); diff --git a/src/socket/routes/productionAgent.ts b/src/socket/routes/productionAgent.ts index 367f7b8..c2b183d 100644 --- a/src/socket/routes/productionAgent.ts +++ b/src/socket/routes/productionAgent.ts @@ -3,7 +3,6 @@ import u from "@/utils"; import { Namespace, Socket } from "socket.io"; import * as agent from "@/agents/productionAgent/index"; import ResTool from "@/socket/resTool"; -import Memory from "@/utils/agent/memory"; async function verifyToken(rawToken: string): Promise { const setting = await u.db("o_setting").where("key", "tokenKey").select("value").first(); @@ -57,7 +56,6 @@ export default (nsp: Namespace) => { abortController?.abort(); abortController = new AbortController(); const currentController = abortController; - const memory = new Memory("scriptAgent", isolationKey); const msg = resTool.newMessage("assistant", "视频策划"); const ctx: agent.AgentContext = { @@ -70,54 +68,51 @@ export default (nsp: Namespace) => { msg, }; - const textStream = await agent.decisionAI(ctx); - - let currentMsg = ctx.msg; - let text = currentMsg.text(); - let currentContent = ""; - - const persistCurrentMessage = async () => { - if (!currentContent.trim()) return; - await memory.add("assistant:decision", currentContent, { - name: "视频策划", - createTime: new Date(currentMsg.datetime).getTime(), - }); - currentContent = ""; - }; - - const syncCurrentMessage = async () => { - if (ctx.msg === currentMsg) return; - text.complete(); - currentMsg.complete(); - await persistCurrentMessage(); - currentMsg = ctx.msg; - text = currentMsg.text(); - }; - - let aborted = false; try { - for await (const chunk of textStream) { - await syncCurrentMessage(); - text.append(chunk); - currentContent += chunk; - } - } catch (err: any) { - if (err.name === "AbortError" || currentController.signal.aborted) { - aborted = true; - } else { - throw err; - } - } finally { - await syncCurrentMessage(); - if (aborted) { - text.append("[已停止]"); - text.complete(); - currentMsg.stop(); - } else { + const textStream = await agent.decisionAI(ctx); + + let currentMsg = ctx.msg; + let text = currentMsg.text(); + + const syncCurrentMessage = () => { + if (ctx.msg === currentMsg) return; text.complete(); currentMsg.complete(); + currentMsg = ctx.msg; + text = currentMsg.text(); + }; + + let aborted = false; + try { + for await (const chunk of textStream) { + syncCurrentMessage(); + text.append(chunk); + } + } catch (err: any) { + if (err.name === "AbortError" || currentController.signal.aborted) { + aborted = true; + } else { + throw err; + } + } finally { + syncCurrentMessage(); + if (aborted) { + text.append("[已停止]"); + text.complete(); + currentMsg.stop(); + } else { + text.complete(); + currentMsg.complete(); + } } - await persistCurrentMessage(); + } catch (err: any) { + if (err.name !== "AbortError" && !currentController.signal.aborted) { + const errorMsg = u.error(err).message; + console.error("[productionAgent] chat error:", errorMsg); + ctx.msg.text(errorMsg).complete(); + ctx.msg.error(); + } + } finally { if (abortController === currentController) { abortController = null; } diff --git a/src/socket/routes/scriptAgent.ts b/src/socket/routes/scriptAgent.ts index 0da1c56..8450881 100644 --- a/src/socket/routes/scriptAgent.ts +++ b/src/socket/routes/scriptAgent.ts @@ -3,7 +3,6 @@ import u from "@/utils"; import { Namespace, Socket } from "socket.io"; import * as agent from "@/agents/scriptAgent/index"; import ResTool from "@/socket/resTool"; -import Memory from "@/utils/agent/memory"; async function verifyToken(rawToken: string): Promise { const setting = await u.db("o_setting").where("key", "tokenKey").select("value").first(); @@ -46,7 +45,6 @@ export default (nsp: Namespace) => { abortController?.abort(); abortController = new AbortController(); const currentController = abortController; - const memory = new Memory("scriptAgent", isolationKey); const msg = resTool.newMessage("assistant", "统筹"); const ctx: agent.AgentContext = { @@ -59,53 +57,50 @@ export default (nsp: Namespace) => { msg, }; - const textStream = await agent.decisionAI(ctx); - - let currentMsg = ctx.msg; - let text = currentMsg.text(); - let currentContent = ""; - - const persistCurrentMessage = async () => { - if (!currentContent.trim()) return; - await memory.add("assistant:decision", currentContent, { - name: "统筹", - createTime: new Date(currentMsg.datetime).getTime(), - }); - currentContent = ""; - }; - - const syncCurrentMessage = async () => { - if (ctx.msg === currentMsg) return; - text.complete(); - currentMsg.complete(); - await persistCurrentMessage(); - currentMsg = ctx.msg; - text = currentMsg.text(); - }; - - let aborted = false; try { - for await (const chunk of textStream) { - await syncCurrentMessage(); - text.append(chunk); - currentContent += chunk; - } - } catch (err: any) { - if (err.name === "AbortError" || currentController.signal.aborted) { - aborted = true; - } else { - throw err; - } - } finally { - await syncCurrentMessage(); - if (aborted) { - text.complete(); - currentMsg.stop(); - } else { + const textStream = await agent.decisionAI(ctx); + + let currentMsg = ctx.msg; + let text = currentMsg.text(); + + const syncCurrentMessage = () => { + if (ctx.msg === currentMsg) return; text.complete(); currentMsg.complete(); + currentMsg = ctx.msg; + text = currentMsg.text(); + }; + + let aborted = false; + try { + for await (const chunk of textStream) { + syncCurrentMessage(); + text.append(chunk); + } + } catch (err: any) { + if (err.name === "AbortError" || currentController.signal.aborted) { + aborted = true; + } else { + throw err; + } + } finally { + syncCurrentMessage(); + if (aborted) { + text.complete(); + currentMsg.stop(); + } else { + text.complete(); + currentMsg.complete(); + } } - await persistCurrentMessage(); + } catch (err: any) { + if (err.name !== "AbortError" && !currentController.signal.aborted) { + const errorMsg = u.error(err).message; + console.error("[scriptAgent] chat error:", errorMsg); + ctx.msg.text(errorMsg).complete(); + ctx.msg.error(); + } + } finally { if (abortController === currentController) { abortController = null; } diff --git a/src/utils/ai.ts b/src/utils/ai.ts index 4f3548d..958d43b 100644 --- a/src/utils/ai.ts +++ b/src/utils/ai.ts @@ -25,7 +25,12 @@ async function getVendorTemplateFn(fnName: FnName, modelName: `${string}:${strin const selectedModel = modelList.find((i: any) => i.modelName == name); if (!selectedModel) throw new Error(`未找到模型 ${name} id=${id}`); const jsCode = transform(vendorConfigData.code!, { transforms: ["typescript"] }).code; - const fn = u.vm(jsCode)[fnName]; + const running = u.vm(jsCode); + if (running.vendor) { + Object.assign(running.vendor.inputValues, JSON.parse(vendorConfigData.inputValues ?? "{}")); + running.vendor.models = modelList; + } + const fn = running[fnName]; if (!fn) throw new Error(`未找到供应商配置中的函数 ${fnName} id=${id}`); if (fnName == "textRequest") return fn(selectedModel); else return (input: T) => fn(input, selectedModel); @@ -115,13 +120,18 @@ class AiImage { constructor(key: `${string}:${string}`) { this.key = key; } - async run(input: ImageConfig, taskRecord: TaskRecord) { - return withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, async (modelName) => { - const fn = await getVendorTemplateFn("imageRequest", modelName); + async run(input: ImageConfig, taskRecord?: TaskRecord) { + const modelName = await resolveModelName(this.key); + const exec = async (mn: `${string}:${string}`) => { + const fn = await getVendorTemplateFn("imageRequest", mn); this.result = await fn(input); if (this.result.startsWith("http")) this.result = await urlToBase64(this.result); return this; - }); + }; + if (taskRecord) { + return withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, exec); + } + return exec(modelName); } async save(path: string) { await u.oss.writeFile(path, this.result); @@ -144,13 +154,18 @@ class AiVideo { constructor(key: `${string}:${string}`) { this.key = key; } - async run(input: VideoConfig, taskRecord: TaskRecord) { - return withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, async (modelName) => { - const fn = await getVendorTemplateFn("videoRequest", modelName); + async run(input: VideoConfig, taskRecord?: TaskRecord) { + const modelName = await resolveModelName(this.key); + const exec = async (mn: `${string}:${string}`) => { + const fn = await getVendorTemplateFn("videoRequest", mn); this.result = await fn(input); if (this.result.startsWith("http")) this.result = await urlToBase64(this.result); return this; - }); + }; + if (taskRecord) { + return withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, exec); + } + return exec(modelName); } async save(path: string) { await u.oss.writeFile(path, this.result); @@ -163,13 +178,18 @@ class AiAudio { constructor(key: `${string}:${string}`) { this.key = key; } - async run(input: VideoConfig, taskRecord: TaskRecord) { - return withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, async (modelName) => { - const fn = await getVendorTemplateFn("ttsRequest", modelName); + async run(input: VideoConfig, taskRecord?: TaskRecord) { + const modelName = await resolveModelName(this.key); + const exec = async (mn: `${string}:${string}`) => { + const fn = await getVendorTemplateFn("ttsRequest", mn); this.result = await fn(input); if (this.result.startsWith("http")) this.result = await urlToBase64(this.result); return this; - }); + }; + if (taskRecord) { + return withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, exec); + } + return exec(modelName); } async save(path: string) { await u.oss.writeFile(path, this.result);