@oyasmi/pipiclaw 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/dist/agent/channel-runner.d.ts +46 -0
  2. package/dist/agent/channel-runner.d.ts.map +1 -0
  3. package/dist/agent/channel-runner.js +434 -0
  4. package/dist/agent/channel-runner.js.map +1 -0
  5. package/dist/agent/index.d.ts +4 -0
  6. package/dist/agent/index.d.ts.map +1 -0
  7. package/dist/agent/index.js +3 -0
  8. package/dist/agent/index.js.map +1 -0
  9. package/dist/agent/progress-formatter.d.ts +5 -0
  10. package/dist/agent/progress-formatter.d.ts.map +1 -0
  11. package/dist/agent/progress-formatter.js +53 -0
  12. package/dist/agent/progress-formatter.js.map +1 -0
  13. package/dist/agent/run-queue.d.ts +8 -0
  14. package/dist/agent/run-queue.d.ts.map +1 -0
  15. package/dist/agent/run-queue.js +27 -0
  16. package/dist/agent/run-queue.js.map +1 -0
  17. package/dist/agent/runner-factory.d.ts +4 -0
  18. package/dist/agent/runner-factory.d.ts.map +1 -0
  19. package/dist/agent/runner-factory.js +11 -0
  20. package/dist/agent/runner-factory.js.map +1 -0
  21. package/dist/agent/session-events.d.ts +15 -0
  22. package/dist/agent/session-events.d.ts.map +1 -0
  23. package/dist/agent/session-events.js +216 -0
  24. package/dist/agent/session-events.js.map +1 -0
  25. package/dist/agent/type-guards.d.ts +23 -0
  26. package/dist/agent/type-guards.d.ts.map +1 -0
  27. package/dist/agent/type-guards.js +107 -0
  28. package/dist/agent/type-guards.js.map +1 -0
  29. package/dist/agent/types.d.ts +161 -0
  30. package/dist/agent/types.d.ts.map +1 -0
  31. package/dist/agent/types.js +23 -0
  32. package/dist/agent/types.js.map +1 -0
  33. package/dist/agent.d.ts +2 -15
  34. package/dist/agent.d.ts.map +1 -1
  35. package/dist/agent.js +1 -781
  36. package/dist/agent.js.map +1 -1
  37. package/dist/context.d.ts +58 -14
  38. package/dist/context.d.ts.map +1 -1
  39. package/dist/context.js +50 -7
  40. package/dist/context.js.map +1 -1
  41. package/dist/index.d.ts +12 -12
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +12 -12
  44. package/dist/index.js.map +1 -1
  45. package/dist/main.js +5 -404
  46. package/dist/main.js.map +1 -1
  47. package/dist/memory/bootstrap.d.ts +7 -0
  48. package/dist/memory/bootstrap.d.ts.map +1 -0
  49. package/dist/memory/bootstrap.js +47 -0
  50. package/dist/memory/bootstrap.js.map +1 -0
  51. package/dist/{memory-candidates.d.ts → memory/candidates.d.ts} +2 -1
  52. package/dist/memory/candidates.d.ts.map +1 -0
  53. package/dist/{memory-candidates.js → memory/candidates.js} +34 -21
  54. package/dist/memory/candidates.js.map +1 -0
  55. package/dist/memory/chinese-words.d.ts +2 -0
  56. package/dist/memory/chinese-words.d.ts.map +1 -0
  57. package/dist/memory/chinese-words.js +210 -0
  58. package/dist/memory/chinese-words.js.map +1 -0
  59. package/dist/{memory-consolidation.d.ts → memory/consolidation.d.ts} +1 -1
  60. package/dist/memory/consolidation.d.ts.map +1 -0
  61. package/dist/{memory-consolidation.js → memory/consolidation.js} +27 -35
  62. package/dist/memory/consolidation.js.map +1 -0
  63. package/dist/{memory-files.d.ts → memory/files.d.ts} +1 -6
  64. package/dist/memory/files.d.ts.map +1 -0
  65. package/dist/{memory-files.js → memory/files.js} +12 -36
  66. package/dist/memory/files.js.map +1 -0
  67. package/dist/{memory-lifecycle.d.ts → memory/lifecycle.d.ts} +24 -6
  68. package/dist/memory/lifecycle.d.ts.map +1 -0
  69. package/dist/memory/lifecycle.js +247 -0
  70. package/dist/memory/lifecycle.js.map +1 -0
  71. package/dist/{memory-recall.d.ts → memory/recall.d.ts} +2 -2
  72. package/dist/memory/recall.d.ts.map +1 -0
  73. package/dist/memory/recall.js +435 -0
  74. package/dist/memory/recall.js.map +1 -0
  75. package/dist/{session-memory.d.ts → memory/session.d.ts} +2 -1
  76. package/dist/memory/session.d.ts.map +1 -0
  77. package/dist/{session-memory.js → memory/session.js} +32 -62
  78. package/dist/memory/session.js.map +1 -0
  79. package/dist/runtime/bootstrap.d.ts +48 -0
  80. package/dist/runtime/bootstrap.d.ts.map +1 -0
  81. package/dist/runtime/bootstrap.js +451 -0
  82. package/dist/runtime/bootstrap.js.map +1 -0
  83. package/dist/runtime/delivery.d.ts.map +1 -0
  84. package/dist/{delivery.js → runtime/delivery.js} +1 -1
  85. package/dist/runtime/delivery.js.map +1 -0
  86. package/dist/{dingtalk.d.ts → runtime/dingtalk.d.ts} +10 -0
  87. package/dist/runtime/dingtalk.d.ts.map +1 -0
  88. package/dist/{dingtalk.js → runtime/dingtalk.js} +87 -27
  89. package/dist/runtime/dingtalk.js.map +1 -0
  90. package/dist/runtime/events.d.ts.map +1 -0
  91. package/dist/{events.js → runtime/events.js} +1 -1
  92. package/dist/runtime/events.js.map +1 -0
  93. package/dist/{store.d.ts → runtime/store.d.ts} +5 -0
  94. package/dist/runtime/store.d.ts.map +1 -0
  95. package/dist/{store.js → runtime/store.js} +60 -19
  96. package/dist/runtime/store.js.map +1 -0
  97. package/dist/shared/markdown-sections.d.ts +7 -0
  98. package/dist/shared/markdown-sections.d.ts.map +1 -0
  99. package/dist/{markdown-sections.js → shared/markdown-sections.js} +10 -3
  100. package/dist/shared/markdown-sections.js.map +1 -0
  101. package/dist/shared/text-utils.d.ts +10 -0
  102. package/dist/shared/text-utils.d.ts.map +1 -0
  103. package/dist/shared/text-utils.js +37 -0
  104. package/dist/shared/text-utils.js.map +1 -0
  105. package/dist/shared/type-guards.d.ts +6 -0
  106. package/dist/shared/type-guards.d.ts.map +1 -0
  107. package/dist/shared/type-guards.js +13 -0
  108. package/dist/shared/type-guards.js.map +1 -0
  109. package/dist/shared/types.d.ts +15 -0
  110. package/dist/shared/types.d.ts.map +1 -0
  111. package/dist/shared/types.js +2 -0
  112. package/dist/shared/types.js.map +1 -0
  113. package/dist/sidecar-worker.d.ts.map +1 -1
  114. package/dist/sidecar-worker.js +1 -7
  115. package/dist/sidecar-worker.js.map +1 -1
  116. package/dist/{sub-agents.d.ts → subagents/discovery.d.ts} +1 -1
  117. package/dist/subagents/discovery.d.ts.map +1 -0
  118. package/dist/{sub-agents.js → subagents/discovery.js} +3 -3
  119. package/dist/subagents/discovery.js.map +1 -0
  120. package/dist/{tools/subagent.d.ts → subagents/tool.d.ts} +3 -16
  121. package/dist/{tools/subagent.d.ts.map → subagents/tool.d.ts.map} +1 -1
  122. package/dist/{tools/subagent.js → subagents/tool.js} +17 -38
  123. package/dist/subagents/tool.js.map +1 -0
  124. package/dist/tools/index.d.ts +1 -1
  125. package/dist/tools/index.d.ts.map +1 -1
  126. package/dist/tools/index.js +1 -1
  127. package/dist/tools/index.js.map +1 -1
  128. package/docs/memory-audit.md +330 -0
  129. package/docs/memory-optimization-round2.md +319 -0
  130. package/package.json +1 -1
  131. package/dist/delivery.d.ts.map +0 -1
  132. package/dist/delivery.js.map +0 -1
  133. package/dist/dingtalk.d.ts.map +0 -1
  134. package/dist/dingtalk.js.map +0 -1
  135. package/dist/events.d.ts.map +0 -1
  136. package/dist/events.js.map +0 -1
  137. package/dist/markdown-sections.d.ts +0 -6
  138. package/dist/markdown-sections.d.ts.map +0 -1
  139. package/dist/markdown-sections.js.map +0 -1
  140. package/dist/memory-candidates.d.ts.map +0 -1
  141. package/dist/memory-candidates.js.map +0 -1
  142. package/dist/memory-consolidation.d.ts.map +0 -1
  143. package/dist/memory-consolidation.js.map +0 -1
  144. package/dist/memory-files.d.ts.map +0 -1
  145. package/dist/memory-files.js.map +0 -1
  146. package/dist/memory-lifecycle.d.ts.map +0 -1
  147. package/dist/memory-lifecycle.js +0 -150
  148. package/dist/memory-lifecycle.js.map +0 -1
  149. package/dist/memory-recall.d.ts.map +0 -1
  150. package/dist/memory-recall.js +0 -218
  151. package/dist/memory-recall.js.map +0 -1
  152. package/dist/session-memory-files.d.ts +0 -2
  153. package/dist/session-memory-files.d.ts.map +0 -1
  154. package/dist/session-memory-files.js +0 -2
  155. package/dist/session-memory-files.js.map +0 -1
  156. package/dist/session-memory.d.ts.map +0 -1
  157. package/dist/session-memory.js.map +0 -1
  158. package/dist/store.d.ts.map +0 -1
  159. package/dist/store.js.map +0 -1
  160. package/dist/sub-agents.d.ts.map +0 -1
  161. package/dist/sub-agents.js.map +0 -1
  162. package/dist/tools/subagent.js.map +0 -1
  163. package/docs/proj-review.md +0 -188
  164. package/docs/test-supplementation-plan.md +0 -553
  165. /package/dist/{delivery.d.ts → runtime/delivery.d.ts} +0 -0
  166. /package/dist/{events.d.ts → runtime/events.d.ts} +0 -0
  167. /package/docs/{memory-rfc.md → specs/001-implement-memory/memory-rfc.md} +0 -0
  168. /package/docs/{subagent → specs/002-subagent}/pi-subagent-analyse.txt +0 -0
  169. /package/docs/{subagent → specs/002-subagent}/pi-subagent-design.txt +0 -0
  170. /package/docs/{subagent → specs/002-subagent}/pi-subagent-phase1-plan.txt +0 -0
  171. /package/docs/{improve-memory → specs/003-improve-memory}/design.md +0 -0
  172. /package/docs/{improve-memory → specs/003-improve-memory}/interfaces-and-tests.md +0 -0
  173. /package/docs/{improve-memory → specs/003-improve-memory}/spec.md +0 -0
