package engine // Dream 巩固提示词构建器. // // 升华改进(ELEVATED): 早期方案 构建叙事式 4 阶段提示词, // 让 Dream SubAgent 用真实工具(ls,grep,Edit,Write)自主完成记忆整理. // 我们的旧版(已删除)用 JSON-ops 格式(让模型输出 [{"op":"update",...}]), // 存在根本性缺陷:模型无法访问 transcript 文件,Phase 2(Gather)完全失效. // 新版恢复早期方案设计:叙事式提示词 + SubAgent-with-tools,模型可以自主 grep 历史. // // 关键常量: // - IndexFile:记忆目录的索引文件名(MEMORY.md),与 memory.Store.UpdateIndex 一致 // - MaxIndexLines:索引截断上限(与 memory.TruncateIndex 保持一致) import ( "fmt" "strings" ) // IndexFile 是记忆目录的入口索引文件名. // 与 pkg/memory 包的 UpdateIndex 逻辑保持一致(同文件名). const IndexFile = "MEMORY.md" // MaxIndexLines 是索引文件的行数上限(超过则截断). // 与 memory.TruncateIndex 的 maxIndexLines 常量保持一致:200 行 / 25KB. const MaxIndexLines = 200 // BuildConsolidationPrompt 构建发送给 Dream SubAgent 的四阶段巩固提示词. // // 参数: // - memoryRoot:记忆目录的绝对路径(SubAgent 的 Edit/Write 限于此目录) // - transcriptDir:会话 transcript 文件目录(空 = 跳过 Grep transcript 提示) // - sessionIDs:自上次巩固以来的会话 ID 列表(可选,用于提示词 hint;nil = 不提供) // // SubAgent 使用的工具: // - Bash(只读命令:ls/find/grep/cat/stat/head/tail) // - Read,Glob,Grep(探索记忆和 transcript) // - Edit,Write(只允许写入 memoryRoot 目录) func BuildConsolidationPrompt(memoryRoot, transcriptDir string, sessionIDs []string) string { var sb strings.Builder sb.WriteString("# Dream: Memory Consolidation\n\n") sb.WriteString("You are performing a dream — a reflective pass over your memory files. ") sb.WriteString("Synthesize what you've learned recently into durable, well-organized memories ") sb.WriteString("so that future sessions can orient quickly.\n\n") sb.WriteString(fmt.Sprintf("Memory directory: `%s`\n", memoryRoot)) sb.WriteString(fmt.Sprintf( "If the directory does not exist yet, create it with `mkdir -p %s` before writing.\n\n", memoryRoot, )) // Transcript 目录(可选) if transcriptDir != "" { sb.WriteString(fmt.Sprintf("Session transcripts: `%s`\n", transcriptDir)) sb.WriteString("(Large JSONL files — grep narrowly, **do not** read whole files.)\n\n") } sb.WriteString("---\n\n") // Phase 1 - Orient sb.WriteString("## Phase 1 — Orient\n\n") sb.WriteString(fmt.Sprintf("- `ls` the memory directory to see what already exists\n")) sb.WriteString(fmt.Sprintf("- Read `%s` to understand the current index\n", IndexFile)) sb.WriteString("- Skim existing topic files so you improve them rather than creating duplicates\n\n") // Phase 2 - Gather sb.WriteString("## Phase 2 — Gather recent signal\n\n") sb.WriteString("Look for new information worth persisting. Sources in rough priority order:\n\n") sb.WriteString("1. **Existing memories that drifted** — facts that contradict the current codebase\n") if transcriptDir != "" { sb.WriteString(fmt.Sprintf( "2. **Transcript search** — grep the JSONL transcripts for narrow terms:\n"+ " `grep -rn \"\" %s/ --include=\"*.jsonl\" | tail -50`\n"+ " Don't exhaustively read transcripts. Look only for things you already suspect matter.\n", transcriptDir, )) } sb.WriteString("\n") // Phase 3 - Consolidate sb.WriteString("## Phase 3 — Consolidate\n\n") sb.WriteString("For each thing worth remembering, write or update a memory file at the top level of ") sb.WriteString("the memory directory. Use the memory file format and type conventions from your ") sb.WriteString("system prompt's auto-memory section — it's the source of truth for what to save, ") sb.WriteString("how to structure it, and what NOT to save.\n\n") sb.WriteString("Focus on:\n") sb.WriteString("- Merging new signal into existing topic files rather than creating near-duplicates\n") sb.WriteString("- Converting relative dates (\"yesterday\", \"last week\") to absolute dates\n") sb.WriteString("- Deleting contradicted facts — if today's investigation disproves an old memory, fix it at the source\n\n") // Phase 4 - Prune and index sb.WriteString("## Phase 4 — Prune and index\n\n") sb.WriteString(fmt.Sprintf( "Update `%s` so it stays under %d lines AND under ~25KB. ", IndexFile, MaxIndexLines, )) sb.WriteString("It's an **index**, not a dump — each entry should be one line under ~150 characters: ") sb.WriteString("`- [Title](file.md) — one-line hook`. Never write memory content directly into it.\n\n") sb.WriteString("- Remove pointers to memories that are now stale, wrong, or superseded\n") sb.WriteString("- Demote verbose entries: if an index line is over ~200 chars, move the detail to the topic file\n") sb.WriteString("- Add pointers to newly important memories\n") sb.WriteString("- Resolve contradictions — if two files disagree, fix the wrong one\n\n") sb.WriteString("---\n\n") sb.WriteString("Return a brief summary of what you consolidated, updated, or pruned. ") sb.WriteString("If nothing changed (memories are already tight), say so.") // 额外上下文:会话列表 hint if len(sessionIDs) > 0 { sb.WriteString(fmt.Sprintf( "\n\n## Additional context\n\n**Tool constraints for this run:** "+ "Bash is restricted to read-only commands (`ls`, `find`, `grep`, `cat`, `stat`, "+ "`wc`, `head`, `tail`, and similar). Anything that writes, redirects to a file, "+ "or modifies state will be denied.\n\n"+ "Sessions since last consolidation (%d):\n", len(sessionIDs), )) for _, id := range sessionIDs { sb.WriteString(fmt.Sprintf("- %s\n", id)) } } return sb.String() }