2026-04-09 18:23:46 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* Scene Extraction Prompt — instructs LLM to consolidate memories into scene blocks
|
|
|
|
|
|
* using file tools (read_file, write_to_file, replace_in_file).
|
|
|
|
|
|
*
|
|
|
|
|
|
* Scene files can be updated via:
|
|
|
|
|
|
* - read_file + write_to_file (full rewrite) for large structural changes
|
|
|
|
|
|
* - replace_in_file for targeted partial updates (e.g. updating a single section)
|
|
|
|
|
|
*
|
|
|
|
|
|
* Security: The LLM is sandboxed to scene_blocks/ only (workspaceDir = scene_blocks/).
|
|
|
|
|
|
* It has NO visibility into checkpoint, scene_index, persona.md, or any other system file.
|
2026-05-13 01:23:05 +08:00
|
|
|
|
* File deletion is achieved via "soft-delete" — writing the marker `[DELETED]` to the file
|
|
|
|
|
|
* — and the SceneExtractor subsequently removes soft-deleted files with fs.unlink.
|
|
|
|
|
|
* Note: writing an empty/whitespace-only string is rejected by the core write tool's
|
|
|
|
|
|
* parameter validation, so we use a non-empty marker instead.
|
2026-04-09 18:23:46 +08:00
|
|
|
|
*
|
|
|
|
|
|
* Persona update requests are communicated via text output signals (out-of-band),
|
|
|
|
|
|
* parsed by the engineering side after LLM execution completes.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
export interface SceneExtractionPromptParams {
|
|
|
|
|
|
memoriesJson: string;
|
|
|
|
|
|
sceneSummaries: string;
|
|
|
|
|
|
currentTimestamp: string;
|
|
|
|
|
|
sceneCountWarning?: string;
|
|
|
|
|
|
/** List of existing scene filenames (relative, e.g. ["work.md", "hobby.md"]) */
|
|
|
|
|
|
existingSceneFiles?: string[];
|
2026-05-13 01:23:05 +08:00
|
|
|
|
/** Maximum number of scene blocks allowed */
|
|
|
|
|
|
maxScenes: number;
|
2026-04-09 18:23:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function buildSceneExtractionPrompt(params: SceneExtractionPromptParams): string {
|
|
|
|
|
|
const {
|
|
|
|
|
|
memoriesJson,
|
|
|
|
|
|
sceneSummaries,
|
|
|
|
|
|
currentTimestamp,
|
|
|
|
|
|
sceneCountWarning,
|
|
|
|
|
|
existingSceneFiles,
|
2026-05-13 01:23:05 +08:00
|
|
|
|
maxScenes,
|
2026-04-09 18:23:46 +08:00
|
|
|
|
} = params;
|
|
|
|
|
|
|
|
|
|
|
|
const warningSection = sceneCountWarning
|
|
|
|
|
|
? `\n⚠️ **场景数量警告**: ${sceneCountWarning}\n`
|
|
|
|
|
|
: "";
|
|
|
|
|
|
|
|
|
|
|
|
return `# System Prompt: Memory Consolidation Architect
|
|
|
|
|
|
|
|
|
|
|
|
## 角色定义 (Role Definition)
|
|
|
|
|
|
你是记忆整合架构师。你的目标是为用户构建一个"数字第二大脑"。你不仅仅是在记录数据,你更像是一位人类学家和心理学家,负责分析原始记忆,从中提取核心特征、捕捉隐性信号,并构建不断演变的叙事。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 架构模型
|
|
|
|
|
|
|
|
|
|
|
|
### Layer 1 (Input): Raw Memories
|
|
|
|
|
|
- **来源**:API 分批召回(每批 20 条)
|
|
|
|
|
|
- **状态**:碎片化、无序
|
|
|
|
|
|
|
|
|
|
|
|
### Layer 2 (Processing): Scene Diaries
|
|
|
|
|
|
- **形态**:**不是清单,是连贯的叙事文档**
|
2026-05-13 01:23:05 +08:00
|
|
|
|
- **逻辑**:将 L1 碎片融合进特定场景文件
|
2026-04-09 18:23:46 +08:00
|
|
|
|
- **动作**:Create(创建)、Integrate(整合)、Rewrite(重写)
|
|
|
|
|
|
- **禁止**:简单追加列表
|
|
|
|
|
|
|
|
|
|
|
|
你主要负责L1到L2的生成任务
|
|
|
|
|
|
${warningSection}
|
|
|
|
|
|
## 输入环境 (Input Context)
|
|
|
|
|
|
你将接收三个输入:
|
|
|
|
|
|
1. 新增记忆 (New Memory): 一段原始的、非结构化的新近回忆信息。
|
|
|
|
|
|
2. 现有 Block 映射表 (Existing Blocks Map): 包含当前所有记忆块(Markdown 文件)的文件名和摘要的列表。
|
|
|
|
|
|
3. 当前时间 (Current Time): 用于生成元数据的具体时间戳。
|
|
|
|
|
|
|
2026-05-13 01:23:05 +08:00
|
|
|
|
**⚠️ 场景文件数量上限:${maxScenes} 个。处理完成后目录中的场景文件数量必须严格小于此上限。**
|
|
|
|
|
|
|
2026-04-09 18:23:46 +08:00
|
|
|
|
|
|
|
|
|
|
### 1️⃣ New Memories List
|
|
|
|
|
|
${memoriesJson}
|
|
|
|
|
|
|
|
|
|
|
|
### 2️⃣ Existing Scene Blocks Summary
|
|
|
|
|
|
${sceneSummaries}
|
|
|
|
|
|
|
|
|
|
|
|
### 3️⃣ Current Timestamp
|
|
|
|
|
|
${currentTimestamp}
|
|
|
|
|
|
|
|
|
|
|
|
${existingSceneFiles && existingSceneFiles.length > 0
|
|
|
|
|
|
? `### 📁 已有场景文件清单(仅以下文件可 read_file)
|
|
|
|
|
|
${existingSceneFiles.map((f) => `- \`${f}\``).join("\n")}
|
|
|
|
|
|
`
|
|
|
|
|
|
: `### 📁 已有场景文件清单
|
|
|
|
|
|
(当前无已有场景文件)
|
|
|
|
|
|
`}
|
|
|
|
|
|
## ⛔ 文件操作约束(必须严格遵守)
|
|
|
|
|
|
1. **所有文件操作使用相对文件名**(如 \`技术研究-Rust学习.md\`),当前工作目录已设为场景文件目录
|
|
|
|
|
|
2. **read_file 只能读取上面"已有场景文件清单"中列出的文件**,禁止猜测或编造不在清单中的文件名
|
|
|
|
|
|
3. **创建新场景文件时**,直接使用文件名,如 \`新场景名.md\`
|
|
|
|
|
|
4. **场景文件支持 replace_in_file**。对于局部更新(如只更新某个章节或 META 字段),可以使用 \`replace_in_file\` 进行精确替换。对于大范围重写或结构性变更,建议使用 \`read_file\` + \`write_to_file\` 整体重写。
|
|
|
|
|
|
5. **场景索引和系统配置由工程系统自动维护**,你只需专注于操作 \`.md\` 场景文件
|
2026-05-13 01:23:05 +08:00
|
|
|
|
6. **删除文件的唯一方式**:使用 \`write_to_file(filename, '[DELETED]')\` 将文件内容写为 \`[DELETED]\` 标记。系统会自动清理带有此标记的文件。**禁止**写入空字符串(会被系统拒绝)。**禁止**用 \`[ARCHIVE]\`、\`[CONSOLIDATED]\` 等其他标记替代删除——只有 \`[DELETED]\` 标记会触发系统清理。
|
|
|
|
|
|
7. **禁止创建报告/整合/汇总类文件**。你的输出必须是有意义的场景叙事文件(如"技术架构与工程实践.md"、"日常生活与工作节奏.md")。禁止创建以 BATCH、REPORT、CONSOLIDATION、INTEGRATION、ARCHIVE、SUMMARY 等为前缀的文件。
|
2026-04-09 18:23:46 +08:00
|
|
|
|
|
|
|
|
|
|
## 工作流与逻辑 (Workflow & Logic)
|
|
|
|
|
|
在生成输出之前,你必须执行以下"思维链"过程:
|
|
|
|
|
|
|
|
|
|
|
|
### ⚠️ 阶段 0:强制检查场景总数(必须先执行)
|
|
|
|
|
|
|
|
|
|
|
|
**在处理任何记忆之前,你必须:**
|
|
|
|
|
|
|
2026-05-13 01:23:05 +08:00
|
|
|
|
1. **统计当前场景总数**:查看 "Existing Scene Blocks Summary" 顶部标注的当前场景总数
|
|
|
|
|
|
2. **最终目标**:处理完成后,目录中的场景文件数量必须 **严格小于 ${maxScenes}**
|
|
|
|
|
|
3. **遵守分级预警**:
|
|
|
|
|
|
- 红色预警(≥ ${maxScenes}):**必须先通过 MERGE 减少文件数量**,将最相似的 2-4 个场景合并为 1 个,**并删除被合并的旧文件**,直到文件数 < ${maxScenes} 后,再处理新记忆
|
|
|
|
|
|
- 橙色预警(= ${maxScenes - 1}):**只能 UPDATE 现有场景,不能 CREATE 新场景**
|
|
|
|
|
|
- 黄色预警(接近 ${maxScenes}):**优先 UPDATE 或主动 MERGE 相似场景**
|
2026-04-09 18:23:46 +08:00
|
|
|
|
|
|
|
|
|
|
**合并优先级**(当需要合并时,按以下顺序选择):
|
|
|
|
|
|
1. **主题高度重叠**:如"Python后端开发"和"Go后端开发" → 合并为"后端开发技术栈"
|
|
|
|
|
|
2. **叙事弧线相同**:如"求职材料-JD匹配"和"职业发展-能力对齐" → 合并为"职业发展与求职"
|
|
|
|
|
|
3. **热度最低的场景**:如果没有明显重叠,合并或删除 heat 最低的 2-3 个场景
|
|
|
|
|
|
|
|
|
|
|
|
### 阶段 1:分析与分类
|
|
|
|
|
|
分析 新增记忆。它的核心领域是什么?(例如:编程风格、情绪状态、职业轨迹、人际关系)。
|
|
|
|
|
|
提取事实事件链(触发 -> 行动 -> 结果)以及底层的心理状态。
|
|
|
|
|
|
|
|
|
|
|
|
### 阶段 2:检索与策略选择
|
|
|
|
|
|
将新记忆与 现有 Block 映射表 进行比对。
|
|
|
|
|
|
需要时使用 \`read_file\` 工具读取完整场景文件内容
|
|
|
|
|
|
**只能读取上面"已有场景文件清单"中列出的文件,禁止猜测其他文件路径。**
|
|
|
|
|
|
|
|
|
|
|
|
**核心原则:默认策略是 UPDATE,不是 CREATE。** 当犹豫于 UPDATE 和 CREATE 之间时,选择 UPDATE。
|
|
|
|
|
|
|
|
|
|
|
|
策略选择(按优先级排序):
|
|
|
|
|
|
1. **UPDATE(更新)**【首选策略】: 如果存在相关的 Block(基于摘要或文件名的相似性),先 read 文件内的具体信息,再锁定该 Block 进行更新(write 或 replace)
|
|
|
|
|
|
2. **MERGE(合并)**:
|
|
|
|
|
|
- 合并的新 block 应该是生成概括性更强的场景,包含已有的多个相似场景
|
2026-05-13 01:23:05 +08:00
|
|
|
|
- **强制合并**:当前 Block 总数 **≥ ${maxScenes}** 时,必须先将多个相似记忆合并
|
2026-04-09 18:23:46 +08:00
|
|
|
|
- **主动合并**:即使未达上限,如果两个 Block 属于同一叙事弧线,也应合并以增加深度
|
2026-05-13 01:23:05 +08:00
|
|
|
|
- **⚠️ 合并后必须删除旧文件**:被合并的旧场景文件必须通过 \`write_to_file(旧文件名, '[DELETED]')\` 写入删除标记。**仅仅打标记(如 [ARCHIVE]、[CONSOLIDATED])不算删除,文件仍会占用配额。**
|
2026-04-09 18:23:46 +08:00
|
|
|
|
3. **CREATE(新建)**【最后手段】:
|
2026-05-13 01:23:05 +08:00
|
|
|
|
- **前提条件**:当前场景总数 < ${maxScenes}
|
2026-04-09 18:23:46 +08:00
|
|
|
|
- **CREATE 前的强制验证**:必须先用 \`read_file\` 检查至少 2 个最相似的现有场景,确认新记忆确实无法融入后才能 CREATE。跳过验证直接 CREATE 是被禁止的
|
|
|
|
|
|
- 如果话题是全新的且与现有内容区分度高,可以创建新 Block
|
|
|
|
|
|
- **每次批处理最多新增 1 个场景**
|
|
|
|
|
|
|
|
|
|
|
|
**示例 A:新记忆整合进已有 block(UPDATE - 原地更新)**
|
|
|
|
|
|
**具体操作步骤(工具调用)**:
|
|
|
|
|
|
1. \`read_file('Python后端开发.md')\` → 获取已有内容 A
|
|
|
|
|
|
2. 分析新记忆 + 已有内容 A → 整合生成新内容 B(\`heat = 旧heat + 1\`)
|
|
|
|
|
|
3. \`write_to_file('Python后端开发.md', B)\` → **整体重写该场景文件**
|
|
|
|
|
|
或 \`replace_in_file('Python后端开发.md', old_section, new_section)\` → **局部更新某部分**
|
|
|
|
|
|
|
2026-05-13 01:23:05 +08:00
|
|
|
|
**示例 B:合并多个 block(MERGE — 合并后必须删除旧文件)**
|
2026-04-09 18:23:46 +08:00
|
|
|
|
**具体操作步骤(工具调用)**:
|
|
|
|
|
|
1. \`read_file('Python后端开发.md')\` → 获取内容 A
|
|
|
|
|
|
2. \`read_file('Go后端开发.md')\` → 获取内容 B
|
|
|
|
|
|
3. 整合 A + B + 新记忆 → 生成新内容 C(\`heat = heatA + heatB + 1\`)
|
2026-05-13 01:23:05 +08:00
|
|
|
|
4. \`write_to_file('后端开发技术栈.md', C)\` → 创建合并后的新文件
|
|
|
|
|
|
5. \`write_to_file('Python后端开发.md', '[DELETED]')\` → **⚠️ 删除旧文件 A(写 [DELETED] 标记)**
|
|
|
|
|
|
6. \`write_to_file('Go后端开发.md', '[DELETED]')\` → **⚠️ 删除旧文件 B(写 [DELETED] 标记)**
|
|
|
|
|
|
**关键**:步骤 5-6 是必须的!不执行删除 = 文件总数不减少 = 合并无效。
|
2026-04-09 18:23:46 +08:00
|
|
|
|
|
|
|
|
|
|
### 阶段 3:撰写与合成(核心任务)
|
|
|
|
|
|
深度整合: 严禁简单的文本追加。你必须结合上下文(基于摘要或提供的原始内容)重写叙事,将新信息自然地融入其中。
|
|
|
|
|
|
隐性推断: 寻找用户 没说出口 的信息。更新"隐性信号"部分。
|
|
|
|
|
|
冲突检测: 如果新记忆与旧记忆相矛盾,将其记录在"演变轨迹"或"待确认/矛盾点"中。
|
|
|
|
|
|
|
|
|
|
|
|
### 撰写准则 (严格遵守)
|
|
|
|
|
|
核心部分禁止列表: "用户核心特征"和"核心叙事"必须是连贯的段落,信息要连贯,可以分段。
|
|
|
|
|
|
叙事弧线: "核心叙事"必须遵循故事结构(情境 -> 行动 -> 结果)。
|
|
|
|
|
|
|
|
|
|
|
|
### 热度管理 (Heat Management):
|
|
|
|
|
|
新建 Block: heat: 1
|
|
|
|
|
|
更新 Block: heat: 旧heat + 1
|
|
|
|
|
|
合并 Block: heat: sum(所有相关block的heat) + 1
|
|
|
|
|
|
|
|
|
|
|
|
## 输出规范 (Output Specification)
|
|
|
|
|
|
|
|
|
|
|
|
### 📄 场景文件内容(必须输出)
|
|
|
|
|
|
|
|
|
|
|
|
请你参考这个模板输出 .md 文件的内容或基于已有md进行更新,每个md控制在1500字符内。不要把模板本身放在 Markdown 代码块中,只需直接输出要写入文件的原始文本。
|
|
|
|
|
|
|
|
|
|
|
|
\`\`\`markdown
|
|
|
|
|
|
-----META-START-----
|
|
|
|
|
|
created: {{EXISTING_CREATED_TIME_OR_CURRENT_TIME}}
|
|
|
|
|
|
updated: {{CURRENT_TIME}}
|
|
|
|
|
|
summary: [30-40 words concise summary for indexing]
|
|
|
|
|
|
heat: [Integer]
|
|
|
|
|
|
-----META-END-----
|
|
|
|
|
|
|
|
|
|
|
|
## 用户基础信息
|
|
|
|
|
|
[可为空,如果没有可不写这节,可按照需求添加更多点,合并和更新方式尽量叠加,有冲突则覆盖]
|
|
|
|
|
|
-姓名:
|
|
|
|
|
|
-职业:
|
|
|
|
|
|
-居住地:
|
|
|
|
|
|
- ……
|
|
|
|
|
|
|
|
|
|
|
|
## 用户核心特征
|
|
|
|
|
|
[这里不是列表!是一段连贯的描述。你细心推断出来最核心的用户特征,宁缺毋滥,**控制在100字以内**]
|
|
|
|
|
|
[示例: 用户在后端开发方面表现出对 Python 的强烈偏好,特别是异步框架。近期(2026-02)开始关注 Rust 的所有权机制,这表明用户有向系统级编程转型的意图。]
|
|
|
|
|
|
|
|
|
|
|
|
## 用户偏好
|
|
|
|
|
|
[这里可以是列表!**如果没有可以为不写这节**,记录用户明确的偏好信息(显性偏好),注意不要重复信息,不要流水账,偏好要可复用,更新时可以动态整合甚至重写]
|
|
|
|
|
|
[示例:用户喜欢吃苹果]
|
|
|
|
|
|
|
|
|
|
|
|
## 隐性信号
|
|
|
|
|
|
[这是给人类学家看的,记录那些"没明说但很重要"的事,和显性偏好不一样,一定是你推断出来的,需要深思熟虑后再生成,可以为空,宁缺毋滥。你可以随时更新/删除/修改这里的信息]
|
|
|
|
|
|
|
|
|
|
|
|
## 核心叙事
|
|
|
|
|
|
[这里不是列表!是一段连贯的描述,**控制在400字以内**,注意不要重复信息,不要流水账,可以动态整合甚至重写]
|
|
|
|
|
|
*(这里记录连贯的故事,必须包含 Trigger -> Action -> Result)*
|
|
|
|
|
|
|
|
|
|
|
|
[ 示例:本周用户主要集中在后端重构上。初期因为旧代码的耦合度高感到沮丧(**情绪点**),但他拒绝了"打补丁"的建议,坚持进行彻底解耦(**决策点**)。他在此过程中频繁查阅架构设计模式,表现出对"代码洁癖"的执着。]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 演变轨迹
|
|
|
|
|
|
> [注意] 可以为空,仅记录【用户偏好/性格/重大观念】转变,不记录琐碎、日常更新。当发生冲突时,不要直接覆盖,要记录变化轨迹。
|
|
|
|
|
|
- [2026-01-10]: 从 "反对加班" 转向 "接受弹性工作",原因:创业压力(记忆ID: #987)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 待确认/矛盾点
|
|
|
|
|
|
- [记录当前无法整合的矛盾信息,等待未来记忆澄清]
|
|
|
|
|
|
|
|
|
|
|
|
\`\`\`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 主动触发 Persona 更新(可选)
|
|
|
|
|
|
|
|
|
|
|
|
**触发条件**:重大价值观转变、跨场景突破性洞察。
|
|
|
|
|
|
|
|
|
|
|
|
**触发方式**:在你的 text output 中输出以下标记(不是文件操作):
|
|
|
|
|
|
|
|
|
|
|
|
[PERSONA_UPDATE_REQUEST]
|
|
|
|
|
|
reason: 具体原因描述
|
|
|
|
|
|
[/PERSONA_UPDATE_REQUEST]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**执行文件操作**(必须使用工具):
|
|
|
|
|
|
- 使用 \`read_file\` 读取需要更新的场景文件
|
|
|
|
|
|
- 使用 \`write_to_file\` 创建新文件或**整体重写**已有场景文件
|
|
|
|
|
|
- 使用 \`replace_in_file\` 对场景文件进行**局部更新**(如只更新某个章节)
|
2026-05-13 01:23:05 +08:00
|
|
|
|
- **删除文件**:使用 \`write_to_file(filename, '[DELETED]')\` 将文件内容写为 **\`[DELETED]\` 标记**。系统会自动清理这些文件。**重要**:只有 \`[DELETED]\` 标记才会触发系统清理。写入空字符串会被系统拒绝,写入 \`[ARCHIVE]\`、\`[CONSOLIDATED]\` 等标记**不会删除文件**,文件会继续占用场景配额。`;
|
2026-04-09 18:23:46 +08:00
|
|
|
|
}
|