@@ -1,7 +1,7 @@
1
1
  import { readFile } from "fs/promises";
2
2
  import { join } from "path";
3
- import { splitLevelOneSections } from "./markdown-sections.js";
4
- import { getChannelHistoryPath, getChannelMemoryPath, getChannelSessionPath, splitMarkdownSections, } from "./memory-files.js";
3
+ import { splitH1Sections, splitH2Sections } from "../shared/markdown-sections.js";
4
+ import { getChannelHistoryPath, getChannelMemoryPath, getChannelSessionPath } from "./files.js";
5
5
  export function createMemoryCandidateCache() {
6
6
  return {
7
7
  entries: new Map(),
@@ -28,38 +28,49 @@ function inferPriority(source, title) {
28
28
  const normalizedTitle = title.trim().toLowerCase();
29
29
  if (source === "channel-session") {
30
30
  if (normalizedTitle === "current state")
31
- return 120;
31
+ return 18;
32
32
  if (normalizedTitle === "next steps")
33
- return 115;
33
+ return 17;
34
34
  if (normalizedTitle === "errors & corrections")
35
- return 110;
35
+ return 16;
36
36
  if (normalizedTitle === "constraints")
37
- return 108;
37
+ return 15;
38
38
  if (normalizedTitle === "user intent")
39
- return 105;
40
- return 100;
39
+ return 15;
40
+ if (normalizedTitle === "active files")
41
+ return 14;
42
+ if (normalizedTitle === "decisions")
43
+ return 14;
44
+ if (normalizedTitle === "session title")
45
+ return 13;
46
+ return 12;
41
47
  }
42
48
  if (source === "channel-memory") {
43
49
  if (normalizedTitle.includes("constraints"))
44
- return 88;
50
+ return 11;
45
51
  if (normalizedTitle.includes("decisions"))
46
- return 86;
52
+ return 10;
47
53
  if (normalizedTitle.includes("open loops"))
48
- return 84;
49
- return 80;
54
+ return 10;
55
+ if (normalizedTitle.includes("preferences"))
56
+ return 9;
57
+ if (normalizedTitle.includes("ongoing work"))
58
+ return 9;
59
+ return 8;
50
60
  }
51
61
  if (source === "workspace-memory") {
52
- return 60;
62
+ return 6;
53
63
  }
54
- return 40;
64
+ return 4;
55
65
  }
56
- function buildCandidate(source, path, title, content, timestamp) {
66
+ function buildCandidate(source, path, title, content, timestamp, searchText) {
57
67
  return {
58
68
  id: `${source}:${slugify(title)}:${timestamp ?? ""}`,
59
69
  source,
60
70
  path,
61
71
  title,
62
72
  content,
73
+ searchText,
63
74
  timestamp,
64
75
  sectionKind: title.trim().toLowerCase(),
65
76
  priority: inferPriority(source, title),
@@ -69,7 +80,7 @@ function buildCacheKey(options) {
69
80
  return `${options.workspaceDir}\u0000${options.channelDir}`;
70
81
  }
71
82
  function buildWorkspaceOrChannelMemoryCandidates(source, path, content) {
72
- const sections = splitMarkdownSections(content);
83
+ const sections = splitH2Sections(content);
73
84
  if (sections.length === 0 && content) {
74
85
  return [
75
86
  buildCandidate(source, path, source === "workspace-memory" ? "Workspace Memory" : "Channel Memory", content),
@@ -80,12 +91,14 @@ function buildWorkspaceOrChannelMemoryCandidates(source, path, content) {
80
91
  .map((section) => buildCandidate(source, path, section.heading, section.content));
81
92
  }
82
93
  function buildSessionCandidates(path, content) {
83
- return splitLevelOneSections(content)
84
- .filter((section) => section.content.trim())
85
- .map((section) => buildCandidate("channel-session", path, section.heading, section.content));
94
+ const sections = splitH1Sections(content).filter((section) => section.content.trim());
95
+ const sessionTitle = sections.find((section) => section.heading.toLowerCase() === "session title")?.content ?? "";
96
+ return sections.map((section) => buildCandidate("channel-session", path, section.heading, section.content, undefined, section.heading.toLowerCase() === "session title" || !sessionTitle.trim()
97
+ ? section.content
98
+ : `${sessionTitle.trim()}\n${section.content}`));
86
99
  }
87
100
  function buildHistoryCandidates(path, content) {
88
- return splitMarkdownSections(content)
101
+ return splitH2Sections(content)
89
102
  .filter((section) => section.content.trim())
90
103
  .map((section) => buildCandidate("channel-history", path, section.heading, section.content, section.heading));
91
104
  }
@@ -123,4 +136,4 @@ export async function buildMemoryCandidates(options) {
123
136
  options.cache.entries.set(key, pending);
124
137
  return pending;
125
138
  }
126
- //# sourceMappingURL=memory-candidates.js.map
139
+ //# sourceMappingURL=candidates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candidates.js","sourceRoot":"","sources":["../../src/memory/candidates.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile } from \"fs/promises\";\nimport { join } from \"path\";\nimport { splitH1Sections, splitH2Sections } from \"../shared/markdown-sections.js\";\nimport { getChannelHistoryPath, getChannelMemoryPath, getChannelSessionPath } from \"./files.js\";\n\nexport interface MemoryCandidate {\n\tid: string;\n\tsource: \"workspace-memory\" | \"channel-memory\" | \"channel-session\" | \"channel-history\";\n\tpath: string;\n\ttitle: string;\n\tcontent: string;\n\tsearchText?: string;\n\ttimestamp?: string;\n\tsectionKind?: string;\n\tpriority: number;\n}\n\nexport interface BuildMemoryCandidatesOptions {\n\tworkspaceDir: string;\n\tchannelDir: string;\n\tcache?: MemoryCandidateCache;\n}\n\nexport interface MemoryCandidateCache {\n\tentries: Map<string, Promise<MemoryCandidate[]>>;\n}\n\nexport function createMemoryCandidateCache(): MemoryCandidateCache {\n\treturn {\n\t\tentries: new Map(),\n\t};\n}\n\nfunction normalizeContent(content: string): string {\n\treturn content.replace(/\\r/g, \"\").trim();\n}\n\nasync function readOptionalFile(path: string): Promise<string> {\n\ttry {\n\t\treturn normalizeContent(await readFile(path, \"utf-8\"));\n\t} catch {\n\t\treturn \"\";\n\t}\n}\n\nfunction slugify(value: string): string {\n\treturn (\n\t\tvalue\n\t\t\t.toLowerCase()\n\t\t\t.replace(/[^a-z0-9]+/g, \"-\")\n\t\t\t.replace(/^-+|-+$/g, \"\") || \"section\"\n\t);\n}\n\nfunction inferPriority(source: MemoryCandidate[\"source\"], title: string): number {\n\tconst normalizedTitle = title.trim().toLowerCase();\n\tif (source === \"channel-session\") {\n\t\tif (normalizedTitle === \"current state\") return 18;\n\t\tif (normalizedTitle === \"next steps\") return 17;\n\t\tif (normalizedTitle === \"errors & corrections\") return 16;\n\t\tif (normalizedTitle === \"constraints\") return 15;\n\t\tif (normalizedTitle === \"user intent\") return 15;\n\t\tif (normalizedTitle === \"active files\") return 14;\n\t\tif (normalizedTitle === \"decisions\") return 14;\n\t\tif (normalizedTitle === \"session title\") return 13;\n\t\treturn 12;\n\t}\n\tif (source === \"channel-memory\") {\n\t\tif (normalizedTitle.includes(\"constraints\")) return 11;\n\t\tif (normalizedTitle.includes(\"decisions\")) return 10;\n\t\tif (normalizedTitle.includes(\"open loops\")) return 10;\n\t\tif (normalizedTitle.includes(\"preferences\")) return 9;\n\t\tif (normalizedTitle.includes(\"ongoing work\")) return 9;\n\t\treturn 8;\n\t}\n\tif (source === \"workspace-memory\") {\n\t\treturn 6;\n\t}\n\treturn 4;\n}\n\nfunction buildCandidate(\n\tsource: MemoryCandidate[\"source\"],\n\tpath: string,\n\ttitle: string,\n\tcontent: string,\n\ttimestamp?: string,\n\tsearchText?: string,\n): MemoryCandidate {\n\treturn {\n\t\tid: `${source}:${slugify(title)}:${timestamp ?? \"\"}`,\n\t\tsource,\n\t\tpath,\n\t\ttitle,\n\t\tcontent,\n\t\tsearchText,\n\t\ttimestamp,\n\t\tsectionKind: title.trim().toLowerCase(),\n\t\tpriority: inferPriority(source, title),\n\t};\n}\n\nfunction buildCacheKey(options: BuildMemoryCandidatesOptions): string {\n\treturn `${options.workspaceDir}\\u0000${options.channelDir}`;\n}\n\nfunction buildWorkspaceOrChannelMemoryCandidates(\n\tsource: \"workspace-memory\" | \"channel-memory\",\n\tpath: string,\n\tcontent: string,\n): MemoryCandidate[] {\n\tconst sections = splitH2Sections(content);\n\tif (sections.length === 0 && content) {\n\t\treturn [\n\t\t\tbuildCandidate(source, path, source === \"workspace-memory\" ? \"Workspace Memory\" : \"Channel Memory\", content),\n\t\t];\n\t}\n\n\treturn sections\n\t\t.filter((section) => section.content.trim())\n\t\t.map((section) => buildCandidate(source, path, section.heading, section.content));\n}\n\nfunction buildSessionCandidates(path: string, content: string): MemoryCandidate[] {\n\tconst sections = splitH1Sections(content).filter((section) => section.content.trim());\n\tconst sessionTitle = sections.find((section) => section.heading.toLowerCase() === \"session title\")?.content ?? \"\";\n\n\treturn sections.map((section) =>\n\t\tbuildCandidate(\n\t\t\t\"channel-session\",\n\t\t\tpath,\n\t\t\tsection.heading,\n\t\t\tsection.content,\n\t\t\tundefined,\n\t\t\tsection.heading.toLowerCase() === \"session title\" || !sessionTitle.trim()\n\t\t\t\t? section.content\n\t\t\t\t: `${sessionTitle.trim()}\\n${section.content}`,\n\t\t),\n\t);\n}\n\nfunction buildHistoryCandidates(path: string, content: string): MemoryCandidate[] {\n\treturn splitH2Sections(content)\n\t\t.filter((section) => section.content.trim())\n\t\t.map((section) => buildCandidate(\"channel-history\", path, section.heading, section.content, section.heading));\n}\n\nasync function buildMemoryCandidatesUncached(options: BuildMemoryCandidatesOptions): Promise<MemoryCandidate[]> {\n\tconst workspaceMemoryPath = join(options.workspaceDir, \"MEMORY.md\");\n\tconst channelMemoryPath = getChannelMemoryPath(options.channelDir);\n\tconst channelSessionPath = getChannelSessionPath(options.channelDir);\n\tconst channelHistoryPath = getChannelHistoryPath(options.channelDir);\n\n\tconst [workspaceMemory, channelMemory, channelSession, channelHistory] = await Promise.all([\n\t\treadOptionalFile(workspaceMemoryPath),\n\t\treadOptionalFile(channelMemoryPath),\n\t\treadOptionalFile(channelSessionPath),\n\t\treadOptionalFile(channelHistoryPath),\n\t]);\n\n\treturn [\n\t\t...buildSessionCandidates(channelSessionPath, channelSession),\n\t\t...buildWorkspaceOrChannelMemoryCandidates(\"channel-memory\", channelMemoryPath, channelMemory),\n\t\t...buildWorkspaceOrChannelMemoryCandidates(\"workspace-memory\", workspaceMemoryPath, workspaceMemory),\n\t\t...buildHistoryCandidates(channelHistoryPath, channelHistory),\n\t];\n}\n\nexport async function buildMemoryCandidates(options: BuildMemoryCandidatesOptions): Promise<MemoryCandidate[]> {\n\tif (!options.cache) {\n\t\treturn buildMemoryCandidatesUncached(options);\n\t}\n\n\tconst key = buildCacheKey(options);\n\tconst cached = options.cache.entries.get(key);\n\tif (cached) {\n\t\treturn cached;\n\t}\n\n\tconst pending = buildMemoryCandidatesUncached(options).catch((error) => {\n\t\toptions.cache?.entries.delete(key);\n\t\tthrow error;\n\t});\n\toptions.cache.entries.set(key, pending);\n\treturn pending;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare const COMMON_CHINESE_WORDS: Set<string>;
2
+ //# sourceMappingURL=chinese-words.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chinese-words.d.ts","sourceRoot":"","sources":["../../src/memory/chinese-words.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,aAgN/B,CAAC"}
@@ -0,0 +1,210 @@
1
+ export const COMMON_CHINESE_WORDS = new Set([
2
+ "当前状态",
3
+ "当前工作",
4
+ "工作状态",
5
+ "会话状态",
6
+ "任务状态",
7
+ "当前任务",
8
+ "工作进度",
9
+ "用户意图",
10
+ "活跃文件",
11
+ "错误修正",
12
+ "下一步",
13
+ "接下来",
14
+ "后续步骤",
15
+ "后续计划",
16
+ "待办事项",
17
+ "开放问题",
18
+ "开放循环",
19
+ "关键事实",
20
+ "设计决策",
21
+ "关键决策",
22
+ "约束条件",
23
+ "技术约束",
24
+ "兼容要求",
25
+ "接口稳定",
26
+ "协议变更",
27
+ "修复方案",
28
+ "实现方案",
29
+ "优化方案",
30
+ "根因分析",
31
+ "问题定位",
32
+ "错误信息",
33
+ "调试过程",
34
+ "排查过程",
35
+ "实现细节",
36
+ "调用链路",
37
+ "模块边界",
38
+ "领域边界",
39
+ "文件路径",
40
+ "运行时",
41
+ "子代理",
42
+ "工具调用",
43
+ "上下文",
44
+ "上下文恢复",
45
+ "上下文窗口",
46
+ "上下文注入",
47
+ "注入上下文",
48
+ "当前问题",
49
+ "历史问题",
50
+ "历史记录",
51
+ "历史恢复",
52
+ "历史叙事",
53
+ "历史块",
54
+ "摘要块",
55
+ "发布记录",
56
+ "部署记录",
57
+ "旧发布",
58
+ "旧记录",
59
+ "早期历史",
60
+ "过去工作",
61
+ "长期任务",
62
+ "短对话",
63
+ "短问答",
64
+ "自然结束",
65
+ "对话结束",
66
+ "会话切换",
67
+ "当前目录",
68
+ "代码实现",
69
+ "类型检查",
70
+ "单元测试",
71
+ "集成测试",
72
+ "回归测试",
73
+ "测试覆盖",
74
+ "回归风险",
75
+ "默认配置",
76
+ "配置项",
77
+ "参数选择",
78
+ "超时设置",
79
+ "内容截断",
80
+ "内存清理",
81
+ "背景维护",
82
+ "增量更新",
83
+ "历史折叠",
84
+ "持久化",
85
+ "一致性",
86
+ "可靠性",
87
+ "稳定性",
88
+ "兼容性",
89
+ "相关性",
90
+ "评分模型",
91
+ "检索候选",
92
+ "候选集合",
93
+ "召回候选",
94
+ "中文分词",
95
+ "词表分词",
96
+ "最大匹配",
97
+ "服务器",
98
+ "数据库",
99
+ "数据表",
100
+ "缓存",
101
+ "队列",
102
+ "网络",
103
+ "集群",
104
+ "容器",
105
+ "网关",
106
+ "代理服务",
107
+ "负载均衡",
108
+ "配置中心",
109
+ "注册中心",
110
+ "消息队列",
111
+ "对象存储",
112
+ "日志系统",
113
+ "监控系统",
114
+ "告警系统",
115
+ "文件系统",
116
+ "函数",
117
+ "变量",
118
+ "常量",
119
+ "接口",
120
+ "类型定义",
121
+ "类型系统",
122
+ "模块",
123
+ "组件",
124
+ "服务层",
125
+ "数据层",
126
+ "控制层",
127
+ "依赖注入",
128
+ "继承关系",
129
+ "抽象层",
130
+ "实现层",
131
+ "状态管理",
132
+ "异常处理",
133
+ "错误处理",
134
+ "并发控制",
135
+ "并发请求",
136
+ "异步任务",
137
+ "同步调用",
138
+ "回调函数",
139
+ "中间件",
140
+ "过滤器",
141
+ "拦截器",
142
+ "路由配置",
143
+ "认证授权",
144
+ "用户认证",
145
+ "权限控制",
146
+ "会话管理",
147
+ "请求参数",
148
+ "响应结果",
149
+ "接口调用",
150
+ "请求头",
151
+ "响应头",
152
+ "重试机制",
153
+ "降级策略",
154
+ "熔断机制",
155
+ "事务处理",
156
+ "事务回滚",
157
+ "索引优化",
158
+ "数据迁移",
159
+ "数据同步",
160
+ "备份恢复",
161
+ "锁机制",
162
+ "乐观锁",
163
+ "悲观锁",
164
+ "死锁问题",
165
+ "查询语句",
166
+ "分页查询",
167
+ "条件过滤",
168
+ "批量操作",
169
+ "性能问题",
170
+ "性能优化",
171
+ "内存泄漏",
172
+ "资源释放",
173
+ "构建流程",
174
+ "编译过程",
175
+ "打包流程",
176
+ "发布流程",
177
+ "回滚方案",
178
+ "需求分析",
179
+ "方案设计",
180
+ "实现阶段",
181
+ "测试阶段",
182
+ "部署阶段",
183
+ "上线过程",
184
+ "故障排查",
185
+ "故障恢复",
186
+ "终端命令",
187
+ "调试器",
188
+ "编辑器",
189
+ "浏览器",
190
+ "编译器",
191
+ "构建工具",
192
+ "打包工具",
193
+ "认证回调",
194
+ "回调状态",
195
+ "回调验证",
196
+ "状态处理",
197
+ "状态流转",
198
+ "登录异常",
199
+ "登录失败",
200
+ "修复登录",
201
+ "生产环境",
202
+ "工作区",
203
+ "频道记忆",
204
+ "记忆系统",
205
+ "记忆子系统",
206
+ "持久记忆",
207
+ "工作记忆",
208
+ "会话记忆",
209
+ ]);
210
+ //# sourceMappingURL=chinese-words.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chinese-words.js","sourceRoot":"","sources":["../../src/memory/chinese-words.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAS;IACnD,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,MAAM;IACN,KAAK;IACL,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,MAAM;IACN,MAAM;IACN,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;CACN,CAAC,CAAC","sourcesContent":["export const COMMON_CHINESE_WORDS = new Set<string>([\n\t\"当前状态\",\n\t\"当前工作\",\n\t\"工作状态\",\n\t\"会话状态\",\n\t\"任务状态\",\n\t\"当前任务\",\n\t\"工作进度\",\n\t\"用户意图\",\n\t\"活跃文件\",\n\t\"错误修正\",\n\t\"下一步\",\n\t\"接下来\",\n\t\"后续步骤\",\n\t\"后续计划\",\n\t\"待办事项\",\n\t\"开放问题\",\n\t\"开放循环\",\n\t\"关键事实\",\n\t\"设计决策\",\n\t\"关键决策\",\n\t\"约束条件\",\n\t\"技术约束\",\n\t\"兼容要求\",\n\t\"接口稳定\",\n\t\"协议变更\",\n\t\"修复方案\",\n\t\"实现方案\",\n\t\"优化方案\",\n\t\"根因分析\",\n\t\"问题定位\",\n\t\"错误信息\",\n\t\"调试过程\",\n\t\"排查过程\",\n\t\"实现细节\",\n\t\"调用链路\",\n\t\"模块边界\",\n\t\"领域边界\",\n\t\"文件路径\",\n\t\"运行时\",\n\t\"子代理\",\n\t\"工具调用\",\n\t\"上下文\",\n\t\"上下文恢复\",\n\t\"上下文窗口\",\n\t\"上下文注入\",\n\t\"注入上下文\",\n\t\"当前问题\",\n\t\"历史问题\",\n\t\"历史记录\",\n\t\"历史恢复\",\n\t\"历史叙事\",\n\t\"历史块\",\n\t\"摘要块\",\n\t\"发布记录\",\n\t\"部署记录\",\n\t\"旧发布\",\n\t\"旧记录\",\n\t\"早期历史\",\n\t\"过去工作\",\n\t\"长期任务\",\n\t\"短对话\",\n\t\"短问答\",\n\t\"自然结束\",\n\t\"对话结束\",\n\t\"会话切换\",\n\t\"当前目录\",\n\t\"代码实现\",\n\t\"类型检查\",\n\t\"单元测试\",\n\t\"集成测试\",\n\t\"回归测试\",\n\t\"测试覆盖\",\n\t\"回归风险\",\n\t\"默认配置\",\n\t\"配置项\",\n\t\"参数选择\",\n\t\"超时设置\",\n\t\"内容截断\",\n\t\"内存清理\",\n\t\"背景维护\",\n\t\"增量更新\",\n\t\"历史折叠\",\n\t\"持久化\",\n\t\"一致性\",\n\t\"可靠性\",\n\t\"稳定性\",\n\t\"兼容性\",\n\t\"相关性\",\n\t\"评分模型\",\n\t\"检索候选\",\n\t\"候选集合\",\n\t\"召回候选\",\n\t\"中文分词\",\n\t\"词表分词\",\n\t\"最大匹配\",\n\t\"服务器\",\n\t\"数据库\",\n\t\"数据表\",\n\t\"缓存\",\n\t\"队列\",\n\t\"网络\",\n\t\"集群\",\n\t\"容器\",\n\t\"网关\",\n\t\"代理服务\",\n\t\"负载均衡\",\n\t\"配置中心\",\n\t\"注册中心\",\n\t\"消息队列\",\n\t\"对象存储\",\n\t\"日志系统\",\n\t\"监控系统\",\n\t\"告警系统\",\n\t\"文件系统\",\n\t\"函数\",\n\t\"变量\",\n\t\"常量\",\n\t\"接口\",\n\t\"类型定义\",\n\t\"类型系统\",\n\t\"模块\",\n\t\"组件\",\n\t\"服务层\",\n\t\"数据层\",\n\t\"控制层\",\n\t\"依赖注入\",\n\t\"继承关系\",\n\t\"抽象层\",\n\t\"实现层\",\n\t\"状态管理\",\n\t\"异常处理\",\n\t\"错误处理\",\n\t\"并发控制\",\n\t\"并发请求\",\n\t\"异步任务\",\n\t\"同步调用\",\n\t\"回调函数\",\n\t\"中间件\",\n\t\"过滤器\",\n\t\"拦截器\",\n\t\"路由配置\",\n\t\"认证授权\",\n\t\"用户认证\",\n\t\"权限控制\",\n\t\"会话管理\",\n\t\"请求参数\",\n\t\"响应结果\",\n\t\"接口调用\",\n\t\"请求头\",\n\t\"响应头\",\n\t\"重试机制\",\n\t\"降级策略\",\n\t\"熔断机制\",\n\t\"事务处理\",\n\t\"事务回滚\",\n\t\"索引优化\",\n\t\"数据迁移\",\n\t\"数据同步\",\n\t\"备份恢复\",\n\t\"锁机制\",\n\t\"乐观锁\",\n\t\"悲观锁\",\n\t\"死锁问题\",\n\t\"查询语句\",\n\t\"分页查询\",\n\t\"条件过滤\",\n\t\"批量操作\",\n\t\"性能问题\",\n\t\"性能优化\",\n\t\"内存泄漏\",\n\t\"资源释放\",\n\t\"构建流程\",\n\t\"编译过程\",\n\t\"打包流程\",\n\t\"发布流程\",\n\t\"回滚方案\",\n\t\"需求分析\",\n\t\"方案设计\",\n\t\"实现阶段\",\n\t\"测试阶段\",\n\t\"部署阶段\",\n\t\"上线过程\",\n\t\"故障排查\",\n\t\"故障恢复\",\n\t\"终端命令\",\n\t\"调试器\",\n\t\"编辑器\",\n\t\"浏览器\",\n\t\"编译器\",\n\t\"构建工具\",\n\t\"打包工具\",\n\t\"认证回调\",\n\t\"回调状态\",\n\t\"回调验证\",\n\t\"状态处理\",\n\t\"状态流转\",\n\t\"登录异常\",\n\t\"登录失败\",\n\t\"修复登录\",\n\t\"生产环境\",\n\t\"工作区\",\n\t\"频道记忆\",\n\t\"记忆系统\",\n\t\"记忆子系统\",\n\t\"持久记忆\",\n\t\"工作记忆\",\n\t\"会话记忆\",\n]);\n"]}
@@ -19,4 +19,4 @@ export interface BackgroundMaintenanceResult {
19
19
  }
20
20
  export declare function runInlineConsolidation(options: ConsolidationRunOptions): Promise<InlineConsolidationResult>;
21
21
  export declare function runBackgroundMaintenance(options: ConsolidationRunOptions): Promise<BackgroundMaintenanceResult>;
22
- //# sourceMappingURL=memory-consolidation.d.ts.map
22
+ //# sourceMappingURL=consolidation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidation.d.ts","sourceRoot":"","sources":["../../src/memory/consolidation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,GAAG,EAA6B,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAEN,KAAK,YAAY,EAGjB,MAAM,+BAA+B,CAAC;AAoFvC,MAAM,WAAW,uBAAuB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACtD,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,cAAc,CAAC,EAAE,YAAY,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,yBAAyB;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,oBAAoB,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,2BAA2B;IAC3C,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;CACvB;AA0HD,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAkCjH;AA8DD,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAQrH"}
@@ -1,13 +1,16 @@
1
1
  import { getLatestCompactionEntry, serializeConversation, } from "@mariozechner/pi-coding-agent";
2
- import { parseJsonObject } from "./llm-json.js";
3
- import { appendChannelHistoryBlock, appendChannelMemoryUpdate, readChannelHistory, readChannelMemory, readChannelSession, rewriteChannelHistory, rewriteChannelMemory, splitMarkdownSections, } from "./memory-files.js";
4
- import { runSidecarTask } from "./sidecar-worker.js";
2
+ import { parseJsonObject } from "../llm-json.js";
3
+ import { splitH2Sections } from "../shared/markdown-sections.js";
4
+ import { clipText } from "../shared/text-utils.js";
5
+ import { buildStandardMessages } from "../shared/type-guards.js";
6
+ import { runSidecarTask } from "../sidecar-worker.js";
7
+ import { appendChannelHistoryBlock, appendChannelMemoryUpdate, readChannelHistory, readChannelMemory, readChannelSession, rewriteChannelHistory, rewriteChannelMemory, } from "./files.js";
5
8
  const INLINE_TRANSCRIPT_MAX_CHARS = 28_000;
6
- const MEMORY_CLEANUP_LENGTH_THRESHOLD = 8_000;
7
- const MEMORY_UPDATE_BLOCK_THRESHOLD = 6;
8
- const HISTORY_LENGTH_THRESHOLD = 16_000;
9
- const HISTORY_BLOCK_THRESHOLD = 8;
10
- const HISTORY_RECENT_BLOCKS_TO_KEEP = 4;
9
+ const MEMORY_CLEANUP_LENGTH_THRESHOLD = 5_000;
10
+ const MEMORY_UPDATE_BLOCK_THRESHOLD = 4;
11
+ const HISTORY_LENGTH_THRESHOLD = 8_000;
12
+ const HISTORY_BLOCK_THRESHOLD = 5;
13
+ const HISTORY_RECENT_BLOCKS_TO_KEEP = 3;
11
14
  const INLINE_CONSOLIDATION_TIMEOUT_MS = 20_000;
12
15
  const MEMORY_CLEANUP_TIMEOUT_MS = 30_000;
13
16
  const HISTORY_FOLDING_TIMEOUT_MS = 30_000;
@@ -28,8 +31,15 @@ Rules:
28
31
  - Do not include ephemeral chatter, obvious one-shot acknowledgements, or formatting instructions.
29
32
  - Prefer leaving highly volatile step-by-step execution state in SESSION.md rather than promoting it into durable memory.
30
33
  - historyBlock: concise Markdown summarizing the conversation chunk for later recovery.
34
+ - For any conversation that contains at least one meaningful user request and one meaningful assistant reply, return a non-empty historyBlock with at least one bullet.
31
35
  - Prefer short bullets and short paragraphs.
32
- - If there is nothing worth storing, return empty values.`;
36
+ - If there is nothing worth storing, return empty values.
37
+
38
+ Example output for a short useful exchange:
39
+ {
40
+ "memoryEntries": ["User prefers dark mode in the dashboard"],
41
+ "historyBlock": "- User asked how to toggle dashboard theme; confirmed dark mode preference."
42
+ }`;
33
43
  const MEMORY_CLEANUP_SYSTEM_PROMPT = `You are rewriting a Pipiclaw channel MEMORY.md file.
34
44
 
35
45
  Return Markdown only. Do not use code fences.
@@ -62,15 +72,6 @@ Goals:
62
72
  function normalizeText(text) {
63
73
  return text.replace(/\r/g, "").trim();
64
74
  }
65
- function clipTranscript(text, maxChars) {
66
- const normalized = normalizeText(text);
67
- if (normalized.length <= maxChars) {
68
- return normalized;
69
- }
70
- const headChars = Math.floor(maxChars * 0.35);
71
- const tailChars = maxChars - headChars;
72
- return `${normalized.slice(0, headChars)}\n\n[... omitted middle section ...]\n\n${normalized.slice(-tailChars)}`;
73
- }
74
75
  function parseConsolidationResponse(text) {
75
76
  const parsed = parseJsonObject(text);
76
77
  return {
@@ -93,15 +94,6 @@ function getLatestCompactionBoundary(entries) {
93
94
  function isMessage(entry) {
94
95
  return entry.type === "message";
95
96
  }
96
- function isStandardAgentMessage(message) {
97
- return (typeof message === "object" &&
98
- message !== null &&
99
- "role" in message &&
100
- (message.role === "user" || message.role === "assistant" || message.role === "toolResult"));
101
- }
102
- function buildMessagesForConsolidation(messages) {
103
- return messages.filter(isStandardAgentMessage);
104
- }
105
97
  function extractMessagesFromSessionEntries(entries) {
106
98
  return entries.filter(isMessage).map((entry) => entry.message);
107
99
  }
@@ -130,7 +122,7 @@ function hasMeaningfulMessages(messages) {
130
122
  return false;
131
123
  }
132
124
  function countMatchingSectionHeadings(content, prefix) {
133
- return splitMarkdownSections(content).filter((section) => section.heading.startsWith(prefix)).length;
125
+ return splitH2Sections(content).filter((section) => section.heading.startsWith(prefix)).length;
134
126
  }
135
127
  async function runWorkerPrompt(name, model, resolveApiKey, systemPrompt, prompt, timeoutMs) {
136
128
  const result = await runSidecarTask({
@@ -145,10 +137,10 @@ async function runWorkerPrompt(name, model, resolveApiKey, systemPrompt, prompt,
145
137
  return result.output;
146
138
  }
147
139
  async function buildInlineConsolidationResponse(options, messages) {
148
- const transcript = clipTranscript(serializeConversation(messages), INLINE_TRANSCRIPT_MAX_CHARS);
149
- const currentMemory = clipTranscript(await readChannelMemory(options.channelDir), 8_000);
150
- const currentSession = clipTranscript(await readChannelSession(options.channelDir), 8_000);
151
- const currentHistory = clipTranscript(await readChannelHistory(options.channelDir), 8_000);
140
+ const transcript = clipText(serializeConversation(messages), INLINE_TRANSCRIPT_MAX_CHARS, { headRatio: 0.35 });
141
+ const currentMemory = clipText(await readChannelMemory(options.channelDir), 8_000, { headRatio: 0.35 });
142
+ const currentSession = clipText(await readChannelSession(options.channelDir), 8_000, { headRatio: 0.35 });
143
+ const currentHistory = clipText(await readChannelHistory(options.channelDir), 8_000, { headRatio: 0.35 });
152
144
  const prompt = `Current SESSION.md:
153
145
  ${currentSession || "(empty)"}
154
146
 
@@ -166,7 +158,7 @@ ${transcript || "(empty)"}`;
166
158
  export async function runInlineConsolidation(options) {
167
159
  const sourceEntries = options.sessionEntries ?? [];
168
160
  const relevantEntries = sourceEntries.length > 0 ? sourceEntries.slice(getLatestCompactionBoundary(sourceEntries)) : sourceEntries;
169
- const relevantMessages = buildMessagesForConsolidation(relevantEntries.length > 0 ? extractMessagesFromSessionEntries(relevantEntries) : options.messages);
161
+ const relevantMessages = buildStandardMessages(relevantEntries.length > 0 ? extractMessagesFromSessionEntries(relevantEntries) : options.messages);
170
162
  if (!hasMeaningfulMessages(relevantMessages)) {
171
163
  return { skipped: true, appendedMemoryEntries: 0, appendedHistoryBlock: false };
172
164
  }
@@ -202,7 +194,7 @@ ${currentMemory}`;
202
194
  return true;
203
195
  }
204
196
  async function foldChannelHistory(options, currentHistory) {
205
- const sections = splitMarkdownSections(currentHistory);
197
+ const sections = splitH2Sections(currentHistory);
206
198
  if (currentHistory.length < HISTORY_LENGTH_THRESHOLD && sections.length < HISTORY_BLOCK_THRESHOLD) {
207
199
  return false;
208
200
  }
@@ -234,4 +226,4 @@ export async function runBackgroundMaintenance(options) {
234
226
  const foldedHistory = await foldChannelHistory(options, currentHistory);
235
227
  return { cleanedMemory, foldedHistory };
236
228
  }
237
- //# sourceMappingURL=memory-consolidation.js.map
229
+ //# sourceMappingURL=consolidation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidation.js","sourceRoot":"","sources":["../../src/memory/consolidation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@mariozechner/pi-agent-core\";\nimport type { Api, AssistantMessage, Message, Model } from \"@mariozechner/pi-ai\";\nimport {\n\tgetLatestCompactionEntry,\n\ttype SessionEntry,\n\ttype SessionMessageEntry,\n\tserializeConversation,\n} from \"@mariozechner/pi-coding-agent\";\nimport { parseJsonObject } from \"../llm-json.js\";\nimport { splitH2Sections } from \"../shared/markdown-sections.js\";\nimport { clipText } from \"../shared/text-utils.js\";\nimport { buildStandardMessages } from \"../shared/type-guards.js\";\nimport { runSidecarTask } from \"../sidecar-worker.js\";\nimport {\n\tappendChannelHistoryBlock,\n\tappendChannelMemoryUpdate,\n\treadChannelHistory,\n\treadChannelMemory,\n\treadChannelSession,\n\trewriteChannelHistory,\n\trewriteChannelMemory,\n} from \"./files.js\";\n\nconst INLINE_TRANSCRIPT_MAX_CHARS = 28_000;\nconst MEMORY_CLEANUP_LENGTH_THRESHOLD = 5_000;\nconst MEMORY_UPDATE_BLOCK_THRESHOLD = 4;\nconst HISTORY_LENGTH_THRESHOLD = 8_000;\nconst HISTORY_BLOCK_THRESHOLD = 5;\nconst HISTORY_RECENT_BLOCKS_TO_KEEP = 3;\nconst INLINE_CONSOLIDATION_TIMEOUT_MS = 20_000;\nconst MEMORY_CLEANUP_TIMEOUT_MS = 30_000;\nconst HISTORY_FOLDING_TIMEOUT_MS = 30_000;\n\nconst INLINE_CONSOLIDATION_SYSTEM_PROMPT = `You are a runtime memory consolidation worker for Pipiclaw.\n\nReturn strict JSON only. Do not wrap in Markdown fences.\n\nOutput schema:\n{\n \"memoryEntries\": [\"string\"],\n \"historyBlock\": \"string\"\n}\n\nRules:\n- memoryEntries: concise durable facts, decisions, preferences, constraints, current work state, or open loops that should survive compaction.\n- Each memoryEntries item must be a standalone sentence fragment suitable for a Markdown bullet without the bullet prefix.\n- Do not include raw transcript quotes unless essential.\n- Do not include ephemeral chatter, obvious one-shot acknowledgements, or formatting instructions.\n- Prefer leaving highly volatile step-by-step execution state in SESSION.md rather than promoting it into durable memory.\n- historyBlock: concise Markdown summarizing the conversation chunk for later recovery.\n- For any conversation that contains at least one meaningful user request and one meaningful assistant reply, return a non-empty historyBlock with at least one bullet.\n- Prefer short bullets and short paragraphs.\n- If there is nothing worth storing, return empty values.\n\nExample output for a short useful exchange:\n{\n \"memoryEntries\": [\"User prefers dark mode in the dashboard\"],\n \"historyBlock\": \"- User asked how to toggle dashboard theme; confirmed dark mode preference.\"\n}`;\n\nconst MEMORY_CLEANUP_SYSTEM_PROMPT = `You are rewriting a Pipiclaw channel MEMORY.md file.\n\nReturn Markdown only. Do not use code fences.\n\nGoals:\n- Keep only durable and useful channel memory.\n- Remove outdated entries, duplicates, and verbose phrasing.\n- Organize the result with stable sections where relevant.\n- Prefer concise bullets over prose.\n- Remove content that is clearly transient session-state and belongs in SESSION.md instead.\n\nSuggested sections:\n- ## Identity / Participants\n- ## Preferences\n- ## Ongoing Work\n- ## Constraints\n- ## Decisions\n- ## Open Loops\n\nOmit empty sections.`;\n\nconst HISTORY_FOLDING_SYSTEM_PROMPT = `You are folding older HISTORY.md blocks for Pipiclaw.\n\nReturn Markdown only. Do not use code fences.\n\nGoals:\n- Compress older history blocks into one concise summary block.\n- Keep important decisions, milestones, and unresolved outcomes.\n- Remove redundancy and transcript-like detail.\n- Preserve a chronological narrative at a high level.`;\n\nexport interface ConsolidationRunOptions {\n\tchannelDir: string;\n\tmodel: Model<Api>;\n\tresolveApiKey: (model: Model<Api>) => Promise<string>;\n\tmessages: AgentMessage[];\n\tsessionEntries?: SessionEntry[];\n}\n\nexport interface InlineConsolidationResult {\n\tskipped: boolean;\n\tappendedMemoryEntries: number;\n\tappendedHistoryBlock: boolean;\n}\n\nexport interface BackgroundMaintenanceResult {\n\tcleanedMemory: boolean;\n\tfoldedHistory: boolean;\n}\n\ninterface ConsolidationResponse {\n\tmemoryEntries: string[];\n\thistoryBlock: string;\n}\n\nfunction normalizeText(text: string): string {\n\treturn text.replace(/\\r/g, \"\").trim();\n}\n\nfunction parseConsolidationResponse(text: string): ConsolidationResponse {\n\tconst parsed = parseJsonObject(text) as Partial<ConsolidationResponse>;\n\treturn {\n\t\tmemoryEntries: Array.isArray(parsed.memoryEntries)\n\t\t\t? parsed.memoryEntries\n\t\t\t\t\t.map((entry) => (typeof entry === \"string\" ? entry.trim() : \"\"))\n\t\t\t\t\t.filter((entry) => entry.length > 0)\n\t\t\t: [],\n\t\thistoryBlock: typeof parsed.historyBlock === \"string\" ? parsed.historyBlock.trim() : \"\",\n\t};\n}\n\nfunction getLatestCompactionBoundary(entries: SessionEntry[]): number {\n\tconst latestCompaction = getLatestCompactionEntry(entries);\n\tif (!latestCompaction) {\n\t\treturn 0;\n\t}\n\n\tconst boundaryIndex = entries.findIndex((entry) => entry.id === latestCompaction.firstKeptEntryId);\n\treturn boundaryIndex >= 0 ? boundaryIndex : 0;\n}\n\nfunction isMessage(entry: SessionEntry): entry is SessionMessageEntry {\n\treturn entry.type === \"message\";\n}\n\nfunction extractMessagesFromSessionEntries(entries: SessionEntry[]): AgentMessage[] {\n\treturn entries.filter(isMessage).map((entry) => entry.message);\n}\n\nfunction hasMeaningfulMessages(messages: Message[]): boolean {\n\tlet meaningfulCount = 0;\n\tfor (const message of messages) {\n\t\tif (message.role === \"user\") {\n\t\t\tconst text =\n\t\t\t\ttypeof message.content === \"string\"\n\t\t\t\t\t? message.content\n\t\t\t\t\t: message.content.map((part) => (part.type === \"text\" ? part.text : \"[image]\")).join(\"\\n\");\n\t\t\tif (text.trim()) meaningfulCount++;\n\t\t} else if (message.role === \"assistant\") {\n\t\t\tconst text = message.content\n\t\t\t\t.filter(\n\t\t\t\t\t(part): part is Extract<AssistantMessage[\"content\"][number], { type: \"text\" }> => part.type === \"text\",\n\t\t\t\t)\n\t\t\t\t.map((part) => part.text)\n\t\t\t\t.join(\"\\n\");\n\t\t\tif (text.trim()) meaningfulCount++;\n\t\t}\n\t\tif (meaningfulCount >= 2) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction countMatchingSectionHeadings(content: string, prefix: string): number {\n\treturn splitH2Sections(content).filter((section) => section.heading.startsWith(prefix)).length;\n}\n\nasync function runWorkerPrompt(\n\tname: string,\n\tmodel: Model<Api>,\n\tresolveApiKey: (model: Model<Api>) => Promise<string>,\n\tsystemPrompt: string,\n\tprompt: string,\n\ttimeoutMs: number,\n): Promise<string> {\n\tconst result = await runSidecarTask({\n\t\tname,\n\t\tmodel,\n\t\tresolveApiKey,\n\t\tsystemPrompt,\n\t\tprompt,\n\t\ttimeoutMs,\n\t\tparse: (text) => text.trim(),\n\t});\n\treturn result.output;\n}\n\nasync function buildInlineConsolidationResponse(\n\toptions: ConsolidationRunOptions,\n\tmessages: Message[],\n): Promise<ConsolidationResponse> {\n\tconst transcript = clipText(serializeConversation(messages), INLINE_TRANSCRIPT_MAX_CHARS, { headRatio: 0.35 });\n\tconst currentMemory = clipText(await readChannelMemory(options.channelDir), 8_000, { headRatio: 0.35 });\n\tconst currentSession = clipText(await readChannelSession(options.channelDir), 8_000, { headRatio: 0.35 });\n\tconst currentHistory = clipText(await readChannelHistory(options.channelDir), 8_000, { headRatio: 0.35 });\n\n\tconst prompt = `Current SESSION.md:\n${currentSession || \"(empty)\"}\n\nChannel memory file:\n${currentMemory || \"(empty)\"}\n\nChannel history file:\n${currentHistory || \"(empty)\"}\n\nConversation chunk to persist:\n${transcript || \"(empty)\"}`;\n\n\tconst rawResponse = await runWorkerPrompt(\n\t\t\"memory-inline-consolidation\",\n\t\toptions.model,\n\t\toptions.resolveApiKey,\n\t\tINLINE_CONSOLIDATION_SYSTEM_PROMPT,\n\t\tprompt,\n\t\tINLINE_CONSOLIDATION_TIMEOUT_MS,\n\t);\n\treturn parseConsolidationResponse(rawResponse);\n}\n\nexport async function runInlineConsolidation(options: ConsolidationRunOptions): Promise<InlineConsolidationResult> {\n\tconst sourceEntries = options.sessionEntries ?? [];\n\tconst relevantEntries =\n\t\tsourceEntries.length > 0 ? sourceEntries.slice(getLatestCompactionBoundary(sourceEntries)) : sourceEntries;\n\tconst relevantMessages = buildStandardMessages(\n\t\trelevantEntries.length > 0 ? extractMessagesFromSessionEntries(relevantEntries) : options.messages,\n\t);\n\n\tif (!hasMeaningfulMessages(relevantMessages)) {\n\t\treturn { skipped: true, appendedMemoryEntries: 0, appendedHistoryBlock: false };\n\t}\n\n\tconst response = await buildInlineConsolidationResponse(options, relevantMessages);\n\tconst timestamp = new Date().toISOString();\n\n\tif (response.memoryEntries.length > 0) {\n\t\tawait appendChannelMemoryUpdate(options.channelDir, {\n\t\t\ttimestamp,\n\t\t\tentries: response.memoryEntries,\n\t\t});\n\t}\n\n\tif (response.historyBlock.trim()) {\n\t\tawait appendChannelHistoryBlock(options.channelDir, {\n\t\t\ttimestamp,\n\t\t\tcontent: response.historyBlock,\n\t\t});\n\t}\n\n\treturn {\n\t\tskipped: false,\n\t\tappendedMemoryEntries: response.memoryEntries.length,\n\t\tappendedHistoryBlock: response.historyBlock.trim().length > 0,\n\t};\n}\n\nasync function cleanupChannelMemory(options: ConsolidationRunOptions, currentMemory: string): Promise<boolean> {\n\tif (\n\t\tcurrentMemory.length < MEMORY_CLEANUP_LENGTH_THRESHOLD &&\n\t\tcountMatchingSectionHeadings(currentMemory, \"Update \") < MEMORY_UPDATE_BLOCK_THRESHOLD\n\t) {\n\t\treturn false;\n\t}\n\n\tconst prompt = `Current MEMORY.md:\n${currentMemory}`;\n\tconst nextMemory = await runWorkerPrompt(\n\t\t\"memory-cleanup\",\n\t\toptions.model,\n\t\toptions.resolveApiKey,\n\t\tMEMORY_CLEANUP_SYSTEM_PROMPT,\n\t\tprompt,\n\t\tMEMORY_CLEANUP_TIMEOUT_MS,\n\t);\n\tawait rewriteChannelMemory(options.channelDir, nextMemory);\n\treturn true;\n}\n\nasync function foldChannelHistory(options: ConsolidationRunOptions, currentHistory: string): Promise<boolean> {\n\tconst sections = splitH2Sections(currentHistory);\n\tif (currentHistory.length < HISTORY_LENGTH_THRESHOLD && sections.length < HISTORY_BLOCK_THRESHOLD) {\n\t\treturn false;\n\t}\n\n\tif (sections.length <= HISTORY_RECENT_BLOCKS_TO_KEEP) {\n\t\treturn false;\n\t}\n\n\tconst olderSections = sections.slice(0, -HISTORY_RECENT_BLOCKS_TO_KEEP);\n\tconst recentSections = sections.slice(-HISTORY_RECENT_BLOCKS_TO_KEEP);\n\tconst prompt = `Older history blocks to fold:\n${olderSections.map((section) => `## ${section.heading}\\n\\n${section.content}`).join(\"\\n\\n\")}`;\n\tconst foldedSummary = await runWorkerPrompt(\n\t\t\"history-folding\",\n\t\toptions.model,\n\t\toptions.resolveApiKey,\n\t\tHISTORY_FOLDING_SYSTEM_PROMPT,\n\t\tprompt,\n\t\tHISTORY_FOLDING_TIMEOUT_MS,\n\t);\n\n\tconst foldedHeading = `## Folded History Through ${olderSections[olderSections.length - 1]?.heading ?? new Date().toISOString()}`;\n\tconst rebuiltHistory = [\n\t\t\"# Channel History\",\n\t\t\"\",\n\t\tfoldedHeading,\n\t\t\"\",\n\t\tnormalizeText(foldedSummary),\n\t\t\"\",\n\t\t...recentSections.flatMap((section) => [`## ${section.heading}`, \"\", normalizeText(section.content), \"\"]),\n\t].join(\"\\n\");\n\n\tawait rewriteChannelHistory(options.channelDir, rebuiltHistory);\n\treturn true;\n}\n\nexport async function runBackgroundMaintenance(options: ConsolidationRunOptions): Promise<BackgroundMaintenanceResult> {\n\tconst currentMemory = await readChannelMemory(options.channelDir);\n\tconst currentHistory = await readChannelHistory(options.channelDir);\n\n\tconst cleanedMemory = await cleanupChannelMemory(options, currentMemory);\n\tconst foldedHistory = await foldChannelHistory(options, currentHistory);\n\n\treturn { cleanedMemory, foldedHistory };\n}\n"]}
@@ -19,9 +19,4 @@ export declare function rewriteChannelHistory(channelDir: string, content: strin
19
19
  export declare function rewriteChannelSession(channelDir: string, content: string): Promise<void>;
20
20
  export declare function appendChannelMemoryUpdate(channelDir: string, block: MemoryUpdateBlock): Promise<void>;
21
21
  export declare function appendChannelHistoryBlock(channelDir: string, block: HistoryBlock): Promise<void>;
22
- export interface MarkdownSection {
23
- heading: string;
24
- content: string;
25
- }
26
- export declare function splitMarkdownSections(content: string): MarkdownSection[];
27
- //# sourceMappingURL=memory-files.d.ts.map
22
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/memory/files.ts"],"names":[],"mappings":"AA+DA,MAAM,WAAW,iBAAiB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CAChB;AAiBD,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAsB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhF;AAED,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAgBrE;AAiBD,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE3E;AAED,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE5E;AAED,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE5E;AAED,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7F;AAED,wBAAsB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI9F;AAED,wBAAsB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI9F;AAED,wBAAsB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAY3G;AAED,wBAAsB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAWtG"}
@@ -97,10 +97,18 @@ export function ensureChannelMemoryFilesSync(channelDir) {
97
97
  }
98
98
  }
99
99
  async function readTextFile(path) {
100
- if (!existsSync(path)) {
101
- return "";
100
+ try {
101
+ return await readFile(path, "utf-8");
102
102
  }
103
- return readFile(path, "utf-8");
103
+ catch (error) {
104
+ if (isNodeError(error) && error.code === "ENOENT") {
105
+ return "";
106
+ }
107
+ throw error;
108
+ }
109
+ }
110
+ function isNodeError(error) {
111
+ return error instanceof Error && "code" in error;
104
112
  }
105
113
  export async function readChannelMemory(channelDir) {
106
114
  return readTextFile(getChannelMemoryPath(channelDir));
@@ -147,36 +155,4 @@ export async function appendChannelHistoryBlock(channelDir, block) {
147
155
  const renderedBlock = [`## ${block.timestamp}`, trimmedContent].join("\n\n");
148
156
  await writeAtomically(path, `${ensureTrailingNewlines(existing)}${renderedBlock}\n`);
149
157
  }
150
- export function splitMarkdownSections(content) {
151
- const normalized = content.replace(/\r/g, "").trim();
152
- if (!normalized) {
153
- return [];
154
- }
155
- const lines = normalized.split("\n");
156
- const sections = [];
157
- let currentHeading = "";
158
- let currentLines = [];
159
- const flush = () => {
160
- if (!currentHeading) {
161
- return;
162
- }
163
- sections.push({
164
- heading: currentHeading,
165
- content: currentLines.join("\n").trim(),
166
- });
167
- };
168
- for (const line of lines) {
169
- if (line.startsWith("## ")) {
170
- flush();
171
- currentHeading = line.slice(3).trim();
172
- currentLines = [];
173
- continue;
174
- }
175
- if (currentHeading) {
176
- currentLines.push(line);
177
- }
178
- }
179
- flush();
180
- return sections;
181
- }
182
- //# sourceMappingURL=memory-files.js.map
158
+ //# sourceMappingURL=files.js.map