From 86dbd144936c14abc285ed218c6aeaafc9dd8fbd Mon Sep 17 00:00:00 2001
From: zhishi <1951671751@qq.com>
Date: Fri, 27 Mar 2026 01:36:21 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E5=8E=BB=E9=99=A4think?=
=?UTF-8?q?=E6=A0=87=E7=AD=BE=20=E6=96=B9=E6=B3=95=20=EF=BC=88=E6=9C=AA?=
=?UTF-8?q?=E4=BD=BF=E7=94=A8=EF=BC=89=EF=BC=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/agents/productionAgent/index.ts | 1 +
src/agents/scriptAgent/index.ts | 6 +-
src/agents/scriptAgent/tools.ts | 59 +++++-----
.../assetsGenerate/polishAssetsPrompt.ts | 1 +
src/types/database.d.ts | 34 +++++-
src/utils/stripThink.ts | 106 ++++++++++++++++++
6 files changed, 179 insertions(+), 28 deletions(-)
create mode 100644 src/utils/stripThink.ts
diff --git a/src/agents/productionAgent/index.ts b/src/agents/productionAgent/index.ts
index 465a15f..709df70 100644
--- a/src/agents/productionAgent/index.ts
+++ b/src/agents/productionAgent/index.ts
@@ -123,6 +123,7 @@ function runSubAgent(parentCtx: AgentContext) {
prompt: z.string().max(100).describe("交给子Agent的任务简约描述"),
}),
execute: async ({ agent, prompt }) => {
+ //todo 传入md有问题
const fn = [executionAI, supervisionAI][subAgentList.indexOf(agent)];
//运行子Agent
const subTextStream = await fn({ ...parentCtx, text: prompt });
diff --git a/src/agents/scriptAgent/index.ts b/src/agents/scriptAgent/index.ts
index df0a344..e507e7f 100644
--- a/src/agents/scriptAgent/index.ts
+++ b/src/agents/scriptAgent/index.ts
@@ -46,7 +46,7 @@ export async function decisionAI(ctx: AgentContext) {
const systemPrompt = buildSystemPrompt(skill.prompt, mem);
const projectData = await u.db("o_project").where("id", resTool.data.projectId).first();
- const novelData = await u.db("o_novel").select("id", "chapterIndex as index");
+ const novelData = await u.db("o_novel").where("projectId", resTool.data.projectId).select("id", "chapterIndex as index");
const projectInfo = [
"## 项目信息",
@@ -70,6 +70,7 @@ export async function decisionAI(ctx: AgentContext) {
...useTools(ctx.resTool),
},
onFinish: async (completion) => {
+ console.log("%c Line:73 🍧 completion", "background:#93c0a4", completion);
await memory.add("assistant:decision", completion.text);
},
});
@@ -99,6 +100,7 @@ export async function executionAI(ctx: AgentContext) {
...useTools(ctx.resTool),
},
onFinish: async (completion) => {
+ console.log("%c Line:102 🍻 completion", "background:#fca650", completion);
await memory.add("assistant:execution", completion.text);
},
});
@@ -125,6 +127,7 @@ export async function supervisionAI(ctx: AgentContext) {
...useTools(ctx.resTool),
},
onFinish: async (completion) => {
+ console.log("%c Line:129 🍣 completion", "background:#3f7cff", completion);
await memory.add("assistant:supervision", completion.text);
},
});
@@ -149,6 +152,7 @@ function runSubAgent(parentCtx: AgentContext) {
let fullResponse = "";
for await (const chunk of subTextStream) {
+ console.log("%c Line:155 🥛 chunk", "background:#fca650", chunk);
msg.send(chunk);
fullResponse += chunk;
}
diff --git a/src/agents/scriptAgent/tools.ts b/src/agents/scriptAgent/tools.ts
index a5be947..420416e 100644
--- a/src/agents/scriptAgent/tools.ts
+++ b/src/agents/scriptAgent/tools.ts
@@ -12,7 +12,7 @@ export const AssetSchema = z.object({
type: z.enum(["role", "tool", "scene", "clip"]).describe("资产类型"),
});
export const ScriptSchema = z.object({
- id: z.number().describe("剧本ID,如果新增则为空").optional(),
+ id: z.number().describe("剧本ID"),
name: z.string().describe("剧本名称"),
content: z.string().describe("剧本内容"),
});
@@ -42,7 +42,7 @@ export default (resTool: ResTool, toolsNames?: string[]) => {
console.log("[tools] get_novel_events", ids);
const data = await u
.db("o_novel")
- .where("projectId",resTool.data.projectId)
+ .where("projectId", resTool.data.projectId)
.select("id", "chapterIndex as index", "reel", "chapter", "chapterData", "event", "eventState")
.whereIn("id", ids);
const eventString = data.map((i: any) => [`第${i.index}章,标题:${i.chapter},事件:${i.event}`].join("\n")).join("\n");
@@ -91,41 +91,48 @@ export default (resTool: ResTool, toolsNames?: string[]) => {
return true;
},
}),
- insert_script_to_sqlite: tool({
- description: "将剧本内容插入sqlite数据库,供后续业务使用",
+ update_script_to_sqlite: tool({
+ description: "更新剧本,修改数据库对应剧本,供后续业务使用",
inputSchema: z.object({
script: ScriptSchema,
- // assetsList: z.array(AssetSchema).describe("剧本所使用资产列表,注意不要包含剧本内容,仅为所使用到的 道具、人物、场景、素材"),
}),
execute: async ({ script }) => {
console.log("%c Line:103 🍷 script", "background:#42b983", script);
- // console.log("[tools] insert_script_to_sqlite", assetsList);
+ await u.db("o_script").where({ id: script.id }).update({
+ name: script.name,
+ content: script.content,
+ });
+
+ socket.emit("setPlanData", { key: "script", value: script.id });
+ return true;
+ },
+ }),
+ insert_script_to_sqlite: tool({
+ description: "新增剧本,将剧本内容插入sqlite数据库,供后续业务使用",
+ inputSchema: z.object({
+ script: ScriptSchema.omit({ id: true }),
+ }),
+ execute: async ({ script }) => {
+ console.log("%c Line:103 🍷 script", "background:#42b983", script);
+
const [scriptId] = await u.db("o_script").insert({
name: script.name,
content: script.content,
projectId: resTool.data.projectId,
createTime: Date.now(),
});
- // if (assetsList && assetsList.length) {
- // const assetId = [];
- // for (const i of assetsList) {
- // if (i.id) {
- // assetId.push(i.id);
- // continue;
- // }
- // const [id] = await u.db("o_assets").insert({
- // name: i.name,
- // prompt: i.prompt,
- // type: i.type,
- // describe: i.desc,
- // projectId: resTool.data.projectId,
- // startTime: Date.now(),
- // });
- // assetId.push(id);
- // }
-
- // await u.db("o_scriptAssets").insert(assetId.map((i) => ({ scriptId, assetId: i })));
- // }
+ socket.emit("setPlanData", { key: "script", value: scriptId });
+ return true;
+ },
+ }),
+ delete_script_to_sqlite: tool({
+ description: "删除剧本,将剧本内容从sqlite数据库中删除",
+ inputSchema: z.object({
+ scriptId: z.string().describe("剧本id"),
+ }),
+ execute: async ({ scriptId }) => {
+ console.log("[tools] delete_script_to_sqlite", scriptId);
+ await u.db("o_script").where({ id: scriptId }).delete();
socket.emit("setPlanData", { key: "script", value: scriptId });
return true;
},
diff --git a/src/routes/assetsGenerate/polishAssetsPrompt.ts b/src/routes/assetsGenerate/polishAssetsPrompt.ts
index 887341e..29fdf19 100644
--- a/src/routes/assetsGenerate/polishAssetsPrompt.ts
+++ b/src/routes/assetsGenerate/polishAssetsPrompt.ts
@@ -122,6 +122,7 @@ export default router.post(
messages: [{ role: "user", content: "小说原文" + novelText }],
tools: skill.tools,
})) as any;
+
if (!_output) return res.status(500).send("失败");
await u.db("o_assets").where("id", assetsId).update({ prompt: _output });
diff --git a/src/types/database.d.ts b/src/types/database.d.ts
index 70b079c..bf2ee8f 100644
--- a/src/types/database.d.ts
+++ b/src/types/database.d.ts
@@ -1,6 +1,36 @@
-// @db-hash d807205fbb27fc5ddb04cae060fb4430
+// @db-hash 579a004cc745580469a24ee71f5f51c3
//该文件由脚本自动生成,请勿手动修改
+export interface _o_project_old_20260326 {
+ 'artStyle'?: string | null;
+ 'createTime'?: number | null;
+ 'id'?: number | null;
+ 'intro'?: string | null;
+ 'name'?: string | null;
+ 'projectType'?: string | null;
+ 'type'?: string | null;
+ 'userId'?: number | null;
+ 'videoRatio'?: string | null;
+}
+export interface _o_storyboard_old_20260325 {
+ 'camera'?: string | null;
+ 'createTime'?: number | null;
+ 'description'?: string | null;
+ 'duration'?: string | null;
+ 'filePath'?: string | null;
+ 'frameMode'?: string | null;
+ 'id'?: number;
+ 'lines'?: string | null;
+ 'mode'?: string | null;
+ 'model'?: string | null;
+ 'prompt'?: string | null;
+ 'reason'?: string | null;
+ 'resolution'?: string | null;
+ 'scriptId'?: number | null;
+ 'sound'?: string | null;
+ 'state'?: string | null;
+ 'title'?: string | null;
+}
export interface memories {
'content': string;
'createTime': number;
@@ -220,6 +250,8 @@ export interface o_videoConfig {
}
export interface DB {
+ "_o_project_old_20260326": _o_project_old_20260326;
+ "_o_storyboard_old_20260325": _o_storyboard_old_20260325;
"memories": memories;
"o_agentDeploy": o_agentDeploy;
"o_agentWorkData": o_agentWorkData;
diff --git a/src/utils/stripThink.ts b/src/utils/stripThink.ts
new file mode 100644
index 0000000..9867a93
--- /dev/null
+++ b/src/utils/stripThink.ts
@@ -0,0 +1,106 @@
+/**
+ * 去除深度思考模型输出的 ... 标签及其内容
+ *
+ * 1. stripThink(text) — 用于非流式,直接去除完整文本中的 块
+ * 2. createThinkStreamFilter() — 用于流式,返回有状态的过滤器,逐 chunk 过滤
+ */
+
+/**
+ * 非流式:去除完整文本中的 ...
+ */
+export function stripThink(text: string): string {
+ return text.replace(/[\s\S]*?<\/think>/g, "").trim();
+}
+
+/**
+ * 流式:创建一个有状态的 chunk 过滤器
+ *
+ * 用法:
+ * ```ts
+ * const filter = createThinkStreamFilter();
+ * for await (const chunk of textStream) {
+ * const filtered = filter.push(chunk);
+ * if (filtered) msg.send(filtered);
+ * }
+ * ```
+ */
+export function createThinkStreamFilter() {
+ let insideThink = false;
+ let buffer = "";
+
+ return {
+ /**
+ * 输入一个 chunk,返回过滤后需要输出的文本(可能为空字符串)
+ */
+ push(chunk: string): string {
+ let output = "";
+ let i = 0;
+
+ while (i < chunk.length) {
+ if (insideThink) {
+ // 正在 内部,寻找
+ const closeIdx = chunk.indexOf("", i);
+ if (closeIdx !== -1) {
+ // 找到闭合标签,跳过标签内容
+ insideThink = false;
+ i = closeIdx + "".length;
+ } else {
+ // 整个剩余 chunk 都在 think 内,全部丢弃
+ break;
+ }
+ } else {
+ // 不在 内部
+ const openIdx = chunk.indexOf("", i);
+ if (openIdx !== -1) {
+ // 找到开启标签,输出标签之前的内容
+ output += buffer + chunk.slice(i, openIdx);
+ buffer = "";
+ insideThink = true;
+ i = openIdx + "".length;
+ } else {
+ // 没有发现 ,但可能 chunk 末尾是不完整的 "" 的不完整前缀
+ * 如 "<", "