@caupulican/pi-adaptative 0.80.86 → 0.80.89

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 (353) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/dist/core/agent-session.d.ts +412 -1
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +2053 -41
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/autonomy/approval-gate.d.ts +4 -0
  7. package/dist/core/autonomy/approval-gate.d.ts.map +1 -0
  8. package/dist/core/autonomy/approval-gate.js +27 -0
  9. package/dist/core/autonomy/approval-gate.js.map +1 -0
  10. package/dist/core/autonomy/bounded-completion.d.ts +27 -0
  11. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -0
  12. package/dist/core/autonomy/bounded-completion.js +44 -0
  13. package/dist/core/autonomy/bounded-completion.js.map +1 -0
  14. package/dist/core/autonomy/contracts.d.ts +129 -0
  15. package/dist/core/autonomy/contracts.d.ts.map +1 -0
  16. package/dist/core/autonomy/contracts.js +2 -0
  17. package/dist/core/autonomy/contracts.js.map +1 -0
  18. package/dist/core/autonomy/gates.d.ts +15 -0
  19. package/dist/core/autonomy/gates.d.ts.map +1 -0
  20. package/dist/core/autonomy/gates.js +205 -0
  21. package/dist/core/autonomy/gates.js.map +1 -0
  22. package/dist/core/autonomy/lane-tracker.d.ts +48 -0
  23. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -0
  24. package/dist/core/autonomy/lane-tracker.js +125 -0
  25. package/dist/core/autonomy/lane-tracker.js.map +1 -0
  26. package/dist/core/autonomy/path-scope.d.ts +9 -0
  27. package/dist/core/autonomy/path-scope.d.ts.map +1 -0
  28. package/dist/core/autonomy/path-scope.js +122 -0
  29. package/dist/core/autonomy/path-scope.js.map +1 -0
  30. package/dist/core/autonomy/risk-assessment.d.ts +3 -0
  31. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -0
  32. package/dist/core/autonomy/risk-assessment.js +122 -0
  33. package/dist/core/autonomy/risk-assessment.js.map +1 -0
  34. package/dist/core/autonomy/session-lane-record.d.ts +10 -0
  35. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -0
  36. package/dist/core/autonomy/session-lane-record.js +36 -0
  37. package/dist/core/autonomy/session-lane-record.js.map +1 -0
  38. package/dist/core/autonomy/status.d.ts +40 -0
  39. package/dist/core/autonomy/status.d.ts.map +1 -0
  40. package/dist/core/autonomy/status.js +107 -0
  41. package/dist/core/autonomy/status.js.map +1 -0
  42. package/dist/core/autonomy/subagent-prompt.d.ts +21 -0
  43. package/dist/core/autonomy/subagent-prompt.d.ts.map +1 -0
  44. package/dist/core/autonomy/subagent-prompt.js +28 -0
  45. package/dist/core/autonomy/subagent-prompt.js.map +1 -0
  46. package/dist/core/autonomy/telemetry-events.d.ts +18 -0
  47. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -0
  48. package/dist/core/autonomy/telemetry-events.js +60 -0
  49. package/dist/core/autonomy/telemetry-events.js.map +1 -0
  50. package/dist/core/context/artifact-retrieval.d.ts +49 -0
  51. package/dist/core/context/artifact-retrieval.d.ts.map +1 -0
  52. package/dist/core/context/artifact-retrieval.js +49 -0
  53. package/dist/core/context/artifact-retrieval.js.map +1 -0
  54. package/dist/core/context/brain-curator.d.ts +88 -0
  55. package/dist/core/context/brain-curator.d.ts.map +1 -0
  56. package/dist/core/context/brain-curator.js +192 -0
  57. package/dist/core/context/brain-curator.js.map +1 -0
  58. package/dist/core/context/context-artifacts.d.ts +94 -0
  59. package/dist/core/context/context-artifacts.d.ts.map +1 -0
  60. package/dist/core/context/context-artifacts.js +307 -0
  61. package/dist/core/context/context-artifacts.js.map +1 -0
  62. package/dist/core/context/context-audit.d.ts +66 -0
  63. package/dist/core/context/context-audit.d.ts.map +1 -0
  64. package/dist/core/context/context-audit.js +173 -0
  65. package/dist/core/context/context-audit.js.map +1 -0
  66. package/dist/core/context/context-composition.d.ts +122 -0
  67. package/dist/core/context/context-composition.d.ts.map +1 -0
  68. package/dist/core/context/context-composition.js +163 -0
  69. package/dist/core/context/context-composition.js.map +1 -0
  70. package/dist/core/context/context-item.d.ts +117 -0
  71. package/dist/core/context/context-item.d.ts.map +1 -0
  72. package/dist/core/context/context-item.js +36 -0
  73. package/dist/core/context/context-item.js.map +1 -0
  74. package/dist/core/context/context-prompt-enforcement.d.ts +86 -0
  75. package/dist/core/context/context-prompt-enforcement.d.ts.map +1 -0
  76. package/dist/core/context/context-prompt-enforcement.js +168 -0
  77. package/dist/core/context/context-prompt-enforcement.js.map +1 -0
  78. package/dist/core/context/context-prompt-policy.d.ts +90 -0
  79. package/dist/core/context/context-prompt-policy.d.ts.map +1 -0
  80. package/dist/core/context/context-prompt-policy.js +73 -0
  81. package/dist/core/context/context-prompt-policy.js.map +1 -0
  82. package/dist/core/context/context-retention.d.ts +36 -0
  83. package/dist/core/context/context-retention.d.ts.map +1 -0
  84. package/dist/core/context/context-retention.js +108 -0
  85. package/dist/core/context/context-retention.js.map +1 -0
  86. package/dist/core/context/context-store.d.ts +37 -0
  87. package/dist/core/context/context-store.d.ts.map +1 -0
  88. package/dist/core/context/context-store.js +45 -0
  89. package/dist/core/context/context-store.js.map +1 -0
  90. package/dist/core/context/memory-diagnostics.d.ts +50 -0
  91. package/dist/core/context/memory-diagnostics.d.ts.map +1 -0
  92. package/dist/core/context/memory-diagnostics.js +43 -0
  93. package/dist/core/context/memory-diagnostics.js.map +1 -0
  94. package/dist/core/context/memory-index-store.d.ts +28 -0
  95. package/dist/core/context/memory-index-store.d.ts.map +1 -0
  96. package/dist/core/context/memory-index-store.js +38 -0
  97. package/dist/core/context/memory-index-store.js.map +1 -0
  98. package/dist/core/context/memory-prompt-block.d.ts +34 -0
  99. package/dist/core/context/memory-prompt-block.d.ts.map +1 -0
  100. package/dist/core/context/memory-prompt-block.js +58 -0
  101. package/dist/core/context/memory-prompt-block.js.map +1 -0
  102. package/dist/core/context/memory-provider-contract.d.ts +114 -0
  103. package/dist/core/context/memory-provider-contract.d.ts.map +1 -0
  104. package/dist/core/context/memory-provider-contract.js +121 -0
  105. package/dist/core/context/memory-provider-contract.js.map +1 -0
  106. package/dist/core/context/memory-retrieval.d.ts +27 -0
  107. package/dist/core/context/memory-retrieval.d.ts.map +1 -0
  108. package/dist/core/context/memory-retrieval.js +91 -0
  109. package/dist/core/context/memory-retrieval.js.map +1 -0
  110. package/dist/core/context/okf-memory-provider.d.ts +26 -0
  111. package/dist/core/context/okf-memory-provider.d.ts.map +1 -0
  112. package/dist/core/context/okf-memory-provider.js +154 -0
  113. package/dist/core/context/okf-memory-provider.js.map +1 -0
  114. package/dist/core/context/okf-memory.d.ts +42 -0
  115. package/dist/core/context/okf-memory.d.ts.map +1 -0
  116. package/dist/core/context/okf-memory.js +175 -0
  117. package/dist/core/context/okf-memory.js.map +1 -0
  118. package/dist/core/context/policy-engine.d.ts +66 -0
  119. package/dist/core/context/policy-engine.d.ts.map +1 -0
  120. package/dist/core/context/policy-engine.js +171 -0
  121. package/dist/core/context/policy-engine.js.map +1 -0
  122. package/dist/core/context/policy-types.d.ts +102 -0
  123. package/dist/core/context/policy-types.d.ts.map +1 -0
  124. package/dist/core/context/policy-types.js +7 -0
  125. package/dist/core/context/policy-types.js.map +1 -0
  126. package/dist/core/context/sqlite-runtime-index.d.ts +19 -0
  127. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -0
  128. package/dist/core/context/sqlite-runtime-index.js +344 -0
  129. package/dist/core/context/sqlite-runtime-index.js.map +1 -0
  130. package/dist/core/context/storage-authority.d.ts +20 -0
  131. package/dist/core/context/storage-authority.d.ts.map +1 -0
  132. package/dist/core/context/storage-authority.js +51 -0
  133. package/dist/core/context/storage-authority.js.map +1 -0
  134. package/dist/core/context/tool-output-packer.d.ts +75 -0
  135. package/dist/core/context/tool-output-packer.d.ts.map +1 -0
  136. package/dist/core/context/tool-output-packer.js +77 -0
  137. package/dist/core/context/tool-output-packer.js.map +1 -0
  138. package/dist/core/context-gc.d.ts +13 -0
  139. package/dist/core/context-gc.d.ts.map +1 -1
  140. package/dist/core/context-gc.js +6 -0
  141. package/dist/core/context-gc.js.map +1 -1
  142. package/dist/core/cost/session-usage.d.ts +20 -0
  143. package/dist/core/cost/session-usage.d.ts.map +1 -0
  144. package/dist/core/cost/session-usage.js +164 -0
  145. package/dist/core/cost/session-usage.js.map +1 -0
  146. package/dist/core/delegation/session-worker-result.d.ts +10 -0
  147. package/dist/core/delegation/session-worker-result.d.ts.map +1 -0
  148. package/dist/core/delegation/session-worker-result.js +36 -0
  149. package/dist/core/delegation/session-worker-result.js.map +1 -0
  150. package/dist/core/delegation/worker-result.d.ts +9 -0
  151. package/dist/core/delegation/worker-result.d.ts.map +1 -0
  152. package/dist/core/delegation/worker-result.js +152 -0
  153. package/dist/core/delegation/worker-result.js.map +1 -0
  154. package/dist/core/delegation/worker-runner.d.ts +58 -0
  155. package/dist/core/delegation/worker-runner.d.ts.map +1 -0
  156. package/dist/core/delegation/worker-runner.js +188 -0
  157. package/dist/core/delegation/worker-runner.js.map +1 -0
  158. package/dist/core/extensions/builtin.d.ts +5 -1
  159. package/dist/core/extensions/builtin.d.ts.map +1 -1
  160. package/dist/core/extensions/builtin.js +23 -1
  161. package/dist/core/extensions/builtin.js.map +1 -1
  162. package/dist/core/footer-data-provider.d.ts +5 -1
  163. package/dist/core/footer-data-provider.d.ts.map +1 -1
  164. package/dist/core/footer-data-provider.js +13 -0
  165. package/dist/core/footer-data-provider.js.map +1 -1
  166. package/dist/core/goals/goal-continuation-controller.d.ts +22 -0
  167. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -0
  168. package/dist/core/goals/goal-continuation-controller.js +88 -0
  169. package/dist/core/goals/goal-continuation-controller.js.map +1 -0
  170. package/dist/core/goals/goal-continuation-defaults.d.ts +10 -0
  171. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -0
  172. package/dist/core/goals/goal-continuation-defaults.js +10 -0
  173. package/dist/core/goals/goal-continuation-defaults.js.map +1 -0
  174. package/dist/core/goals/goal-continuation-prompt.d.ts +18 -0
  175. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -0
  176. package/dist/core/goals/goal-continuation-prompt.js +141 -0
  177. package/dist/core/goals/goal-continuation-prompt.js.map +1 -0
  178. package/dist/core/goals/goal-runtime-snapshot.d.ts +19 -0
  179. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -0
  180. package/dist/core/goals/goal-runtime-snapshot.js +23 -0
  181. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -0
  182. package/dist/core/goals/goal-state.d.ts +87 -0
  183. package/dist/core/goals/goal-state.d.ts.map +1 -0
  184. package/dist/core/goals/goal-state.js +259 -0
  185. package/dist/core/goals/goal-state.js.map +1 -0
  186. package/dist/core/goals/goal-tool-core.d.ts +66 -0
  187. package/dist/core/goals/goal-tool-core.d.ts.map +1 -0
  188. package/dist/core/goals/goal-tool-core.js +146 -0
  189. package/dist/core/goals/goal-tool-core.js.map +1 -0
  190. package/dist/core/goals/session-goal-state.d.ts +10 -0
  191. package/dist/core/goals/session-goal-state.d.ts.map +1 -0
  192. package/dist/core/goals/session-goal-state.js +35 -0
  193. package/dist/core/goals/session-goal-state.js.map +1 -0
  194. package/dist/core/learning/learning-audit.d.ts +45 -0
  195. package/dist/core/learning/learning-audit.d.ts.map +1 -0
  196. package/dist/core/learning/learning-audit.js +139 -0
  197. package/dist/core/learning/learning-audit.js.map +1 -0
  198. package/dist/core/learning/learning-gate.d.ts +29 -0
  199. package/dist/core/learning/learning-gate.d.ts.map +1 -0
  200. package/dist/core/learning/learning-gate.js +150 -0
  201. package/dist/core/learning/learning-gate.js.map +1 -0
  202. package/dist/core/learning/session-learning-decision.d.ts +10 -0
  203. package/dist/core/learning/session-learning-decision.d.ts.map +1 -0
  204. package/dist/core/learning/session-learning-decision.js +36 -0
  205. package/dist/core/learning/session-learning-decision.js.map +1 -0
  206. package/dist/core/model-capability.d.ts +41 -0
  207. package/dist/core/model-capability.d.ts.map +1 -0
  208. package/dist/core/model-capability.js +101 -0
  209. package/dist/core/model-capability.js.map +1 -0
  210. package/dist/core/model-router/config-diagnostics.d.ts.map +1 -1
  211. package/dist/core/model-router/config-diagnostics.js +1 -0
  212. package/dist/core/model-router/config-diagnostics.js.map +1 -1
  213. package/dist/core/model-router/intent-classifier.d.ts +2 -0
  214. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  215. package/dist/core/model-router/intent-classifier.js +154 -9
  216. package/dist/core/model-router/intent-classifier.js.map +1 -1
  217. package/dist/core/model-router/route-judge.d.ts +54 -0
  218. package/dist/core/model-router/route-judge.d.ts.map +1 -0
  219. package/dist/core/model-router/route-judge.js +128 -0
  220. package/dist/core/model-router/route-judge.js.map +1 -0
  221. package/dist/core/model-router/status.d.ts +4 -1
  222. package/dist/core/model-router/status.d.ts.map +1 -1
  223. package/dist/core/model-router/status.js +30 -6
  224. package/dist/core/model-router/status.js.map +1 -1
  225. package/dist/core/model-router/tool-escalation.d.ts +4 -6
  226. package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
  227. package/dist/core/model-router/tool-escalation.js +1 -1
  228. package/dist/core/model-router/tool-escalation.js.map +1 -1
  229. package/dist/core/models/fitness-store.d.ts +40 -0
  230. package/dist/core/models/fitness-store.d.ts.map +1 -0
  231. package/dist/core/models/fitness-store.js +61 -0
  232. package/dist/core/models/fitness-store.js.map +1 -0
  233. package/dist/core/profile-registry.d.ts.map +1 -1
  234. package/dist/core/profile-registry.js +1 -1
  235. package/dist/core/profile-registry.js.map +1 -1
  236. package/dist/core/prompt-templates.d.ts +2 -0
  237. package/dist/core/prompt-templates.d.ts.map +1 -1
  238. package/dist/core/prompt-templates.js +12 -4
  239. package/dist/core/prompt-templates.js.map +1 -1
  240. package/dist/core/research/automata-provider.d.ts +5 -0
  241. package/dist/core/research/automata-provider.d.ts.map +1 -0
  242. package/dist/core/research/automata-provider.js +15 -0
  243. package/dist/core/research/automata-provider.js.map +1 -0
  244. package/dist/core/research/evidence-bundle.d.ts +10 -0
  245. package/dist/core/research/evidence-bundle.d.ts.map +1 -0
  246. package/dist/core/research/evidence-bundle.js +116 -0
  247. package/dist/core/research/evidence-bundle.js.map +1 -0
  248. package/dist/core/research/model-fitness.d.ts +82 -0
  249. package/dist/core/research/model-fitness.d.ts.map +1 -0
  250. package/dist/core/research/model-fitness.js +308 -0
  251. package/dist/core/research/model-fitness.js.map +1 -0
  252. package/dist/core/research/research-gate.d.ts +11 -0
  253. package/dist/core/research/research-gate.d.ts.map +1 -0
  254. package/dist/core/research/research-gate.js +82 -0
  255. package/dist/core/research/research-gate.js.map +1 -0
  256. package/dist/core/research/research-runner.d.ts +59 -0
  257. package/dist/core/research/research-runner.d.ts.map +1 -0
  258. package/dist/core/research/research-runner.js +155 -0
  259. package/dist/core/research/research-runner.js.map +1 -0
  260. package/dist/core/research/session-evidence-bundle.d.ts +11 -0
  261. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -0
  262. package/dist/core/research/session-evidence-bundle.js +55 -0
  263. package/dist/core/research/session-evidence-bundle.js.map +1 -0
  264. package/dist/core/resource-loader.d.ts.map +1 -1
  265. package/dist/core/resource-loader.js +4 -0
  266. package/dist/core/resource-loader.js.map +1 -1
  267. package/dist/core/settings-manager.d.ts +160 -4
  268. package/dist/core/settings-manager.d.ts.map +1 -1
  269. package/dist/core/settings-manager.js +304 -9
  270. package/dist/core/settings-manager.js.map +1 -1
  271. package/dist/core/skills.d.ts +4 -0
  272. package/dist/core/skills.d.ts.map +1 -1
  273. package/dist/core/skills.js +18 -6
  274. package/dist/core/skills.js.map +1 -1
  275. package/dist/core/slash-commands.d.ts.map +1 -1
  276. package/dist/core/slash-commands.js +10 -1
  277. package/dist/core/slash-commands.js.map +1 -1
  278. package/dist/core/toolkit/script-registry.d.ts +34 -0
  279. package/dist/core/toolkit/script-registry.d.ts.map +1 -0
  280. package/dist/core/toolkit/script-registry.js +71 -0
  281. package/dist/core/toolkit/script-registry.js.map +1 -0
  282. package/dist/core/toolkit/script-runner.d.ts +28 -0
  283. package/dist/core/toolkit/script-runner.d.ts.map +1 -0
  284. package/dist/core/toolkit/script-runner.js +48 -0
  285. package/dist/core/toolkit/script-runner.js.map +1 -0
  286. package/dist/core/tools/artifact-retrieve.d.ts +23 -0
  287. package/dist/core/tools/artifact-retrieve.d.ts.map +1 -0
  288. package/dist/core/tools/artifact-retrieve.js +110 -0
  289. package/dist/core/tools/artifact-retrieve.js.map +1 -0
  290. package/dist/core/tools/delegate.d.ts +32 -0
  291. package/dist/core/tools/delegate.d.ts.map +1 -0
  292. package/dist/core/tools/delegate.js +60 -0
  293. package/dist/core/tools/delegate.js.map +1 -0
  294. package/dist/core/tools/fff-search-backend.d.ts +103 -0
  295. package/dist/core/tools/fff-search-backend.d.ts.map +1 -0
  296. package/dist/core/tools/fff-search-backend.js +151 -0
  297. package/dist/core/tools/fff-search-backend.js.map +1 -0
  298. package/dist/core/tools/find.d.ts +21 -1
  299. package/dist/core/tools/find.d.ts.map +1 -1
  300. package/dist/core/tools/find.js +183 -10
  301. package/dist/core/tools/find.js.map +1 -1
  302. package/dist/core/tools/goal.d.ts +35 -0
  303. package/dist/core/tools/goal.d.ts.map +1 -0
  304. package/dist/core/tools/goal.js +122 -0
  305. package/dist/core/tools/goal.js.map +1 -0
  306. package/dist/core/tools/grep.d.ts +21 -1
  307. package/dist/core/tools/grep.d.ts.map +1 -1
  308. package/dist/core/tools/grep.js +272 -27
  309. package/dist/core/tools/grep.js.map +1 -1
  310. package/dist/core/tools/index.d.ts +4 -1
  311. package/dist/core/tools/index.d.ts.map +1 -1
  312. package/dist/core/tools/index.js +9 -0
  313. package/dist/core/tools/index.js.map +1 -1
  314. package/dist/core/tools/model-fitness.d.ts +30 -0
  315. package/dist/core/tools/model-fitness.d.ts.map +1 -0
  316. package/dist/core/tools/model-fitness.js +38 -0
  317. package/dist/core/tools/model-fitness.js.map +1 -0
  318. package/dist/core/tools/run-toolkit-script.d.ts +24 -0
  319. package/dist/core/tools/run-toolkit-script.d.ts.map +1 -0
  320. package/dist/core/tools/run-toolkit-script.js +103 -0
  321. package/dist/core/tools/run-toolkit-script.js.map +1 -0
  322. package/dist/core/tools/search-router.d.ts +75 -0
  323. package/dist/core/tools/search-router.d.ts.map +1 -0
  324. package/dist/core/tools/search-router.js +85 -0
  325. package/dist/core/tools/search-router.js.map +1 -0
  326. package/dist/modes/interactive/components/fitness-role-selector.d.ts +13 -0
  327. package/dist/modes/interactive/components/fitness-role-selector.d.ts.map +1 -0
  328. package/dist/modes/interactive/components/fitness-role-selector.js +65 -0
  329. package/dist/modes/interactive/components/fitness-role-selector.js.map +1 -0
  330. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  331. package/dist/modes/interactive/components/footer.js +18 -16
  332. package/dist/modes/interactive/components/footer.js.map +1 -1
  333. package/dist/modes/interactive/components/settings-selector.d.ts +16 -1
  334. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  335. package/dist/modes/interactive/components/settings-selector.js +555 -11
  336. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  337. package/dist/modes/interactive/interactive-mode.d.ts +9 -0
  338. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  339. package/dist/modes/interactive/interactive-mode.js +308 -39
  340. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  341. package/dist/utils/tools-manager.d.ts +2 -0
  342. package/dist/utils/tools-manager.d.ts.map +1 -1
  343. package/dist/utils/tools-manager.js +154 -2
  344. package/dist/utils/tools-manager.js.map +1 -1
  345. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  346. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  347. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  348. package/examples/extensions/sandbox/package-lock.json +2 -2
  349. package/examples/extensions/sandbox/package.json +1 -1
  350. package/examples/extensions/with-deps/package-lock.json +2 -2
  351. package/examples/extensions/with-deps/package.json +1 -1
  352. package/npm-shrinkwrap.json +368 -12
  353. package/package.json +5 -4
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Tool output digesting and packing (Phase 3): "measure -> digest/preview/artifact ->
3
+ * prompt item", per tool-output-artifacts.md's boundary rule. Large raw tool output is
4
+ * captured to an artifact BEFORE truncation, so the artifact holds the exact raw payload;
5
+ * the model only ever sees the bounded preview plus an artifact reference.
6
+ *
7
+ * This module is pure with respect to wiring: it takes an `ArtifactStore` by dependency
8
+ * injection and does not know about sessions, transcripts, or prompt construction. A tool
9
+ * (grep/find) that never passes an `ArtifactStore` gets byte-for-byte its prior behavior --
10
+ * packing is opt-in per call site, not a global switch.
11
+ */
12
+ import { truncateHead } from "../tools/truncate.js";
13
+ /** Footer notice text for a packed artifact, for callers to fold into their own notices. */
14
+ export function formatArtifactNotice(artifactId) {
15
+ return `Full output: artifact tool-output:${artifactId}`;
16
+ }
17
+ /**
18
+ * Measure `request.rawContent`; if it fits within the caps, return it unchanged (small
19
+ * output stays exactly as readable as before this module existed). If it's oversized and
20
+ * an `ArtifactStore` is provided, capture the exact raw payload as an artifact first, then
21
+ * return the same bounded preview `truncateHead` would have produced anyway.
22
+ *
23
+ * Fails closed: if the artifact write succeeds but registering `holderId` as a reference
24
+ * fails (`addReference` returns false), the artifact is not claimed in the result at all --
25
+ * the caller falls back to the bounded/truncated content exactly as if no store had been
26
+ * provided, since an unprotected artifact could be cleaned up at any time.
27
+ */
28
+ export function packToolOutput(request, artifactStore, holderId) {
29
+ const truncation = truncateHead(request.rawContent, request.truncation);
30
+ if (!truncation.truncated || !artifactStore) {
31
+ return { content: truncation.content, truncation, packed: false };
32
+ }
33
+ const { ref } = artifactStore.write({
34
+ kind: "tool_output",
35
+ content: request.rawContent,
36
+ toolName: request.toolName,
37
+ command: request.command,
38
+ path: request.path,
39
+ sessionEntryId: request.sessionEntryId,
40
+ createdAtTurn: request.createdAtTurn ?? 0,
41
+ reproducible: request.reproducible ?? true,
42
+ });
43
+ if (!artifactStore.addReference(ref.id, holderId)) {
44
+ return { content: truncation.content, truncation, packed: false };
45
+ }
46
+ return { content: truncation.content, truncation, artifactId: ref.id, packed: true };
47
+ }
48
+ export function createInMemoryBroadQueryTracker() {
49
+ const counts = new Map();
50
+ return {
51
+ recordBroadQuery(key) {
52
+ const next = (counts.get(key) ?? 0) + 1;
53
+ counts.set(key, next);
54
+ return next;
55
+ },
56
+ };
57
+ }
58
+ /** Normalize a search-tool call into a stable repetition key: same query, same broadness. */
59
+ export function normalizeBroadQueryKey(input) {
60
+ return [input.toolName, input.pattern ?? "", input.path ?? "", input.glob ?? ""].join("␟");
61
+ }
62
+ const REPEATED_BROAD_QUERY_THRESHOLD = 2;
63
+ /**
64
+ * When a broad-query condition (match/result limit hit, or byte truncation) repeats for
65
+ * the same normalized query, produce a compact "do not repeat" style note. This is only
66
+ * the Phase 3 signal; the durable invalidation ledger (supersession/expiry rules) is
67
+ * Phase 6 per implementation-phases.md.
68
+ */
69
+ export function broadQueryInvalidationNote(tracker, key, humanQueryDescription) {
70
+ if (!tracker)
71
+ return undefined;
72
+ const count = tracker.recordBroadQuery(key);
73
+ if (count < REPEATED_BROAD_QUERY_THRESHOLD)
74
+ return undefined;
75
+ return `Do not repeat: ${humanQueryDescription} has produced broad/truncated results ${count} times in this session. Narrow the path/glob/pattern.`;
76
+ }
77
+ //# sourceMappingURL=tool-output-packer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-output-packer.js","sourceRoot":"","sources":["../../../src/core/context/tool-output-packer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAiD,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAiCnG,4FAA4F;AAC5F,MAAM,UAAU,oBAAoB,CAAC,UAAkB,EAAU;IAChE,OAAO,qCAAqC,UAAU,EAAE,CAAC;AAAA,CACzD;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAC7B,OAA8B,EAC9B,aAAwC,EACxC,QAAgB,EACG;IACnB,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAExE,IAAI,CAAC,UAAU,CAAC,SAAS,IAAI,CAAC,aAAa,EAAE,CAAC;QAC7C,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACnE,CAAC;IAED,MAAM,EAAE,GAAG,EAAE,GAAG,aAAa,CAAC,KAAK,CAAC;QACnC,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,OAAO,CAAC,UAAU;QAC3B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,CAAC;QACzC,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,IAAI;KAC1C,CAAC,CAAC;IAEH,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC;QACnD,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACnE,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAAA,CACrF;AAOD,MAAM,UAAU,+BAA+B,GAAsB;IACpE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,OAAO;QACN,gBAAgB,CAAC,GAAW,EAAU;YACrC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACxC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACtB,OAAO,IAAI,CAAC;QAAA,CACZ;KACD,CAAC;AAAA,CACF;AAED,6FAA6F;AAC7F,MAAM,UAAU,sBAAsB,CAAC,KAKtC,EAAU;IACV,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAG,CAAC,CAAC;AAAA,CAC3F;AAED,MAAM,8BAA8B,GAAG,CAAC,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CACzC,OAAsC,EACtC,GAAW,EACX,qBAA6B,EACR;IACrB,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,KAAK,GAAG,8BAA8B;QAAE,OAAO,SAAS,CAAC;IAC7D,OAAO,kBAAkB,qBAAqB,yCAAyC,KAAK,uDAAuD,CAAC;AAAA,CACpJ","sourcesContent":["/**\n * Tool output digesting and packing (Phase 3): \"measure -> digest/preview/artifact ->\n * prompt item\", per tool-output-artifacts.md's boundary rule. Large raw tool output is\n * captured to an artifact BEFORE truncation, so the artifact holds the exact raw payload;\n * the model only ever sees the bounded preview plus an artifact reference.\n *\n * This module is pure with respect to wiring: it takes an `ArtifactStore` by dependency\n * injection and does not know about sessions, transcripts, or prompt construction. A tool\n * (grep/find) that never passes an `ArtifactStore` gets byte-for-byte its prior behavior --\n * packing is opt-in per call site, not a global switch.\n */\n\nimport { type TruncationOptions, type TruncationResult, truncateHead } from \"../tools/truncate.ts\";\nimport type { ArtifactStore } from \"./context-artifacts.ts\";\n\nexport interface PackToolOutputRequest {\n\ttoolName: string;\n\tcommand?: string;\n\tpath?: string;\n\trawContent: string;\n\tsessionEntryId?: string;\n\t/**\n\t * Turn number for artifact capture identity. Real session-turn wiring lands in a later\n\t * slice; callers that don't track turns yet may pass 0.\n\t */\n\tcreatedAtTurn?: number;\n\t/** Whether re-running the same tool call would reproduce this content. Default: true. */\n\treproducible?: boolean;\n\ttruncation?: TruncationOptions;\n}\n\nexport interface PackedToolOutput {\n\t/**\n\t * Bounded preview content -- exactly what `truncateHead` alone would have produced.\n\t * No footer/notice text is appended here; callers already have their own per-tool\n\t * footer conventions (grep's vs. find's bracket ordering differ) and own formatting\n\t * the artifact notice into their own notice list via `formatArtifactNotice`.\n\t */\n\tcontent: string;\n\ttruncation: TruncationResult;\n\t/** Present only if packing succeeded and the artifact is protected from cleanup. */\n\tartifactId?: string;\n\tpacked: boolean;\n}\n\n/** Footer notice text for a packed artifact, for callers to fold into their own notices. */\nexport function formatArtifactNotice(artifactId: string): string {\n\treturn `Full output: artifact tool-output:${artifactId}`;\n}\n\n/**\n * Measure `request.rawContent`; if it fits within the caps, return it unchanged (small\n * output stays exactly as readable as before this module existed). If it's oversized and\n * an `ArtifactStore` is provided, capture the exact raw payload as an artifact first, then\n * return the same bounded preview `truncateHead` would have produced anyway.\n *\n * Fails closed: if the artifact write succeeds but registering `holderId` as a reference\n * fails (`addReference` returns false), the artifact is not claimed in the result at all --\n * the caller falls back to the bounded/truncated content exactly as if no store had been\n * provided, since an unprotected artifact could be cleaned up at any time.\n */\nexport function packToolOutput(\n\trequest: PackToolOutputRequest,\n\tartifactStore: ArtifactStore | undefined,\n\tholderId: string,\n): PackedToolOutput {\n\tconst truncation = truncateHead(request.rawContent, request.truncation);\n\n\tif (!truncation.truncated || !artifactStore) {\n\t\treturn { content: truncation.content, truncation, packed: false };\n\t}\n\n\tconst { ref } = artifactStore.write({\n\t\tkind: \"tool_output\",\n\t\tcontent: request.rawContent,\n\t\ttoolName: request.toolName,\n\t\tcommand: request.command,\n\t\tpath: request.path,\n\t\tsessionEntryId: request.sessionEntryId,\n\t\tcreatedAtTurn: request.createdAtTurn ?? 0,\n\t\treproducible: request.reproducible ?? true,\n\t});\n\n\tif (!artifactStore.addReference(ref.id, holderId)) {\n\t\treturn { content: truncation.content, truncation, packed: false };\n\t}\n\n\treturn { content: truncation.content, truncation, artifactId: ref.id, packed: true };\n}\n\nexport interface BroadQueryTracker {\n\t/** Record one more broad occurrence of `key`; returns the cumulative count including this one. */\n\trecordBroadQuery(key: string): number;\n}\n\nexport function createInMemoryBroadQueryTracker(): BroadQueryTracker {\n\tconst counts = new Map<string, number>();\n\treturn {\n\t\trecordBroadQuery(key: string): number {\n\t\t\tconst next = (counts.get(key) ?? 0) + 1;\n\t\t\tcounts.set(key, next);\n\t\t\treturn next;\n\t\t},\n\t};\n}\n\n/** Normalize a search-tool call into a stable repetition key: same query, same broadness. */\nexport function normalizeBroadQueryKey(input: {\n\ttoolName: string;\n\tpattern?: string;\n\tpath?: string;\n\tglob?: string;\n}): string {\n\treturn [input.toolName, input.pattern ?? \"\", input.path ?? \"\", input.glob ?? \"\"].join(\"␟\");\n}\n\nconst REPEATED_BROAD_QUERY_THRESHOLD = 2;\n\n/**\n * When a broad-query condition (match/result limit hit, or byte truncation) repeats for\n * the same normalized query, produce a compact \"do not repeat\" style note. This is only\n * the Phase 3 signal; the durable invalidation ledger (supersession/expiry rules) is\n * Phase 6 per implementation-phases.md.\n */\nexport function broadQueryInvalidationNote(\n\ttracker: BroadQueryTracker | undefined,\n\tkey: string,\n\thumanQueryDescription: string,\n): string | undefined {\n\tif (!tracker) return undefined;\n\tconst count = tracker.recordBroadQuery(key);\n\tif (count < REPEATED_BROAD_QUERY_THRESHOLD) return undefined;\n\treturn `Do not repeat: ${humanQueryDescription} has produced broad/truncated results ${count} times in this session. Narrow the path/glob/pattern.`;\n}\n"]}
@@ -22,10 +22,20 @@ export interface ContextGcSettings {
22
22
  export interface NormalizedContextGcSettings extends Omit<Required<ContextGcSettings>, "semanticMemory"> {
23
23
  semanticMemory: Required<SemanticMemoryGcSettings>;
24
24
  }
25
+ /**
26
+ * Brain-curation hooks (both optional; absent hooks are byte-for-byte today's behavior).
27
+ * `resolveDigest` is a pure lookup keyed by the record's content hash; `onPacked` lets the
28
+ * caller enqueue digest work with the exact original text at the moment it is packed.
29
+ */
30
+ export interface ContextGcCurationHooks {
31
+ resolveDigest?: (digestKey: string) => string | undefined;
32
+ onPacked?: (record: ContextGcPackedRecord, originalText: string) => void;
33
+ }
25
34
  export interface ContextGcOptions extends NormalizedContextGcSettings {
26
35
  cwd: string;
27
36
  storageDir?: string;
28
37
  writePayloads?: boolean;
38
+ curation?: ContextGcCurationHooks;
29
39
  }
30
40
  export interface ContextGcPackedRecord {
31
41
  toolName: string;
@@ -39,6 +49,8 @@ export interface ContextGcPackedRecord {
39
49
  path?: string;
40
50
  command?: string;
41
51
  key?: string;
52
+ /** Brain-curator semantic digest of the packed content (model-generated; advisory only). */
53
+ digest?: string;
42
54
  }
43
55
  export interface ContextGcReport {
44
56
  enabled: boolean;
@@ -58,5 +70,6 @@ export declare function applyContextGc(messages: AgentMessage[], rawSettings: Co
58
70
  cwd?: string;
59
71
  storageDir?: string;
60
72
  writePayloads?: boolean;
73
+ curation?: ContextGcCurationHooks;
61
74
  }): ContextGcResult;
62
75
  //# sourceMappingURL=context-gc.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-gc.d.ts","sourceRoot":"","sources":["../../src/core/context-gc.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAK9D,MAAM,WAAW,wBAAwB;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oEAAoE;IACpE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,sFAAsF;IACtF,cAAc,CAAC,EAAE,wBAAwB,CAAC;CAC1C;AAED,MAAM,WAAW,2BAA4B,SAAQ,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,gBAAgB,CAAC;IACvG,cAAc,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,gBAAiB,SAAQ,2BAA2B;IACpE,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,iBAAiB,GAAG,mBAAmB,GAAG,uBAAuB,CAAC;IAC1E,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,qBAAqB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,MAAM,EAAE,eAAe,CAAC;CACxB;AAuBD,eAAO,MAAM,2BAA2B,EAAE,2BA4BzC,CAAC;AA6CF,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,2BAA2B,CAE9F;AAkND,wBAAgB,cAAc,CAC7B,QAAQ,EAAE,YAAY,EAAE,EACxB,WAAW,EAAE,iBAAiB,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7F,eAAe,CA6GjB","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, resolve } from \"node:path\";\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { ToolResultMessage } from \"@caupulican/pi-ai\";\nimport { normalizePath } from \"../utils/paths.ts\";\nimport { estimateTokens } from \"./compaction/compaction.ts\";\n\nexport interface SemanticMemoryGcSettings {\n\tenabled?: boolean;\n\t/** Number of newest Automata/Mind injected pages to preserve verbatim. */\n\tpreserveRecentPages?: number;\n\t/** Minimum provider-visible text chars before a stale semantic memory page is packed. */\n\tminChars?: number;\n\t/** Markers that identify deterministic Automata/Mind context pages. */\n\tmarkers?: string[];\n}\n\nexport interface ContextGcSettings {\n\tenabled?: boolean;\n\t/** Number of most recent AgentMessage rows to preserve verbatim. */\n\tpreserveRecentMessages?: number;\n\t/** Minimum provider-visible text chars before a stale tool result is packed. */\n\tminToolResultChars?: number;\n\t/** Tool names eligible for stale result packing. */\n\ttools?: string[];\n\t/** Provider-context control for deterministic Automata/Mind semantic memory pages. */\n\tsemanticMemory?: SemanticMemoryGcSettings;\n}\n\nexport interface NormalizedContextGcSettings extends Omit<Required<ContextGcSettings>, \"semanticMemory\"> {\n\tsemanticMemory: Required<SemanticMemoryGcSettings>;\n}\n\nexport interface ContextGcOptions extends NormalizedContextGcSettings {\n\tcwd: string;\n\tstorageDir?: string;\n\twritePayloads?: boolean;\n}\n\nexport interface ContextGcPackedRecord {\n\ttoolName: string;\n\ttoolCallId: string;\n\tmessageIndex: number;\n\treason: \"superseded-read\" | \"stale-tool-result\" | \"stale-semantic-memory\";\n\toriginalChars: number;\n\toriginalTokens: number;\n\tpackedTokens: number;\n\tstoragePath?: string;\n\tpath?: string;\n\tcommand?: string;\n\tkey?: string;\n}\n\nexport interface ContextGcReport {\n\tenabled: boolean;\n\tpackedCount: number;\n\toriginalTokens: number;\n\tpackedTokens: number;\n\tsavedTokens: number;\n\trecords: ContextGcPackedRecord[];\n}\n\nexport interface ContextGcResult {\n\tmessages: AgentMessage[];\n\treport: ContextGcReport;\n}\n\nconst DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS: Required<SemanticMemoryGcSettings> = {\n\tenabled: true,\n\tpreserveRecentPages: 1,\n\tminChars: 900,\n\tmarkers: [\n\t\t// Generic memory-subsystem recall page marker (brand-free). Provider-specific markers are\n\t\t// merged in dynamically at runtime via MemoryManager.getContextMarkers().\n\t\t\"<memory_context\",\n\t\t// Pre-existing provider-specific markers (to be generalized to provider-declared markers).\n\t\t\"<automata_context\",\n\t\t\"<automata_response\",\n\t\t\"<automata_query\",\n\t\t\"<automata_fetch\",\n\t\t\"<memory_lifecycle_audit\",\n\t\t\"<memory_lifecycle_purge\",\n\t\t\"<automata_doctor\",\n\t\t\"<automata_optimizer\",\n\t\t\"<automata_mesh\",\n\t],\n};\n\nexport const DEFAULT_CONTEXT_GC_SETTINGS: NormalizedContextGcSettings = {\n\tenabled: true,\n\tpreserveRecentMessages: 8,\n\tminToolResultChars: 1200,\n\ttools: [\n\t\t\"read\",\n\t\t\"bash\",\n\t\t\"rg\",\n\t\t\"grep\",\n\t\t\"find\",\n\t\t\"ls\",\n\t\t\"skill_open\",\n\t\t\"automata_graph_status\",\n\t\t\"automata_graph_search\",\n\t\t\"automata_graph_query\",\n\t\t\"automata_graph_neighbors\",\n\t\t\"automata_graph_path\",\n\t\t\"automata_graph_pointer_pack\",\n\t\t\"learning_query_memory\",\n\t\t\"subagent\",\n\t\t\"task_steps\",\n\t\t\"task_background\",\n\t\t\"task_goal\",\n\t\t\"run_ledger\",\n\t\t\"context_headroom_retrieve\",\n\t\t\"headroom_retrieve\",\n\t],\n\tsemanticMemory: DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS,\n};\n\ntype ToolCallMeta = {\n\tid: string;\n\tname: string;\n\targs: Record<string, unknown>;\n\tmessageIndex: number;\n};\n\nfunction cap(text: string, limit = 220): string {\n\tconst compact = text.replace(/\\s+/g, \" \").trim();\n\treturn compact.length > limit ? `${compact.slice(0, Math.max(0, limit - 1))}…` : compact;\n}\n\nfunction normalizeSemanticMemoryGcSettings(settings?: SemanticMemoryGcSettings): Required<SemanticMemoryGcSettings> {\n\treturn {\n\t\tenabled: settings?.enabled ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.enabled,\n\t\tpreserveRecentPages: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.preserveRecentPages ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.preserveRecentPages),\n\t\t),\n\t\tminChars: Math.max(0, Math.floor(settings?.minChars ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.minChars)),\n\t\tmarkers:\n\t\t\tsettings?.markers && settings.markers.length > 0\n\t\t\t\t? settings.markers\n\t\t\t\t: DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.markers,\n\t};\n}\n\nfunction normalizeContextGcSettings(settings?: ContextGcSettings): NormalizedContextGcSettings {\n\treturn {\n\t\tenabled: settings?.enabled ?? DEFAULT_CONTEXT_GC_SETTINGS.enabled,\n\t\tpreserveRecentMessages: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.preserveRecentMessages ?? DEFAULT_CONTEXT_GC_SETTINGS.preserveRecentMessages),\n\t\t),\n\t\tminToolResultChars: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.minToolResultChars ?? DEFAULT_CONTEXT_GC_SETTINGS.minToolResultChars),\n\t\t),\n\t\ttools: settings?.tools && settings.tools.length > 0 ? settings.tools : DEFAULT_CONTEXT_GC_SETTINGS.tools,\n\t\tsemanticMemory: normalizeSemanticMemoryGcSettings(settings?.semanticMemory),\n\t};\n}\n\nexport function getContextGcSettings(settings?: ContextGcSettings): NormalizedContextGcSettings {\n\treturn normalizeContextGcSettings(settings);\n}\n\nfunction textContentParts(content: unknown): string[] | undefined {\n\tif (typeof content === \"string\") return [content];\n\tif (!Array.isArray(content)) return undefined;\n\tconst parts: string[] = [];\n\tfor (const part of content) {\n\t\tif (typeof part !== \"object\" || part === null) return undefined;\n\t\tconst typed = part as { type?: string; text?: string; mimeType?: string };\n\t\tif (typed.type === \"text\" && typeof typed.text === \"string\") parts.push(typed.text);\n\t\telse if (typed.type === \"image\") return undefined;\n\t\telse return undefined;\n\t}\n\treturn parts;\n}\n\nfunction contentText(content: unknown): string | undefined {\n\tif (typeof content === \"string\") return content;\n\treturn textContentParts(content)?.join(\"\\n\");\n}\n\nfunction toolResultParts(message: ToolResultMessage): string[] {\n\tconst parts: string[] = [];\n\tfor (const part of message.content) {\n\t\tif (part.type === \"text\" && part.text) parts.push(part.text);\n\t\telse if (part.type === \"image\") parts.push(`[image ${part.mimeType}]`);\n\t}\n\treturn parts;\n}\n\nfunction toolResultText(message: ToolResultMessage): string {\n\treturn toolResultParts(message).join(\"\\n\");\n}\n\nfunction smallStringSlice(value: string, start?: number, end?: number): string {\n\tconst sliced = value.slice(start, end);\n\treturn sliced ? ` ${sliced}`.slice(1) : \"\";\n}\n\nfunction joinedPartsContainMarker(parts: string[], marker: string): boolean {\n\tif (marker.length === 0) return true;\n\tconst tailLength = marker.length - 1;\n\tlet tail = \"\";\n\tlet first = true;\n\tfor (const part of parts) {\n\t\tif (part.includes(marker)) return true;\n\t\tif (!first && `${tail}\\n${smallStringSlice(part, 0, tailLength)}`.includes(marker)) return true;\n\t\tif (tailLength === 0) tail = \"\";\n\t\telse if (part.length >= tailLength) tail = smallStringSlice(part, -tailLength);\n\t\telse tail = `${tail}${first ? \"\" : \"\\n\"}${part}`.slice(-tailLength);\n\t\tfirst = false;\n\t}\n\treturn false;\n}\n\nfunction joinedPartsContainAnyMarker(parts: string[], markers: readonly string[]): boolean {\n\treturn markers.some((marker) => joinedPartsContainMarker(parts, marker));\n}\n\nfunction isSemanticMemoryCustomMessage(message: AgentMessage): boolean {\n\tif (message.role !== \"custom\") return false;\n\tconst customType = String((message as { customType?: unknown }).customType ?? \"\").toLowerCase();\n\treturn customType.includes(\"automata\") || customType.includes(\"memory\") || customType.includes(\"mind\");\n}\n\nfunction agentMessageText(message: AgentMessage): string | undefined {\n\tif (message.role === \"toolResult\") return toolResultText(message);\n\tif (isSemanticMemoryCustomMessage(message)) return contentText((message as { content?: unknown }).content);\n\treturn undefined;\n}\n\nfunction semanticMessageHasMarker(message: AgentMessage, settings: Required<SemanticMemoryGcSettings>): boolean {\n\tif (message.role === \"toolResult\") return joinedPartsContainAnyMarker(toolResultParts(message), settings.markers);\n\tif (isSemanticMemoryCustomMessage(message)) {\n\t\tconst parts = textContentParts((message as { content?: unknown }).content);\n\t\treturn parts ? joinedPartsContainAnyMarker(parts, settings.markers) : false;\n\t}\n\treturn false;\n}\n\ninterface ContextGcPlan {\n\tcalls: Map<string, ToolCallMeta>;\n\tlatestReadByPath: Map<string, string>;\n\tsemanticIndexes: number[];\n}\n\nfunction normalizeToolPath(cwd: string, value: unknown): string | undefined {\n\tif (typeof value !== \"string\" || value.trim() === \"\") return undefined;\n\tconst path = value.trim();\n\treturn normalizePath(isAbsolute(path) ? path : resolve(cwd, path));\n}\n\nfunction collectContextGcPlan(\n\tmessages: AgentMessage[],\n\tcwd: string,\n\tsemanticSettings: Required<SemanticMemoryGcSettings>,\n): ContextGcPlan {\n\tconst calls = new Map<string, ToolCallMeta>();\n\tconst readResultCallIds: string[] = [];\n\tconst semanticIndexes: number[] = [];\n\n\tfor (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {\n\t\tconst message = messages[messageIndex];\n\t\tif (message.role === \"assistant\") {\n\t\t\tfor (const part of message.content) {\n\t\t\t\tif (part.type !== \"toolCall\") continue;\n\t\t\t\tcalls.set(part.id, {\n\t\t\t\t\tid: part.id,\n\t\t\t\t\tname: part.name,\n\t\t\t\t\targs: part.arguments ?? {},\n\t\t\t\t\tmessageIndex,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (message.role === \"toolResult\" && message.toolName === \"read\") {\n\t\t\treadResultCallIds.push(message.toolCallId);\n\t\t}\n\n\t\tif (semanticSettings.enabled && semanticMessageHasMarker(message, semanticSettings)) {\n\t\t\tsemanticIndexes.push(messageIndex);\n\t\t}\n\t}\n\n\tconst latestReadByPath = new Map<string, string>();\n\tfor (const toolCallId of readResultCallIds) {\n\t\tconst call = calls.get(toolCallId);\n\t\tconst path = normalizeToolPath(cwd, call?.args.path);\n\t\tif (path) latestReadByPath.set(path, toolCallId);\n\t}\n\n\treturn { calls, latestReadByPath, semanticIndexes };\n}\n\nfunction storagePathFor(storageDir: string | undefined, key: string): string | undefined {\n\tif (!storageDir || !isAbsolute(storageDir)) return undefined;\n\treturn resolve(storageDir, `${key}.txt`);\n}\n\nfunction maybeStoreOriginal(options: ContextGcOptions, key: string, original: string): string | undefined {\n\tconst path = storagePathFor(options.storageDir, key);\n\tif (!path || !options.writePayloads) return path;\n\ttry {\n\t\tmkdirSync(options.storageDir!, { recursive: true });\n\t\tif (!existsSync(path)) writeFileSync(path, original, \"utf8\");\n\t} catch {\n\t\treturn undefined;\n\t}\n\treturn path;\n}\n\nfunction reasonText(record: ContextGcPackedRecord): string {\n\tif (record.reason === \"superseded-read\") return \"older read snapshot superseded by a later read of the same file\";\n\tif (record.reason === \"stale-semantic-memory\") {\n\t\treturn \"older Automata/Mind semantic context page outside the semantic-memory freshness window\";\n\t}\n\treturn \"stale bulky tool output outside the recent context window\";\n}\n\nfunction buildSummary(record: ContextGcPackedRecord): string {\n\tconst semantic = record.reason === \"stale-semantic-memory\";\n\tconst lines = [\n\t\tsemantic ? \"[Semantic GC packed stale Automata/Mind context page]\" : \"[Context GC packed stale tool result]\",\n\t\tsemantic ? undefined : `tool: ${record.toolName}`,\n\t\trecord.path ? `path: ${record.path}` : undefined,\n\t\trecord.command ? `command: ${cap(record.command)}` : undefined,\n\t\t`reason: ${reasonText(record)}`,\n\t\t`original: ${record.originalChars} chars (~${record.originalTokens} tokens)`,\n\t\trecord.storagePath\n\t\t\t? `exact old provider-visible text stored at: ${record.storagePath}`\n\t\t\t: \"exact old provider-visible text retained in the session log, not inline in provider context\",\n\t\tsemantic\n\t\t\t? \"If this memory context matters, query Automata/Mind again with the same topic/filter or fetch the drawer pointers from the stored page.\"\n\t\t\t: record.path\n\t\t\t\t? \"For current file contents, use the read tool on the path above. For the exact old output, read the stored payload path if present.\"\n\t\t\t\t: \"If this exact old output matters, retrieve/read the stored payload path if present or rerun the tool command.\",\n\t\t\"Do not rely on this summary as the original content.\",\n\t].filter((line): line is string => line !== undefined);\n\treturn lines.join(\"\\n\");\n}\n\nfunction gcDetails(message: { details?: unknown }, record: ContextGcPackedRecord): Record<string, unknown> {\n\treturn {\n\t\t...(typeof message.details === \"object\" && message.details !== null ? message.details : {}),\n\t\tcontextGc: {\n\t\t\tpacked: true,\n\t\t\toriginalChars: record.originalChars,\n\t\t\toriginalTokens: record.originalTokens,\n\t\t\tstoragePath: record.storagePath,\n\t\t\treason: record.reason,\n\t\t},\n\t};\n}\n\nfunction makePackedToolResult(message: ToolResultMessage, record: ContextGcPackedRecord): ToolResultMessage {\n\tconst summary = buildSummary(record);\n\treturn {\n\t\t...message,\n\t\tcontent: [{ type: \"text\", text: summary }],\n\t\tdetails: gcDetails(message, record),\n\t};\n}\n\nfunction makePackedSemanticMemoryMessage(message: AgentMessage, record: ContextGcPackedRecord): AgentMessage {\n\tconst summary = buildSummary(record);\n\treturn {\n\t\t...(message as unknown as Record<string, unknown>),\n\t\tcontent: [{ type: \"text\", text: summary }],\n\t\tdetails: gcDetails(message as { details?: unknown }, record),\n\t} as AgentMessage;\n}\n\nexport function applyContextGc(\n\tmessages: AgentMessage[],\n\trawSettings: ContextGcSettings & { cwd?: string; storageDir?: string; writePayloads?: boolean },\n): ContextGcResult {\n\tconst settings = normalizeContextGcSettings(rawSettings);\n\tconst baseReport: ContextGcReport = {\n\t\tenabled: settings.enabled,\n\t\tpackedCount: 0,\n\t\toriginalTokens: 0,\n\t\tpackedTokens: 0,\n\t\tsavedTokens: 0,\n\t\trecords: [],\n\t};\n\tif (!settings.enabled) return { messages, report: baseReport };\n\n\tconst options: ContextGcOptions = {\n\t\t...settings,\n\t\tcwd: rawSettings.cwd ?? process.cwd(),\n\t\tstorageDir: rawSettings.storageDir,\n\t\twritePayloads: rawSettings.writePayloads ?? true,\n\t};\n\tconst eligibleTools = new Set(options.tools);\n\tconst plan = collectContextGcPlan(messages, options.cwd, options.semanticMemory);\n\tconst recentStart = Math.max(0, messages.length - options.preserveRecentMessages);\n\tconst semanticIndexSet = new Set(plan.semanticIndexes);\n\tconst preservedSemanticIndexes = new Set(\n\t\toptions.semanticMemory.preserveRecentPages > 0\n\t\t\t? plan.semanticIndexes.slice(-options.semanticMemory.preserveRecentPages)\n\t\t\t: [],\n\t);\n\tconst nextMessages = messages.slice();\n\tlet changed = false;\n\n\tfor (let index = 0; index < messages.length; index++) {\n\t\tconst message = messages[index];\n\t\tif (semanticIndexSet.has(index) && !preservedSemanticIndexes.has(index) && index < recentStart) {\n\t\t\tconst originalText = agentMessageText(message);\n\t\t\tif (originalText && originalText.length >= options.semanticMemory.minChars) {\n\t\t\t\tconst originalTokens = estimateTokens(message);\n\t\t\t\tconst key = createHash(\"sha256\")\n\t\t\t\t\t.update(`semantic-memory\\0${index}\\0${originalText}`)\n\t\t\t\t\t.digest(\"hex\")\n\t\t\t\t\t.slice(0, 24);\n\t\t\t\tconst storagePath = maybeStoreOriginal(options, key, originalText);\n\t\t\t\tconst record: ContextGcPackedRecord = {\n\t\t\t\t\ttoolName: \"automata-mind\",\n\t\t\t\t\ttoolCallId: `semantic-${index}`,\n\t\t\t\t\tmessageIndex: index,\n\t\t\t\t\treason: \"stale-semantic-memory\",\n\t\t\t\t\toriginalChars: originalText.length,\n\t\t\t\t\toriginalTokens,\n\t\t\t\t\tpackedTokens: 0,\n\t\t\t\t\tstoragePath,\n\t\t\t\t\tkey,\n\t\t\t\t};\n\t\t\t\tconst packed = makePackedSemanticMemoryMessage(message, record);\n\t\t\t\trecord.packedTokens = estimateTokens(packed);\n\t\t\t\tnextMessages[index] = packed;\n\t\t\t\tbaseReport.records.push(record);\n\t\t\t\tbaseReport.originalTokens += record.originalTokens;\n\t\t\t\tbaseReport.packedTokens += record.packedTokens;\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (message.role !== \"toolResult\") continue;\n\t\tif (!eligibleTools.has(message.toolName)) continue;\n\t\tif (index >= recentStart) continue;\n\n\t\tconst originalText = toolResultText(message);\n\t\tif (originalText.length < options.minToolResultChars) continue;\n\n\t\tconst call = plan.calls.get(message.toolCallId);\n\t\tconst path = normalizeToolPath(options.cwd, call?.args.path);\n\t\tlet reason: ContextGcPackedRecord[\"reason\"] = \"stale-tool-result\";\n\t\tif (message.toolName === \"read\" && path) {\n\t\t\tif (plan.latestReadByPath.get(path) === message.toolCallId) continue;\n\t\t\treason = \"superseded-read\";\n\t\t}\n\n\t\tconst originalTokens = estimateTokens(message);\n\t\tconst key = createHash(\"sha256\")\n\t\t\t.update(`${message.toolName}\\0${message.toolCallId}\\0${originalText}`)\n\t\t\t.digest(\"hex\")\n\t\t\t.slice(0, 24);\n\t\tconst storagePath = maybeStoreOriginal(options, key, originalText);\n\t\tconst record: ContextGcPackedRecord = {\n\t\t\ttoolName: message.toolName,\n\t\t\ttoolCallId: message.toolCallId,\n\t\t\tmessageIndex: index,\n\t\t\treason,\n\t\t\toriginalChars: originalText.length,\n\t\t\toriginalTokens,\n\t\t\tpackedTokens: 0,\n\t\t\tstoragePath,\n\t\t\tpath,\n\t\t\tcommand: typeof call?.args.command === \"string\" ? call.args.command : undefined,\n\t\t\tkey,\n\t\t};\n\t\tconst packed = makePackedToolResult(message, record);\n\t\trecord.packedTokens = estimateTokens(packed);\n\t\tnextMessages[index] = packed as AgentMessage;\n\t\tbaseReport.records.push(record);\n\t\tbaseReport.originalTokens += record.originalTokens;\n\t\tbaseReport.packedTokens += record.packedTokens;\n\t\tchanged = true;\n\t}\n\n\tbaseReport.packedCount = baseReport.records.length;\n\tbaseReport.savedTokens = Math.max(0, baseReport.originalTokens - baseReport.packedTokens);\n\treturn { messages: changed ? nextMessages : messages, report: baseReport };\n}\n"]}
1
+ {"version":3,"file":"context-gc.d.ts","sourceRoot":"","sources":["../../src/core/context-gc.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAK9D,MAAM,WAAW,wBAAwB;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oEAAoE;IACpE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,sFAAsF;IACtF,cAAc,CAAC,EAAE,wBAAwB,CAAC;CAC1C;AAED,MAAM,WAAW,2BAA4B,SAAQ,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,gBAAgB,CAAC;IACvG,cAAc,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC;CACnD;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC1D,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;CACzE;AAED,MAAM,WAAW,gBAAiB,SAAQ,2BAA2B;IACpE,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,sBAAsB,CAAC;CAClC;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,iBAAiB,GAAG,mBAAmB,GAAG,uBAAuB,CAAC;IAC1E,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,qBAAqB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,MAAM,EAAE,eAAe,CAAC;CACxB;AAuBD,eAAO,MAAM,2BAA2B,EAAE,2BA4BzC,CAAC;AA6CF,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,2BAA2B,CAE9F;AAmND,wBAAgB,cAAc,CAC7B,QAAQ,EAAE,YAAY,EAAE,EACxB,WAAW,EAAE,iBAAiB,GAAG;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,sBAAsB,CAAC;CAClC,GACC,eAAe,CAkHjB","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, resolve } from \"node:path\";\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { ToolResultMessage } from \"@caupulican/pi-ai\";\nimport { normalizePath } from \"../utils/paths.ts\";\nimport { estimateTokens } from \"./compaction/compaction.ts\";\n\nexport interface SemanticMemoryGcSettings {\n\tenabled?: boolean;\n\t/** Number of newest Automata/Mind injected pages to preserve verbatim. */\n\tpreserveRecentPages?: number;\n\t/** Minimum provider-visible text chars before a stale semantic memory page is packed. */\n\tminChars?: number;\n\t/** Markers that identify deterministic Automata/Mind context pages. */\n\tmarkers?: string[];\n}\n\nexport interface ContextGcSettings {\n\tenabled?: boolean;\n\t/** Number of most recent AgentMessage rows to preserve verbatim. */\n\tpreserveRecentMessages?: number;\n\t/** Minimum provider-visible text chars before a stale tool result is packed. */\n\tminToolResultChars?: number;\n\t/** Tool names eligible for stale result packing. */\n\ttools?: string[];\n\t/** Provider-context control for deterministic Automata/Mind semantic memory pages. */\n\tsemanticMemory?: SemanticMemoryGcSettings;\n}\n\nexport interface NormalizedContextGcSettings extends Omit<Required<ContextGcSettings>, \"semanticMemory\"> {\n\tsemanticMemory: Required<SemanticMemoryGcSettings>;\n}\n\n/**\n * Brain-curation hooks (both optional; absent hooks are byte-for-byte today's behavior).\n * `resolveDigest` is a pure lookup keyed by the record's content hash; `onPacked` lets the\n * caller enqueue digest work with the exact original text at the moment it is packed.\n */\nexport interface ContextGcCurationHooks {\n\tresolveDigest?: (digestKey: string) => string | undefined;\n\tonPacked?: (record: ContextGcPackedRecord, originalText: string) => void;\n}\n\nexport interface ContextGcOptions extends NormalizedContextGcSettings {\n\tcwd: string;\n\tstorageDir?: string;\n\twritePayloads?: boolean;\n\tcuration?: ContextGcCurationHooks;\n}\n\nexport interface ContextGcPackedRecord {\n\ttoolName: string;\n\ttoolCallId: string;\n\tmessageIndex: number;\n\treason: \"superseded-read\" | \"stale-tool-result\" | \"stale-semantic-memory\";\n\toriginalChars: number;\n\toriginalTokens: number;\n\tpackedTokens: number;\n\tstoragePath?: string;\n\tpath?: string;\n\tcommand?: string;\n\tkey?: string;\n\t/** Brain-curator semantic digest of the packed content (model-generated; advisory only). */\n\tdigest?: string;\n}\n\nexport interface ContextGcReport {\n\tenabled: boolean;\n\tpackedCount: number;\n\toriginalTokens: number;\n\tpackedTokens: number;\n\tsavedTokens: number;\n\trecords: ContextGcPackedRecord[];\n}\n\nexport interface ContextGcResult {\n\tmessages: AgentMessage[];\n\treport: ContextGcReport;\n}\n\nconst DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS: Required<SemanticMemoryGcSettings> = {\n\tenabled: true,\n\tpreserveRecentPages: 1,\n\tminChars: 900,\n\tmarkers: [\n\t\t// Generic memory-subsystem recall page marker (brand-free). Provider-specific markers are\n\t\t// merged in dynamically at runtime via MemoryManager.getContextMarkers().\n\t\t\"<memory_context\",\n\t\t// Pre-existing provider-specific markers (to be generalized to provider-declared markers).\n\t\t\"<automata_context\",\n\t\t\"<automata_response\",\n\t\t\"<automata_query\",\n\t\t\"<automata_fetch\",\n\t\t\"<memory_lifecycle_audit\",\n\t\t\"<memory_lifecycle_purge\",\n\t\t\"<automata_doctor\",\n\t\t\"<automata_optimizer\",\n\t\t\"<automata_mesh\",\n\t],\n};\n\nexport const DEFAULT_CONTEXT_GC_SETTINGS: NormalizedContextGcSettings = {\n\tenabled: true,\n\tpreserveRecentMessages: 8,\n\tminToolResultChars: 1200,\n\ttools: [\n\t\t\"read\",\n\t\t\"bash\",\n\t\t\"rg\",\n\t\t\"grep\",\n\t\t\"find\",\n\t\t\"ls\",\n\t\t\"skill_open\",\n\t\t\"automata_graph_status\",\n\t\t\"automata_graph_search\",\n\t\t\"automata_graph_query\",\n\t\t\"automata_graph_neighbors\",\n\t\t\"automata_graph_path\",\n\t\t\"automata_graph_pointer_pack\",\n\t\t\"learning_query_memory\",\n\t\t\"subagent\",\n\t\t\"task_steps\",\n\t\t\"task_background\",\n\t\t\"task_goal\",\n\t\t\"run_ledger\",\n\t\t\"context_headroom_retrieve\",\n\t\t\"headroom_retrieve\",\n\t],\n\tsemanticMemory: DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS,\n};\n\ntype ToolCallMeta = {\n\tid: string;\n\tname: string;\n\targs: Record<string, unknown>;\n\tmessageIndex: number;\n};\n\nfunction cap(text: string, limit = 220): string {\n\tconst compact = text.replace(/\\s+/g, \" \").trim();\n\treturn compact.length > limit ? `${compact.slice(0, Math.max(0, limit - 1))}…` : compact;\n}\n\nfunction normalizeSemanticMemoryGcSettings(settings?: SemanticMemoryGcSettings): Required<SemanticMemoryGcSettings> {\n\treturn {\n\t\tenabled: settings?.enabled ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.enabled,\n\t\tpreserveRecentPages: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.preserveRecentPages ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.preserveRecentPages),\n\t\t),\n\t\tminChars: Math.max(0, Math.floor(settings?.minChars ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.minChars)),\n\t\tmarkers:\n\t\t\tsettings?.markers && settings.markers.length > 0\n\t\t\t\t? settings.markers\n\t\t\t\t: DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.markers,\n\t};\n}\n\nfunction normalizeContextGcSettings(settings?: ContextGcSettings): NormalizedContextGcSettings {\n\treturn {\n\t\tenabled: settings?.enabled ?? DEFAULT_CONTEXT_GC_SETTINGS.enabled,\n\t\tpreserveRecentMessages: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.preserveRecentMessages ?? DEFAULT_CONTEXT_GC_SETTINGS.preserveRecentMessages),\n\t\t),\n\t\tminToolResultChars: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.minToolResultChars ?? DEFAULT_CONTEXT_GC_SETTINGS.minToolResultChars),\n\t\t),\n\t\ttools: settings?.tools && settings.tools.length > 0 ? settings.tools : DEFAULT_CONTEXT_GC_SETTINGS.tools,\n\t\tsemanticMemory: normalizeSemanticMemoryGcSettings(settings?.semanticMemory),\n\t};\n}\n\nexport function getContextGcSettings(settings?: ContextGcSettings): NormalizedContextGcSettings {\n\treturn normalizeContextGcSettings(settings);\n}\n\nfunction textContentParts(content: unknown): string[] | undefined {\n\tif (typeof content === \"string\") return [content];\n\tif (!Array.isArray(content)) return undefined;\n\tconst parts: string[] = [];\n\tfor (const part of content) {\n\t\tif (typeof part !== \"object\" || part === null) return undefined;\n\t\tconst typed = part as { type?: string; text?: string; mimeType?: string };\n\t\tif (typed.type === \"text\" && typeof typed.text === \"string\") parts.push(typed.text);\n\t\telse if (typed.type === \"image\") return undefined;\n\t\telse return undefined;\n\t}\n\treturn parts;\n}\n\nfunction contentText(content: unknown): string | undefined {\n\tif (typeof content === \"string\") return content;\n\treturn textContentParts(content)?.join(\"\\n\");\n}\n\nfunction toolResultParts(message: ToolResultMessage): string[] {\n\tconst parts: string[] = [];\n\tfor (const part of message.content) {\n\t\tif (part.type === \"text\" && part.text) parts.push(part.text);\n\t\telse if (part.type === \"image\") parts.push(`[image ${part.mimeType}]`);\n\t}\n\treturn parts;\n}\n\nfunction toolResultText(message: ToolResultMessage): string {\n\treturn toolResultParts(message).join(\"\\n\");\n}\n\nfunction smallStringSlice(value: string, start?: number, end?: number): string {\n\tconst sliced = value.slice(start, end);\n\treturn sliced ? ` ${sliced}`.slice(1) : \"\";\n}\n\nfunction joinedPartsContainMarker(parts: string[], marker: string): boolean {\n\tif (marker.length === 0) return true;\n\tconst tailLength = marker.length - 1;\n\tlet tail = \"\";\n\tlet first = true;\n\tfor (const part of parts) {\n\t\tif (part.includes(marker)) return true;\n\t\tif (!first && `${tail}\\n${smallStringSlice(part, 0, tailLength)}`.includes(marker)) return true;\n\t\tif (tailLength === 0) tail = \"\";\n\t\telse if (part.length >= tailLength) tail = smallStringSlice(part, -tailLength);\n\t\telse tail = `${tail}${first ? \"\" : \"\\n\"}${part}`.slice(-tailLength);\n\t\tfirst = false;\n\t}\n\treturn false;\n}\n\nfunction joinedPartsContainAnyMarker(parts: string[], markers: readonly string[]): boolean {\n\treturn markers.some((marker) => joinedPartsContainMarker(parts, marker));\n}\n\nfunction isSemanticMemoryCustomMessage(message: AgentMessage): boolean {\n\tif (message.role !== \"custom\") return false;\n\tconst customType = String((message as { customType?: unknown }).customType ?? \"\").toLowerCase();\n\treturn customType.includes(\"automata\") || customType.includes(\"memory\") || customType.includes(\"mind\");\n}\n\nfunction agentMessageText(message: AgentMessage): string | undefined {\n\tif (message.role === \"toolResult\") return toolResultText(message);\n\tif (isSemanticMemoryCustomMessage(message)) return contentText((message as { content?: unknown }).content);\n\treturn undefined;\n}\n\nfunction semanticMessageHasMarker(message: AgentMessage, settings: Required<SemanticMemoryGcSettings>): boolean {\n\tif (message.role === \"toolResult\") return joinedPartsContainAnyMarker(toolResultParts(message), settings.markers);\n\tif (isSemanticMemoryCustomMessage(message)) {\n\t\tconst parts = textContentParts((message as { content?: unknown }).content);\n\t\treturn parts ? joinedPartsContainAnyMarker(parts, settings.markers) : false;\n\t}\n\treturn false;\n}\n\ninterface ContextGcPlan {\n\tcalls: Map<string, ToolCallMeta>;\n\tlatestReadByPath: Map<string, string>;\n\tsemanticIndexes: number[];\n}\n\nfunction normalizeToolPath(cwd: string, value: unknown): string | undefined {\n\tif (typeof value !== \"string\" || value.trim() === \"\") return undefined;\n\tconst path = value.trim();\n\treturn normalizePath(isAbsolute(path) ? path : resolve(cwd, path));\n}\n\nfunction collectContextGcPlan(\n\tmessages: AgentMessage[],\n\tcwd: string,\n\tsemanticSettings: Required<SemanticMemoryGcSettings>,\n): ContextGcPlan {\n\tconst calls = new Map<string, ToolCallMeta>();\n\tconst readResultCallIds: string[] = [];\n\tconst semanticIndexes: number[] = [];\n\n\tfor (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {\n\t\tconst message = messages[messageIndex];\n\t\tif (message.role === \"assistant\") {\n\t\t\tfor (const part of message.content) {\n\t\t\t\tif (part.type !== \"toolCall\") continue;\n\t\t\t\tcalls.set(part.id, {\n\t\t\t\t\tid: part.id,\n\t\t\t\t\tname: part.name,\n\t\t\t\t\targs: part.arguments ?? {},\n\t\t\t\t\tmessageIndex,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (message.role === \"toolResult\" && message.toolName === \"read\") {\n\t\t\treadResultCallIds.push(message.toolCallId);\n\t\t}\n\n\t\tif (semanticSettings.enabled && semanticMessageHasMarker(message, semanticSettings)) {\n\t\t\tsemanticIndexes.push(messageIndex);\n\t\t}\n\t}\n\n\tconst latestReadByPath = new Map<string, string>();\n\tfor (const toolCallId of readResultCallIds) {\n\t\tconst call = calls.get(toolCallId);\n\t\tconst path = normalizeToolPath(cwd, call?.args.path);\n\t\tif (path) latestReadByPath.set(path, toolCallId);\n\t}\n\n\treturn { calls, latestReadByPath, semanticIndexes };\n}\n\nfunction storagePathFor(storageDir: string | undefined, key: string): string | undefined {\n\tif (!storageDir || !isAbsolute(storageDir)) return undefined;\n\treturn resolve(storageDir, `${key}.txt`);\n}\n\nfunction maybeStoreOriginal(options: ContextGcOptions, key: string, original: string): string | undefined {\n\tconst path = storagePathFor(options.storageDir, key);\n\tif (!path || !options.writePayloads) return path;\n\ttry {\n\t\tmkdirSync(options.storageDir!, { recursive: true });\n\t\tif (!existsSync(path)) writeFileSync(path, original, \"utf8\");\n\t} catch {\n\t\treturn undefined;\n\t}\n\treturn path;\n}\n\nfunction reasonText(record: ContextGcPackedRecord): string {\n\tif (record.reason === \"superseded-read\") return \"older read snapshot superseded by a later read of the same file\";\n\tif (record.reason === \"stale-semantic-memory\") {\n\t\treturn \"older Automata/Mind semantic context page outside the semantic-memory freshness window\";\n\t}\n\treturn \"stale bulky tool output outside the recent context window\";\n}\n\nfunction buildSummary(record: ContextGcPackedRecord): string {\n\tconst semantic = record.reason === \"stale-semantic-memory\";\n\tconst lines = [\n\t\tsemantic ? \"[Semantic GC packed stale Automata/Mind context page]\" : \"[Context GC packed stale tool result]\",\n\t\tsemantic ? undefined : `tool: ${record.toolName}`,\n\t\trecord.path ? `path: ${record.path}` : undefined,\n\t\trecord.command ? `command: ${cap(record.command)}` : undefined,\n\t\t`reason: ${reasonText(record)}`,\n\t\t`original: ${record.originalChars} chars (~${record.originalTokens} tokens)`,\n\t\trecord.digest ? `summary (auto-digest, machine paraphrase, not authoritative): ${record.digest}` : undefined,\n\t\trecord.storagePath\n\t\t\t? `exact old provider-visible text stored at: ${record.storagePath}`\n\t\t\t: \"exact old provider-visible text retained in the session log, not inline in provider context\",\n\t\tsemantic\n\t\t\t? \"If this memory context matters, query Automata/Mind again with the same topic/filter or fetch the drawer pointers from the stored page.\"\n\t\t\t: record.path\n\t\t\t\t? \"For current file contents, use the read tool on the path above. For the exact old output, read the stored payload path if present.\"\n\t\t\t\t: \"If this exact old output matters, retrieve/read the stored payload path if present or rerun the tool command.\",\n\t\t\"Do not rely on this summary as the original content.\",\n\t].filter((line): line is string => line !== undefined);\n\treturn lines.join(\"\\n\");\n}\n\nfunction gcDetails(message: { details?: unknown }, record: ContextGcPackedRecord): Record<string, unknown> {\n\treturn {\n\t\t...(typeof message.details === \"object\" && message.details !== null ? message.details : {}),\n\t\tcontextGc: {\n\t\t\tpacked: true,\n\t\t\toriginalChars: record.originalChars,\n\t\t\toriginalTokens: record.originalTokens,\n\t\t\tstoragePath: record.storagePath,\n\t\t\treason: record.reason,\n\t\t},\n\t};\n}\n\nfunction makePackedToolResult(message: ToolResultMessage, record: ContextGcPackedRecord): ToolResultMessage {\n\tconst summary = buildSummary(record);\n\treturn {\n\t\t...message,\n\t\tcontent: [{ type: \"text\", text: summary }],\n\t\tdetails: gcDetails(message, record),\n\t};\n}\n\nfunction makePackedSemanticMemoryMessage(message: AgentMessage, record: ContextGcPackedRecord): AgentMessage {\n\tconst summary = buildSummary(record);\n\treturn {\n\t\t...(message as unknown as Record<string, unknown>),\n\t\tcontent: [{ type: \"text\", text: summary }],\n\t\tdetails: gcDetails(message as { details?: unknown }, record),\n\t} as AgentMessage;\n}\n\nexport function applyContextGc(\n\tmessages: AgentMessage[],\n\trawSettings: ContextGcSettings & {\n\t\tcwd?: string;\n\t\tstorageDir?: string;\n\t\twritePayloads?: boolean;\n\t\tcuration?: ContextGcCurationHooks;\n\t},\n): ContextGcResult {\n\tconst settings = normalizeContextGcSettings(rawSettings);\n\tconst baseReport: ContextGcReport = {\n\t\tenabled: settings.enabled,\n\t\tpackedCount: 0,\n\t\toriginalTokens: 0,\n\t\tpackedTokens: 0,\n\t\tsavedTokens: 0,\n\t\trecords: [],\n\t};\n\tif (!settings.enabled) return { messages, report: baseReport };\n\n\tconst options: ContextGcOptions = {\n\t\t...settings,\n\t\tcwd: rawSettings.cwd ?? process.cwd(),\n\t\tstorageDir: rawSettings.storageDir,\n\t\twritePayloads: rawSettings.writePayloads ?? true,\n\t\tcuration: rawSettings.curation,\n\t};\n\tconst eligibleTools = new Set(options.tools);\n\tconst plan = collectContextGcPlan(messages, options.cwd, options.semanticMemory);\n\tconst recentStart = Math.max(0, messages.length - options.preserveRecentMessages);\n\tconst semanticIndexSet = new Set(plan.semanticIndexes);\n\tconst preservedSemanticIndexes = new Set(\n\t\toptions.semanticMemory.preserveRecentPages > 0\n\t\t\t? plan.semanticIndexes.slice(-options.semanticMemory.preserveRecentPages)\n\t\t\t: [],\n\t);\n\tconst nextMessages = messages.slice();\n\tlet changed = false;\n\n\tfor (let index = 0; index < messages.length; index++) {\n\t\tconst message = messages[index];\n\t\tif (semanticIndexSet.has(index) && !preservedSemanticIndexes.has(index) && index < recentStart) {\n\t\t\tconst originalText = agentMessageText(message);\n\t\t\tif (originalText && originalText.length >= options.semanticMemory.minChars) {\n\t\t\t\tconst originalTokens = estimateTokens(message);\n\t\t\t\tconst key = createHash(\"sha256\")\n\t\t\t\t\t.update(`semantic-memory\\0${index}\\0${originalText}`)\n\t\t\t\t\t.digest(\"hex\")\n\t\t\t\t\t.slice(0, 24);\n\t\t\t\tconst storagePath = maybeStoreOriginal(options, key, originalText);\n\t\t\t\tconst record: ContextGcPackedRecord = {\n\t\t\t\t\ttoolName: \"automata-mind\",\n\t\t\t\t\ttoolCallId: `semantic-${index}`,\n\t\t\t\t\tmessageIndex: index,\n\t\t\t\t\treason: \"stale-semantic-memory\",\n\t\t\t\t\toriginalChars: originalText.length,\n\t\t\t\t\toriginalTokens,\n\t\t\t\t\tpackedTokens: 0,\n\t\t\t\t\tstoragePath,\n\t\t\t\t\tkey,\n\t\t\t\t};\n\t\t\t\trecord.digest = options.curation?.resolveDigest?.(key);\n\t\t\t\toptions.curation?.onPacked?.(record, originalText);\n\t\t\t\tconst packed = makePackedSemanticMemoryMessage(message, record);\n\t\t\t\trecord.packedTokens = estimateTokens(packed);\n\t\t\t\tnextMessages[index] = packed;\n\t\t\t\tbaseReport.records.push(record);\n\t\t\t\tbaseReport.originalTokens += record.originalTokens;\n\t\t\t\tbaseReport.packedTokens += record.packedTokens;\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (message.role !== \"toolResult\") continue;\n\t\tif (!eligibleTools.has(message.toolName)) continue;\n\t\tif (index >= recentStart) continue;\n\n\t\tconst originalText = toolResultText(message);\n\t\tif (originalText.length < options.minToolResultChars) continue;\n\n\t\tconst call = plan.calls.get(message.toolCallId);\n\t\tconst path = normalizeToolPath(options.cwd, call?.args.path);\n\t\tlet reason: ContextGcPackedRecord[\"reason\"] = \"stale-tool-result\";\n\t\tif (message.toolName === \"read\" && path) {\n\t\t\tif (plan.latestReadByPath.get(path) === message.toolCallId) continue;\n\t\t\treason = \"superseded-read\";\n\t\t}\n\n\t\tconst originalTokens = estimateTokens(message);\n\t\tconst key = createHash(\"sha256\")\n\t\t\t.update(`${message.toolName}\\0${message.toolCallId}\\0${originalText}`)\n\t\t\t.digest(\"hex\")\n\t\t\t.slice(0, 24);\n\t\tconst storagePath = maybeStoreOriginal(options, key, originalText);\n\t\tconst record: ContextGcPackedRecord = {\n\t\t\ttoolName: message.toolName,\n\t\t\ttoolCallId: message.toolCallId,\n\t\t\tmessageIndex: index,\n\t\t\treason,\n\t\t\toriginalChars: originalText.length,\n\t\t\toriginalTokens,\n\t\t\tpackedTokens: 0,\n\t\t\tstoragePath,\n\t\t\tpath,\n\t\t\tcommand: typeof call?.args.command === \"string\" ? call.args.command : undefined,\n\t\t\tkey,\n\t\t};\n\t\trecord.digest = options.curation?.resolveDigest?.(key);\n\t\toptions.curation?.onPacked?.(record, originalText);\n\t\tconst packed = makePackedToolResult(message, record);\n\t\trecord.packedTokens = estimateTokens(packed);\n\t\tnextMessages[index] = packed as AgentMessage;\n\t\tbaseReport.records.push(record);\n\t\tbaseReport.originalTokens += record.originalTokens;\n\t\tbaseReport.packedTokens += record.packedTokens;\n\t\tchanged = true;\n\t}\n\n\tbaseReport.packedCount = baseReport.records.length;\n\tbaseReport.savedTokens = Math.max(0, baseReport.originalTokens - baseReport.packedTokens);\n\treturn { messages: changed ? nextMessages : messages, report: baseReport };\n}\n"]}
@@ -241,6 +241,7 @@ function buildSummary(record) {
241
241
  record.command ? `command: ${cap(record.command)}` : undefined,
242
242
  `reason: ${reasonText(record)}`,
243
243
  `original: ${record.originalChars} chars (~${record.originalTokens} tokens)`,
244
+ record.digest ? `summary (auto-digest, machine paraphrase, not authoritative): ${record.digest}` : undefined,
244
245
  record.storagePath
245
246
  ? `exact old provider-visible text stored at: ${record.storagePath}`
246
247
  : "exact old provider-visible text retained in the session log, not inline in provider context",
@@ -298,6 +299,7 @@ export function applyContextGc(messages, rawSettings) {
298
299
  cwd: rawSettings.cwd ?? process.cwd(),
299
300
  storageDir: rawSettings.storageDir,
300
301
  writePayloads: rawSettings.writePayloads ?? true,
302
+ curation: rawSettings.curation,
301
303
  };
302
304
  const eligibleTools = new Set(options.tools);
303
305
  const plan = collectContextGcPlan(messages, options.cwd, options.semanticMemory);
@@ -330,6 +332,8 @@ export function applyContextGc(messages, rawSettings) {
330
332
  storagePath,
331
333
  key,
332
334
  };
335
+ record.digest = options.curation?.resolveDigest?.(key);
336
+ options.curation?.onPacked?.(record, originalText);
333
337
  const packed = makePackedSemanticMemoryMessage(message, record);
334
338
  record.packedTokens = estimateTokens(packed);
335
339
  nextMessages[index] = packed;
@@ -376,6 +380,8 @@ export function applyContextGc(messages, rawSettings) {
376
380
  command: typeof call?.args.command === "string" ? call.args.command : undefined,
377
381
  key,
378
382
  };
383
+ record.digest = options.curation?.resolveDigest?.(key);
384
+ options.curation?.onPacked?.(record, originalText);
379
385
  const packed = makePackedToolResult(message, record);
380
386
  record.packedTokens = estimateTokens(packed);
381
387
  nextMessages[index] = packed;
@@ -1 +1 @@
1
- {"version":3,"file":"context-gc.js","sourceRoot":"","sources":["../../src/core/context-gc.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, resolve } from \"node:path\";\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { ToolResultMessage } from \"@caupulican/pi-ai\";\nimport { normalizePath } from \"../utils/paths.ts\";\nimport { estimateTokens } from \"./compaction/compaction.ts\";\n\nexport interface SemanticMemoryGcSettings {\n\tenabled?: boolean;\n\t/** Number of newest Automata/Mind injected pages to preserve verbatim. */\n\tpreserveRecentPages?: number;\n\t/** Minimum provider-visible text chars before a stale semantic memory page is packed. */\n\tminChars?: number;\n\t/** Markers that identify deterministic Automata/Mind context pages. */\n\tmarkers?: string[];\n}\n\nexport interface ContextGcSettings {\n\tenabled?: boolean;\n\t/** Number of most recent AgentMessage rows to preserve verbatim. */\n\tpreserveRecentMessages?: number;\n\t/** Minimum provider-visible text chars before a stale tool result is packed. */\n\tminToolResultChars?: number;\n\t/** Tool names eligible for stale result packing. */\n\ttools?: string[];\n\t/** Provider-context control for deterministic Automata/Mind semantic memory pages. */\n\tsemanticMemory?: SemanticMemoryGcSettings;\n}\n\nexport interface NormalizedContextGcSettings extends Omit<Required<ContextGcSettings>, \"semanticMemory\"> {\n\tsemanticMemory: Required<SemanticMemoryGcSettings>;\n}\n\nexport interface ContextGcOptions extends NormalizedContextGcSettings {\n\tcwd: string;\n\tstorageDir?: string;\n\twritePayloads?: boolean;\n}\n\nexport interface ContextGcPackedRecord {\n\ttoolName: string;\n\ttoolCallId: string;\n\tmessageIndex: number;\n\treason: \"superseded-read\" | \"stale-tool-result\" | \"stale-semantic-memory\";\n\toriginalChars: number;\n\toriginalTokens: number;\n\tpackedTokens: number;\n\tstoragePath?: string;\n\tpath?: string;\n\tcommand?: string;\n\tkey?: string;\n}\n\nexport interface ContextGcReport {\n\tenabled: boolean;\n\tpackedCount: number;\n\toriginalTokens: number;\n\tpackedTokens: number;\n\tsavedTokens: number;\n\trecords: ContextGcPackedRecord[];\n}\n\nexport interface ContextGcResult {\n\tmessages: AgentMessage[];\n\treport: ContextGcReport;\n}\n\nconst DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS: Required<SemanticMemoryGcSettings> = {\n\tenabled: true,\n\tpreserveRecentPages: 1,\n\tminChars: 900,\n\tmarkers: [\n\t\t// Generic memory-subsystem recall page marker (brand-free). Provider-specific markers are\n\t\t// merged in dynamically at runtime via MemoryManager.getContextMarkers().\n\t\t\"<memory_context\",\n\t\t// Pre-existing provider-specific markers (to be generalized to provider-declared markers).\n\t\t\"<automata_context\",\n\t\t\"<automata_response\",\n\t\t\"<automata_query\",\n\t\t\"<automata_fetch\",\n\t\t\"<memory_lifecycle_audit\",\n\t\t\"<memory_lifecycle_purge\",\n\t\t\"<automata_doctor\",\n\t\t\"<automata_optimizer\",\n\t\t\"<automata_mesh\",\n\t],\n};\n\nexport const DEFAULT_CONTEXT_GC_SETTINGS: NormalizedContextGcSettings = {\n\tenabled: true,\n\tpreserveRecentMessages: 8,\n\tminToolResultChars: 1200,\n\ttools: [\n\t\t\"read\",\n\t\t\"bash\",\n\t\t\"rg\",\n\t\t\"grep\",\n\t\t\"find\",\n\t\t\"ls\",\n\t\t\"skill_open\",\n\t\t\"automata_graph_status\",\n\t\t\"automata_graph_search\",\n\t\t\"automata_graph_query\",\n\t\t\"automata_graph_neighbors\",\n\t\t\"automata_graph_path\",\n\t\t\"automata_graph_pointer_pack\",\n\t\t\"learning_query_memory\",\n\t\t\"subagent\",\n\t\t\"task_steps\",\n\t\t\"task_background\",\n\t\t\"task_goal\",\n\t\t\"run_ledger\",\n\t\t\"context_headroom_retrieve\",\n\t\t\"headroom_retrieve\",\n\t],\n\tsemanticMemory: DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS,\n};\n\ntype ToolCallMeta = {\n\tid: string;\n\tname: string;\n\targs: Record<string, unknown>;\n\tmessageIndex: number;\n};\n\nfunction cap(text: string, limit = 220): string {\n\tconst compact = text.replace(/\\s+/g, \" \").trim();\n\treturn compact.length > limit ? `${compact.slice(0, Math.max(0, limit - 1))}…` : compact;\n}\n\nfunction normalizeSemanticMemoryGcSettings(settings?: SemanticMemoryGcSettings): Required<SemanticMemoryGcSettings> {\n\treturn {\n\t\tenabled: settings?.enabled ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.enabled,\n\t\tpreserveRecentPages: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.preserveRecentPages ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.preserveRecentPages),\n\t\t),\n\t\tminChars: Math.max(0, Math.floor(settings?.minChars ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.minChars)),\n\t\tmarkers:\n\t\t\tsettings?.markers && settings.markers.length > 0\n\t\t\t\t? settings.markers\n\t\t\t\t: DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.markers,\n\t};\n}\n\nfunction normalizeContextGcSettings(settings?: ContextGcSettings): NormalizedContextGcSettings {\n\treturn {\n\t\tenabled: settings?.enabled ?? DEFAULT_CONTEXT_GC_SETTINGS.enabled,\n\t\tpreserveRecentMessages: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.preserveRecentMessages ?? DEFAULT_CONTEXT_GC_SETTINGS.preserveRecentMessages),\n\t\t),\n\t\tminToolResultChars: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.minToolResultChars ?? DEFAULT_CONTEXT_GC_SETTINGS.minToolResultChars),\n\t\t),\n\t\ttools: settings?.tools && settings.tools.length > 0 ? settings.tools : DEFAULT_CONTEXT_GC_SETTINGS.tools,\n\t\tsemanticMemory: normalizeSemanticMemoryGcSettings(settings?.semanticMemory),\n\t};\n}\n\nexport function getContextGcSettings(settings?: ContextGcSettings): NormalizedContextGcSettings {\n\treturn normalizeContextGcSettings(settings);\n}\n\nfunction textContentParts(content: unknown): string[] | undefined {\n\tif (typeof content === \"string\") return [content];\n\tif (!Array.isArray(content)) return undefined;\n\tconst parts: string[] = [];\n\tfor (const part of content) {\n\t\tif (typeof part !== \"object\" || part === null) return undefined;\n\t\tconst typed = part as { type?: string; text?: string; mimeType?: string };\n\t\tif (typed.type === \"text\" && typeof typed.text === \"string\") parts.push(typed.text);\n\t\telse if (typed.type === \"image\") return undefined;\n\t\telse return undefined;\n\t}\n\treturn parts;\n}\n\nfunction contentText(content: unknown): string | undefined {\n\tif (typeof content === \"string\") return content;\n\treturn textContentParts(content)?.join(\"\\n\");\n}\n\nfunction toolResultParts(message: ToolResultMessage): string[] {\n\tconst parts: string[] = [];\n\tfor (const part of message.content) {\n\t\tif (part.type === \"text\" && part.text) parts.push(part.text);\n\t\telse if (part.type === \"image\") parts.push(`[image ${part.mimeType}]`);\n\t}\n\treturn parts;\n}\n\nfunction toolResultText(message: ToolResultMessage): string {\n\treturn toolResultParts(message).join(\"\\n\");\n}\n\nfunction smallStringSlice(value: string, start?: number, end?: number): string {\n\tconst sliced = value.slice(start, end);\n\treturn sliced ? ` ${sliced}`.slice(1) : \"\";\n}\n\nfunction joinedPartsContainMarker(parts: string[], marker: string): boolean {\n\tif (marker.length === 0) return true;\n\tconst tailLength = marker.length - 1;\n\tlet tail = \"\";\n\tlet first = true;\n\tfor (const part of parts) {\n\t\tif (part.includes(marker)) return true;\n\t\tif (!first && `${tail}\\n${smallStringSlice(part, 0, tailLength)}`.includes(marker)) return true;\n\t\tif (tailLength === 0) tail = \"\";\n\t\telse if (part.length >= tailLength) tail = smallStringSlice(part, -tailLength);\n\t\telse tail = `${tail}${first ? \"\" : \"\\n\"}${part}`.slice(-tailLength);\n\t\tfirst = false;\n\t}\n\treturn false;\n}\n\nfunction joinedPartsContainAnyMarker(parts: string[], markers: readonly string[]): boolean {\n\treturn markers.some((marker) => joinedPartsContainMarker(parts, marker));\n}\n\nfunction isSemanticMemoryCustomMessage(message: AgentMessage): boolean {\n\tif (message.role !== \"custom\") return false;\n\tconst customType = String((message as { customType?: unknown }).customType ?? \"\").toLowerCase();\n\treturn customType.includes(\"automata\") || customType.includes(\"memory\") || customType.includes(\"mind\");\n}\n\nfunction agentMessageText(message: AgentMessage): string | undefined {\n\tif (message.role === \"toolResult\") return toolResultText(message);\n\tif (isSemanticMemoryCustomMessage(message)) return contentText((message as { content?: unknown }).content);\n\treturn undefined;\n}\n\nfunction semanticMessageHasMarker(message: AgentMessage, settings: Required<SemanticMemoryGcSettings>): boolean {\n\tif (message.role === \"toolResult\") return joinedPartsContainAnyMarker(toolResultParts(message), settings.markers);\n\tif (isSemanticMemoryCustomMessage(message)) {\n\t\tconst parts = textContentParts((message as { content?: unknown }).content);\n\t\treturn parts ? joinedPartsContainAnyMarker(parts, settings.markers) : false;\n\t}\n\treturn false;\n}\n\ninterface ContextGcPlan {\n\tcalls: Map<string, ToolCallMeta>;\n\tlatestReadByPath: Map<string, string>;\n\tsemanticIndexes: number[];\n}\n\nfunction normalizeToolPath(cwd: string, value: unknown): string | undefined {\n\tif (typeof value !== \"string\" || value.trim() === \"\") return undefined;\n\tconst path = value.trim();\n\treturn normalizePath(isAbsolute(path) ? path : resolve(cwd, path));\n}\n\nfunction collectContextGcPlan(\n\tmessages: AgentMessage[],\n\tcwd: string,\n\tsemanticSettings: Required<SemanticMemoryGcSettings>,\n): ContextGcPlan {\n\tconst calls = new Map<string, ToolCallMeta>();\n\tconst readResultCallIds: string[] = [];\n\tconst semanticIndexes: number[] = [];\n\n\tfor (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {\n\t\tconst message = messages[messageIndex];\n\t\tif (message.role === \"assistant\") {\n\t\t\tfor (const part of message.content) {\n\t\t\t\tif (part.type !== \"toolCall\") continue;\n\t\t\t\tcalls.set(part.id, {\n\t\t\t\t\tid: part.id,\n\t\t\t\t\tname: part.name,\n\t\t\t\t\targs: part.arguments ?? {},\n\t\t\t\t\tmessageIndex,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (message.role === \"toolResult\" && message.toolName === \"read\") {\n\t\t\treadResultCallIds.push(message.toolCallId);\n\t\t}\n\n\t\tif (semanticSettings.enabled && semanticMessageHasMarker(message, semanticSettings)) {\n\t\t\tsemanticIndexes.push(messageIndex);\n\t\t}\n\t}\n\n\tconst latestReadByPath = new Map<string, string>();\n\tfor (const toolCallId of readResultCallIds) {\n\t\tconst call = calls.get(toolCallId);\n\t\tconst path = normalizeToolPath(cwd, call?.args.path);\n\t\tif (path) latestReadByPath.set(path, toolCallId);\n\t}\n\n\treturn { calls, latestReadByPath, semanticIndexes };\n}\n\nfunction storagePathFor(storageDir: string | undefined, key: string): string | undefined {\n\tif (!storageDir || !isAbsolute(storageDir)) return undefined;\n\treturn resolve(storageDir, `${key}.txt`);\n}\n\nfunction maybeStoreOriginal(options: ContextGcOptions, key: string, original: string): string | undefined {\n\tconst path = storagePathFor(options.storageDir, key);\n\tif (!path || !options.writePayloads) return path;\n\ttry {\n\t\tmkdirSync(options.storageDir!, { recursive: true });\n\t\tif (!existsSync(path)) writeFileSync(path, original, \"utf8\");\n\t} catch {\n\t\treturn undefined;\n\t}\n\treturn path;\n}\n\nfunction reasonText(record: ContextGcPackedRecord): string {\n\tif (record.reason === \"superseded-read\") return \"older read snapshot superseded by a later read of the same file\";\n\tif (record.reason === \"stale-semantic-memory\") {\n\t\treturn \"older Automata/Mind semantic context page outside the semantic-memory freshness window\";\n\t}\n\treturn \"stale bulky tool output outside the recent context window\";\n}\n\nfunction buildSummary(record: ContextGcPackedRecord): string {\n\tconst semantic = record.reason === \"stale-semantic-memory\";\n\tconst lines = [\n\t\tsemantic ? \"[Semantic GC packed stale Automata/Mind context page]\" : \"[Context GC packed stale tool result]\",\n\t\tsemantic ? undefined : `tool: ${record.toolName}`,\n\t\trecord.path ? `path: ${record.path}` : undefined,\n\t\trecord.command ? `command: ${cap(record.command)}` : undefined,\n\t\t`reason: ${reasonText(record)}`,\n\t\t`original: ${record.originalChars} chars (~${record.originalTokens} tokens)`,\n\t\trecord.storagePath\n\t\t\t? `exact old provider-visible text stored at: ${record.storagePath}`\n\t\t\t: \"exact old provider-visible text retained in the session log, not inline in provider context\",\n\t\tsemantic\n\t\t\t? \"If this memory context matters, query Automata/Mind again with the same topic/filter or fetch the drawer pointers from the stored page.\"\n\t\t\t: record.path\n\t\t\t\t? \"For current file contents, use the read tool on the path above. For the exact old output, read the stored payload path if present.\"\n\t\t\t\t: \"If this exact old output matters, retrieve/read the stored payload path if present or rerun the tool command.\",\n\t\t\"Do not rely on this summary as the original content.\",\n\t].filter((line): line is string => line !== undefined);\n\treturn lines.join(\"\\n\");\n}\n\nfunction gcDetails(message: { details?: unknown }, record: ContextGcPackedRecord): Record<string, unknown> {\n\treturn {\n\t\t...(typeof message.details === \"object\" && message.details !== null ? message.details : {}),\n\t\tcontextGc: {\n\t\t\tpacked: true,\n\t\t\toriginalChars: record.originalChars,\n\t\t\toriginalTokens: record.originalTokens,\n\t\t\tstoragePath: record.storagePath,\n\t\t\treason: record.reason,\n\t\t},\n\t};\n}\n\nfunction makePackedToolResult(message: ToolResultMessage, record: ContextGcPackedRecord): ToolResultMessage {\n\tconst summary = buildSummary(record);\n\treturn {\n\t\t...message,\n\t\tcontent: [{ type: \"text\", text: summary }],\n\t\tdetails: gcDetails(message, record),\n\t};\n}\n\nfunction makePackedSemanticMemoryMessage(message: AgentMessage, record: ContextGcPackedRecord): AgentMessage {\n\tconst summary = buildSummary(record);\n\treturn {\n\t\t...(message as unknown as Record<string, unknown>),\n\t\tcontent: [{ type: \"text\", text: summary }],\n\t\tdetails: gcDetails(message as { details?: unknown }, record),\n\t} as AgentMessage;\n}\n\nexport function applyContextGc(\n\tmessages: AgentMessage[],\n\trawSettings: ContextGcSettings & { cwd?: string; storageDir?: string; writePayloads?: boolean },\n): ContextGcResult {\n\tconst settings = normalizeContextGcSettings(rawSettings);\n\tconst baseReport: ContextGcReport = {\n\t\tenabled: settings.enabled,\n\t\tpackedCount: 0,\n\t\toriginalTokens: 0,\n\t\tpackedTokens: 0,\n\t\tsavedTokens: 0,\n\t\trecords: [],\n\t};\n\tif (!settings.enabled) return { messages, report: baseReport };\n\n\tconst options: ContextGcOptions = {\n\t\t...settings,\n\t\tcwd: rawSettings.cwd ?? process.cwd(),\n\t\tstorageDir: rawSettings.storageDir,\n\t\twritePayloads: rawSettings.writePayloads ?? true,\n\t};\n\tconst eligibleTools = new Set(options.tools);\n\tconst plan = collectContextGcPlan(messages, options.cwd, options.semanticMemory);\n\tconst recentStart = Math.max(0, messages.length - options.preserveRecentMessages);\n\tconst semanticIndexSet = new Set(plan.semanticIndexes);\n\tconst preservedSemanticIndexes = new Set(\n\t\toptions.semanticMemory.preserveRecentPages > 0\n\t\t\t? plan.semanticIndexes.slice(-options.semanticMemory.preserveRecentPages)\n\t\t\t: [],\n\t);\n\tconst nextMessages = messages.slice();\n\tlet changed = false;\n\n\tfor (let index = 0; index < messages.length; index++) {\n\t\tconst message = messages[index];\n\t\tif (semanticIndexSet.has(index) && !preservedSemanticIndexes.has(index) && index < recentStart) {\n\t\t\tconst originalText = agentMessageText(message);\n\t\t\tif (originalText && originalText.length >= options.semanticMemory.minChars) {\n\t\t\t\tconst originalTokens = estimateTokens(message);\n\t\t\t\tconst key = createHash(\"sha256\")\n\t\t\t\t\t.update(`semantic-memory\\0${index}\\0${originalText}`)\n\t\t\t\t\t.digest(\"hex\")\n\t\t\t\t\t.slice(0, 24);\n\t\t\t\tconst storagePath = maybeStoreOriginal(options, key, originalText);\n\t\t\t\tconst record: ContextGcPackedRecord = {\n\t\t\t\t\ttoolName: \"automata-mind\",\n\t\t\t\t\ttoolCallId: `semantic-${index}`,\n\t\t\t\t\tmessageIndex: index,\n\t\t\t\t\treason: \"stale-semantic-memory\",\n\t\t\t\t\toriginalChars: originalText.length,\n\t\t\t\t\toriginalTokens,\n\t\t\t\t\tpackedTokens: 0,\n\t\t\t\t\tstoragePath,\n\t\t\t\t\tkey,\n\t\t\t\t};\n\t\t\t\tconst packed = makePackedSemanticMemoryMessage(message, record);\n\t\t\t\trecord.packedTokens = estimateTokens(packed);\n\t\t\t\tnextMessages[index] = packed;\n\t\t\t\tbaseReport.records.push(record);\n\t\t\t\tbaseReport.originalTokens += record.originalTokens;\n\t\t\t\tbaseReport.packedTokens += record.packedTokens;\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (message.role !== \"toolResult\") continue;\n\t\tif (!eligibleTools.has(message.toolName)) continue;\n\t\tif (index >= recentStart) continue;\n\n\t\tconst originalText = toolResultText(message);\n\t\tif (originalText.length < options.minToolResultChars) continue;\n\n\t\tconst call = plan.calls.get(message.toolCallId);\n\t\tconst path = normalizeToolPath(options.cwd, call?.args.path);\n\t\tlet reason: ContextGcPackedRecord[\"reason\"] = \"stale-tool-result\";\n\t\tif (message.toolName === \"read\" && path) {\n\t\t\tif (plan.latestReadByPath.get(path) === message.toolCallId) continue;\n\t\t\treason = \"superseded-read\";\n\t\t}\n\n\t\tconst originalTokens = estimateTokens(message);\n\t\tconst key = createHash(\"sha256\")\n\t\t\t.update(`${message.toolName}\\0${message.toolCallId}\\0${originalText}`)\n\t\t\t.digest(\"hex\")\n\t\t\t.slice(0, 24);\n\t\tconst storagePath = maybeStoreOriginal(options, key, originalText);\n\t\tconst record: ContextGcPackedRecord = {\n\t\t\ttoolName: message.toolName,\n\t\t\ttoolCallId: message.toolCallId,\n\t\t\tmessageIndex: index,\n\t\t\treason,\n\t\t\toriginalChars: originalText.length,\n\t\t\toriginalTokens,\n\t\t\tpackedTokens: 0,\n\t\t\tstoragePath,\n\t\t\tpath,\n\t\t\tcommand: typeof call?.args.command === \"string\" ? call.args.command : undefined,\n\t\t\tkey,\n\t\t};\n\t\tconst packed = makePackedToolResult(message, record);\n\t\trecord.packedTokens = estimateTokens(packed);\n\t\tnextMessages[index] = packed as AgentMessage;\n\t\tbaseReport.records.push(record);\n\t\tbaseReport.originalTokens += record.originalTokens;\n\t\tbaseReport.packedTokens += record.packedTokens;\n\t\tchanged = true;\n\t}\n\n\tbaseReport.packedCount = baseReport.records.length;\n\tbaseReport.savedTokens = Math.max(0, baseReport.originalTokens - baseReport.packedTokens);\n\treturn { messages: changed ? nextMessages : messages, report: baseReport };\n}\n"]}
1
+ {"version":3,"file":"context-gc.js","sourceRoot":"","sources":["../../src/core/context-gc.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, resolve } from \"node:path\";\nimport type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { ToolResultMessage } from \"@caupulican/pi-ai\";\nimport { normalizePath } from \"../utils/paths.ts\";\nimport { estimateTokens } from \"./compaction/compaction.ts\";\n\nexport interface SemanticMemoryGcSettings {\n\tenabled?: boolean;\n\t/** Number of newest Automata/Mind injected pages to preserve verbatim. */\n\tpreserveRecentPages?: number;\n\t/** Minimum provider-visible text chars before a stale semantic memory page is packed. */\n\tminChars?: number;\n\t/** Markers that identify deterministic Automata/Mind context pages. */\n\tmarkers?: string[];\n}\n\nexport interface ContextGcSettings {\n\tenabled?: boolean;\n\t/** Number of most recent AgentMessage rows to preserve verbatim. */\n\tpreserveRecentMessages?: number;\n\t/** Minimum provider-visible text chars before a stale tool result is packed. */\n\tminToolResultChars?: number;\n\t/** Tool names eligible for stale result packing. */\n\ttools?: string[];\n\t/** Provider-context control for deterministic Automata/Mind semantic memory pages. */\n\tsemanticMemory?: SemanticMemoryGcSettings;\n}\n\nexport interface NormalizedContextGcSettings extends Omit<Required<ContextGcSettings>, \"semanticMemory\"> {\n\tsemanticMemory: Required<SemanticMemoryGcSettings>;\n}\n\n/**\n * Brain-curation hooks (both optional; absent hooks are byte-for-byte today's behavior).\n * `resolveDigest` is a pure lookup keyed by the record's content hash; `onPacked` lets the\n * caller enqueue digest work with the exact original text at the moment it is packed.\n */\nexport interface ContextGcCurationHooks {\n\tresolveDigest?: (digestKey: string) => string | undefined;\n\tonPacked?: (record: ContextGcPackedRecord, originalText: string) => void;\n}\n\nexport interface ContextGcOptions extends NormalizedContextGcSettings {\n\tcwd: string;\n\tstorageDir?: string;\n\twritePayloads?: boolean;\n\tcuration?: ContextGcCurationHooks;\n}\n\nexport interface ContextGcPackedRecord {\n\ttoolName: string;\n\ttoolCallId: string;\n\tmessageIndex: number;\n\treason: \"superseded-read\" | \"stale-tool-result\" | \"stale-semantic-memory\";\n\toriginalChars: number;\n\toriginalTokens: number;\n\tpackedTokens: number;\n\tstoragePath?: string;\n\tpath?: string;\n\tcommand?: string;\n\tkey?: string;\n\t/** Brain-curator semantic digest of the packed content (model-generated; advisory only). */\n\tdigest?: string;\n}\n\nexport interface ContextGcReport {\n\tenabled: boolean;\n\tpackedCount: number;\n\toriginalTokens: number;\n\tpackedTokens: number;\n\tsavedTokens: number;\n\trecords: ContextGcPackedRecord[];\n}\n\nexport interface ContextGcResult {\n\tmessages: AgentMessage[];\n\treport: ContextGcReport;\n}\n\nconst DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS: Required<SemanticMemoryGcSettings> = {\n\tenabled: true,\n\tpreserveRecentPages: 1,\n\tminChars: 900,\n\tmarkers: [\n\t\t// Generic memory-subsystem recall page marker (brand-free). Provider-specific markers are\n\t\t// merged in dynamically at runtime via MemoryManager.getContextMarkers().\n\t\t\"<memory_context\",\n\t\t// Pre-existing provider-specific markers (to be generalized to provider-declared markers).\n\t\t\"<automata_context\",\n\t\t\"<automata_response\",\n\t\t\"<automata_query\",\n\t\t\"<automata_fetch\",\n\t\t\"<memory_lifecycle_audit\",\n\t\t\"<memory_lifecycle_purge\",\n\t\t\"<automata_doctor\",\n\t\t\"<automata_optimizer\",\n\t\t\"<automata_mesh\",\n\t],\n};\n\nexport const DEFAULT_CONTEXT_GC_SETTINGS: NormalizedContextGcSettings = {\n\tenabled: true,\n\tpreserveRecentMessages: 8,\n\tminToolResultChars: 1200,\n\ttools: [\n\t\t\"read\",\n\t\t\"bash\",\n\t\t\"rg\",\n\t\t\"grep\",\n\t\t\"find\",\n\t\t\"ls\",\n\t\t\"skill_open\",\n\t\t\"automata_graph_status\",\n\t\t\"automata_graph_search\",\n\t\t\"automata_graph_query\",\n\t\t\"automata_graph_neighbors\",\n\t\t\"automata_graph_path\",\n\t\t\"automata_graph_pointer_pack\",\n\t\t\"learning_query_memory\",\n\t\t\"subagent\",\n\t\t\"task_steps\",\n\t\t\"task_background\",\n\t\t\"task_goal\",\n\t\t\"run_ledger\",\n\t\t\"context_headroom_retrieve\",\n\t\t\"headroom_retrieve\",\n\t],\n\tsemanticMemory: DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS,\n};\n\ntype ToolCallMeta = {\n\tid: string;\n\tname: string;\n\targs: Record<string, unknown>;\n\tmessageIndex: number;\n};\n\nfunction cap(text: string, limit = 220): string {\n\tconst compact = text.replace(/\\s+/g, \" \").trim();\n\treturn compact.length > limit ? `${compact.slice(0, Math.max(0, limit - 1))}…` : compact;\n}\n\nfunction normalizeSemanticMemoryGcSettings(settings?: SemanticMemoryGcSettings): Required<SemanticMemoryGcSettings> {\n\treturn {\n\t\tenabled: settings?.enabled ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.enabled,\n\t\tpreserveRecentPages: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.preserveRecentPages ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.preserveRecentPages),\n\t\t),\n\t\tminChars: Math.max(0, Math.floor(settings?.minChars ?? DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.minChars)),\n\t\tmarkers:\n\t\t\tsettings?.markers && settings.markers.length > 0\n\t\t\t\t? settings.markers\n\t\t\t\t: DEFAULT_SEMANTIC_MEMORY_GC_SETTINGS.markers,\n\t};\n}\n\nfunction normalizeContextGcSettings(settings?: ContextGcSettings): NormalizedContextGcSettings {\n\treturn {\n\t\tenabled: settings?.enabled ?? DEFAULT_CONTEXT_GC_SETTINGS.enabled,\n\t\tpreserveRecentMessages: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.preserveRecentMessages ?? DEFAULT_CONTEXT_GC_SETTINGS.preserveRecentMessages),\n\t\t),\n\t\tminToolResultChars: Math.max(\n\t\t\t0,\n\t\t\tMath.floor(settings?.minToolResultChars ?? DEFAULT_CONTEXT_GC_SETTINGS.minToolResultChars),\n\t\t),\n\t\ttools: settings?.tools && settings.tools.length > 0 ? settings.tools : DEFAULT_CONTEXT_GC_SETTINGS.tools,\n\t\tsemanticMemory: normalizeSemanticMemoryGcSettings(settings?.semanticMemory),\n\t};\n}\n\nexport function getContextGcSettings(settings?: ContextGcSettings): NormalizedContextGcSettings {\n\treturn normalizeContextGcSettings(settings);\n}\n\nfunction textContentParts(content: unknown): string[] | undefined {\n\tif (typeof content === \"string\") return [content];\n\tif (!Array.isArray(content)) return undefined;\n\tconst parts: string[] = [];\n\tfor (const part of content) {\n\t\tif (typeof part !== \"object\" || part === null) return undefined;\n\t\tconst typed = part as { type?: string; text?: string; mimeType?: string };\n\t\tif (typed.type === \"text\" && typeof typed.text === \"string\") parts.push(typed.text);\n\t\telse if (typed.type === \"image\") return undefined;\n\t\telse return undefined;\n\t}\n\treturn parts;\n}\n\nfunction contentText(content: unknown): string | undefined {\n\tif (typeof content === \"string\") return content;\n\treturn textContentParts(content)?.join(\"\\n\");\n}\n\nfunction toolResultParts(message: ToolResultMessage): string[] {\n\tconst parts: string[] = [];\n\tfor (const part of message.content) {\n\t\tif (part.type === \"text\" && part.text) parts.push(part.text);\n\t\telse if (part.type === \"image\") parts.push(`[image ${part.mimeType}]`);\n\t}\n\treturn parts;\n}\n\nfunction toolResultText(message: ToolResultMessage): string {\n\treturn toolResultParts(message).join(\"\\n\");\n}\n\nfunction smallStringSlice(value: string, start?: number, end?: number): string {\n\tconst sliced = value.slice(start, end);\n\treturn sliced ? ` ${sliced}`.slice(1) : \"\";\n}\n\nfunction joinedPartsContainMarker(parts: string[], marker: string): boolean {\n\tif (marker.length === 0) return true;\n\tconst tailLength = marker.length - 1;\n\tlet tail = \"\";\n\tlet first = true;\n\tfor (const part of parts) {\n\t\tif (part.includes(marker)) return true;\n\t\tif (!first && `${tail}\\n${smallStringSlice(part, 0, tailLength)}`.includes(marker)) return true;\n\t\tif (tailLength === 0) tail = \"\";\n\t\telse if (part.length >= tailLength) tail = smallStringSlice(part, -tailLength);\n\t\telse tail = `${tail}${first ? \"\" : \"\\n\"}${part}`.slice(-tailLength);\n\t\tfirst = false;\n\t}\n\treturn false;\n}\n\nfunction joinedPartsContainAnyMarker(parts: string[], markers: readonly string[]): boolean {\n\treturn markers.some((marker) => joinedPartsContainMarker(parts, marker));\n}\n\nfunction isSemanticMemoryCustomMessage(message: AgentMessage): boolean {\n\tif (message.role !== \"custom\") return false;\n\tconst customType = String((message as { customType?: unknown }).customType ?? \"\").toLowerCase();\n\treturn customType.includes(\"automata\") || customType.includes(\"memory\") || customType.includes(\"mind\");\n}\n\nfunction agentMessageText(message: AgentMessage): string | undefined {\n\tif (message.role === \"toolResult\") return toolResultText(message);\n\tif (isSemanticMemoryCustomMessage(message)) return contentText((message as { content?: unknown }).content);\n\treturn undefined;\n}\n\nfunction semanticMessageHasMarker(message: AgentMessage, settings: Required<SemanticMemoryGcSettings>): boolean {\n\tif (message.role === \"toolResult\") return joinedPartsContainAnyMarker(toolResultParts(message), settings.markers);\n\tif (isSemanticMemoryCustomMessage(message)) {\n\t\tconst parts = textContentParts((message as { content?: unknown }).content);\n\t\treturn parts ? joinedPartsContainAnyMarker(parts, settings.markers) : false;\n\t}\n\treturn false;\n}\n\ninterface ContextGcPlan {\n\tcalls: Map<string, ToolCallMeta>;\n\tlatestReadByPath: Map<string, string>;\n\tsemanticIndexes: number[];\n}\n\nfunction normalizeToolPath(cwd: string, value: unknown): string | undefined {\n\tif (typeof value !== \"string\" || value.trim() === \"\") return undefined;\n\tconst path = value.trim();\n\treturn normalizePath(isAbsolute(path) ? path : resolve(cwd, path));\n}\n\nfunction collectContextGcPlan(\n\tmessages: AgentMessage[],\n\tcwd: string,\n\tsemanticSettings: Required<SemanticMemoryGcSettings>,\n): ContextGcPlan {\n\tconst calls = new Map<string, ToolCallMeta>();\n\tconst readResultCallIds: string[] = [];\n\tconst semanticIndexes: number[] = [];\n\n\tfor (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {\n\t\tconst message = messages[messageIndex];\n\t\tif (message.role === \"assistant\") {\n\t\t\tfor (const part of message.content) {\n\t\t\t\tif (part.type !== \"toolCall\") continue;\n\t\t\t\tcalls.set(part.id, {\n\t\t\t\t\tid: part.id,\n\t\t\t\t\tname: part.name,\n\t\t\t\t\targs: part.arguments ?? {},\n\t\t\t\t\tmessageIndex,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (message.role === \"toolResult\" && message.toolName === \"read\") {\n\t\t\treadResultCallIds.push(message.toolCallId);\n\t\t}\n\n\t\tif (semanticSettings.enabled && semanticMessageHasMarker(message, semanticSettings)) {\n\t\t\tsemanticIndexes.push(messageIndex);\n\t\t}\n\t}\n\n\tconst latestReadByPath = new Map<string, string>();\n\tfor (const toolCallId of readResultCallIds) {\n\t\tconst call = calls.get(toolCallId);\n\t\tconst path = normalizeToolPath(cwd, call?.args.path);\n\t\tif (path) latestReadByPath.set(path, toolCallId);\n\t}\n\n\treturn { calls, latestReadByPath, semanticIndexes };\n}\n\nfunction storagePathFor(storageDir: string | undefined, key: string): string | undefined {\n\tif (!storageDir || !isAbsolute(storageDir)) return undefined;\n\treturn resolve(storageDir, `${key}.txt`);\n}\n\nfunction maybeStoreOriginal(options: ContextGcOptions, key: string, original: string): string | undefined {\n\tconst path = storagePathFor(options.storageDir, key);\n\tif (!path || !options.writePayloads) return path;\n\ttry {\n\t\tmkdirSync(options.storageDir!, { recursive: true });\n\t\tif (!existsSync(path)) writeFileSync(path, original, \"utf8\");\n\t} catch {\n\t\treturn undefined;\n\t}\n\treturn path;\n}\n\nfunction reasonText(record: ContextGcPackedRecord): string {\n\tif (record.reason === \"superseded-read\") return \"older read snapshot superseded by a later read of the same file\";\n\tif (record.reason === \"stale-semantic-memory\") {\n\t\treturn \"older Automata/Mind semantic context page outside the semantic-memory freshness window\";\n\t}\n\treturn \"stale bulky tool output outside the recent context window\";\n}\n\nfunction buildSummary(record: ContextGcPackedRecord): string {\n\tconst semantic = record.reason === \"stale-semantic-memory\";\n\tconst lines = [\n\t\tsemantic ? \"[Semantic GC packed stale Automata/Mind context page]\" : \"[Context GC packed stale tool result]\",\n\t\tsemantic ? undefined : `tool: ${record.toolName}`,\n\t\trecord.path ? `path: ${record.path}` : undefined,\n\t\trecord.command ? `command: ${cap(record.command)}` : undefined,\n\t\t`reason: ${reasonText(record)}`,\n\t\t`original: ${record.originalChars} chars (~${record.originalTokens} tokens)`,\n\t\trecord.digest ? `summary (auto-digest, machine paraphrase, not authoritative): ${record.digest}` : undefined,\n\t\trecord.storagePath\n\t\t\t? `exact old provider-visible text stored at: ${record.storagePath}`\n\t\t\t: \"exact old provider-visible text retained in the session log, not inline in provider context\",\n\t\tsemantic\n\t\t\t? \"If this memory context matters, query Automata/Mind again with the same topic/filter or fetch the drawer pointers from the stored page.\"\n\t\t\t: record.path\n\t\t\t\t? \"For current file contents, use the read tool on the path above. For the exact old output, read the stored payload path if present.\"\n\t\t\t\t: \"If this exact old output matters, retrieve/read the stored payload path if present or rerun the tool command.\",\n\t\t\"Do not rely on this summary as the original content.\",\n\t].filter((line): line is string => line !== undefined);\n\treturn lines.join(\"\\n\");\n}\n\nfunction gcDetails(message: { details?: unknown }, record: ContextGcPackedRecord): Record<string, unknown> {\n\treturn {\n\t\t...(typeof message.details === \"object\" && message.details !== null ? message.details : {}),\n\t\tcontextGc: {\n\t\t\tpacked: true,\n\t\t\toriginalChars: record.originalChars,\n\t\t\toriginalTokens: record.originalTokens,\n\t\t\tstoragePath: record.storagePath,\n\t\t\treason: record.reason,\n\t\t},\n\t};\n}\n\nfunction makePackedToolResult(message: ToolResultMessage, record: ContextGcPackedRecord): ToolResultMessage {\n\tconst summary = buildSummary(record);\n\treturn {\n\t\t...message,\n\t\tcontent: [{ type: \"text\", text: summary }],\n\t\tdetails: gcDetails(message, record),\n\t};\n}\n\nfunction makePackedSemanticMemoryMessage(message: AgentMessage, record: ContextGcPackedRecord): AgentMessage {\n\tconst summary = buildSummary(record);\n\treturn {\n\t\t...(message as unknown as Record<string, unknown>),\n\t\tcontent: [{ type: \"text\", text: summary }],\n\t\tdetails: gcDetails(message as { details?: unknown }, record),\n\t} as AgentMessage;\n}\n\nexport function applyContextGc(\n\tmessages: AgentMessage[],\n\trawSettings: ContextGcSettings & {\n\t\tcwd?: string;\n\t\tstorageDir?: string;\n\t\twritePayloads?: boolean;\n\t\tcuration?: ContextGcCurationHooks;\n\t},\n): ContextGcResult {\n\tconst settings = normalizeContextGcSettings(rawSettings);\n\tconst baseReport: ContextGcReport = {\n\t\tenabled: settings.enabled,\n\t\tpackedCount: 0,\n\t\toriginalTokens: 0,\n\t\tpackedTokens: 0,\n\t\tsavedTokens: 0,\n\t\trecords: [],\n\t};\n\tif (!settings.enabled) return { messages, report: baseReport };\n\n\tconst options: ContextGcOptions = {\n\t\t...settings,\n\t\tcwd: rawSettings.cwd ?? process.cwd(),\n\t\tstorageDir: rawSettings.storageDir,\n\t\twritePayloads: rawSettings.writePayloads ?? true,\n\t\tcuration: rawSettings.curation,\n\t};\n\tconst eligibleTools = new Set(options.tools);\n\tconst plan = collectContextGcPlan(messages, options.cwd, options.semanticMemory);\n\tconst recentStart = Math.max(0, messages.length - options.preserveRecentMessages);\n\tconst semanticIndexSet = new Set(plan.semanticIndexes);\n\tconst preservedSemanticIndexes = new Set(\n\t\toptions.semanticMemory.preserveRecentPages > 0\n\t\t\t? plan.semanticIndexes.slice(-options.semanticMemory.preserveRecentPages)\n\t\t\t: [],\n\t);\n\tconst nextMessages = messages.slice();\n\tlet changed = false;\n\n\tfor (let index = 0; index < messages.length; index++) {\n\t\tconst message = messages[index];\n\t\tif (semanticIndexSet.has(index) && !preservedSemanticIndexes.has(index) && index < recentStart) {\n\t\t\tconst originalText = agentMessageText(message);\n\t\t\tif (originalText && originalText.length >= options.semanticMemory.minChars) {\n\t\t\t\tconst originalTokens = estimateTokens(message);\n\t\t\t\tconst key = createHash(\"sha256\")\n\t\t\t\t\t.update(`semantic-memory\\0${index}\\0${originalText}`)\n\t\t\t\t\t.digest(\"hex\")\n\t\t\t\t\t.slice(0, 24);\n\t\t\t\tconst storagePath = maybeStoreOriginal(options, key, originalText);\n\t\t\t\tconst record: ContextGcPackedRecord = {\n\t\t\t\t\ttoolName: \"automata-mind\",\n\t\t\t\t\ttoolCallId: `semantic-${index}`,\n\t\t\t\t\tmessageIndex: index,\n\t\t\t\t\treason: \"stale-semantic-memory\",\n\t\t\t\t\toriginalChars: originalText.length,\n\t\t\t\t\toriginalTokens,\n\t\t\t\t\tpackedTokens: 0,\n\t\t\t\t\tstoragePath,\n\t\t\t\t\tkey,\n\t\t\t\t};\n\t\t\t\trecord.digest = options.curation?.resolveDigest?.(key);\n\t\t\t\toptions.curation?.onPacked?.(record, originalText);\n\t\t\t\tconst packed = makePackedSemanticMemoryMessage(message, record);\n\t\t\t\trecord.packedTokens = estimateTokens(packed);\n\t\t\t\tnextMessages[index] = packed;\n\t\t\t\tbaseReport.records.push(record);\n\t\t\t\tbaseReport.originalTokens += record.originalTokens;\n\t\t\t\tbaseReport.packedTokens += record.packedTokens;\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (message.role !== \"toolResult\") continue;\n\t\tif (!eligibleTools.has(message.toolName)) continue;\n\t\tif (index >= recentStart) continue;\n\n\t\tconst originalText = toolResultText(message);\n\t\tif (originalText.length < options.minToolResultChars) continue;\n\n\t\tconst call = plan.calls.get(message.toolCallId);\n\t\tconst path = normalizeToolPath(options.cwd, call?.args.path);\n\t\tlet reason: ContextGcPackedRecord[\"reason\"] = \"stale-tool-result\";\n\t\tif (message.toolName === \"read\" && path) {\n\t\t\tif (plan.latestReadByPath.get(path) === message.toolCallId) continue;\n\t\t\treason = \"superseded-read\";\n\t\t}\n\n\t\tconst originalTokens = estimateTokens(message);\n\t\tconst key = createHash(\"sha256\")\n\t\t\t.update(`${message.toolName}\\0${message.toolCallId}\\0${originalText}`)\n\t\t\t.digest(\"hex\")\n\t\t\t.slice(0, 24);\n\t\tconst storagePath = maybeStoreOriginal(options, key, originalText);\n\t\tconst record: ContextGcPackedRecord = {\n\t\t\ttoolName: message.toolName,\n\t\t\ttoolCallId: message.toolCallId,\n\t\t\tmessageIndex: index,\n\t\t\treason,\n\t\t\toriginalChars: originalText.length,\n\t\t\toriginalTokens,\n\t\t\tpackedTokens: 0,\n\t\t\tstoragePath,\n\t\t\tpath,\n\t\t\tcommand: typeof call?.args.command === \"string\" ? call.args.command : undefined,\n\t\t\tkey,\n\t\t};\n\t\trecord.digest = options.curation?.resolveDigest?.(key);\n\t\toptions.curation?.onPacked?.(record, originalText);\n\t\tconst packed = makePackedToolResult(message, record);\n\t\trecord.packedTokens = estimateTokens(packed);\n\t\tnextMessages[index] = packed as AgentMessage;\n\t\tbaseReport.records.push(record);\n\t\tbaseReport.originalTokens += record.originalTokens;\n\t\tbaseReport.packedTokens += record.packedTokens;\n\t\tchanged = true;\n\t}\n\n\tbaseReport.packedCount = baseReport.records.length;\n\tbaseReport.savedTokens = Math.max(0, baseReport.originalTokens - baseReport.packedTokens);\n\treturn { messages: changed ? nextMessages : messages, report: baseReport };\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import type { Usage } from "@caupulican/pi-ai";
2
+ import { type SessionEntry } from "../session-manager.ts";
3
+ export declare function readAutoLearnSessionIdFromFile(filePath: string): string | undefined;
4
+ export declare function findChildSessionFile(sessionDir: string, sessionId: string): string | undefined;
5
+ export declare function aggregateCumulativeUsageFromSessionEntries(entries: SessionEntry[]): Usage;
6
+ export declare function reportCompletedAutoLearnUsageHelper(args: {
7
+ runId: string;
8
+ sessionDir: string;
9
+ sessionId: string;
10
+ logPath?: string;
11
+ parentSession: {
12
+ addSpawnedUsage: (usage: Usage, opts: {
13
+ label: string;
14
+ sourceSessionId: string;
15
+ reportId: string;
16
+ }) => string | undefined;
17
+ };
18
+ appendLog?: (logPath: string, message: string) => void;
19
+ }): void;
20
+ //# sourceMappingURL=session-usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-usage.d.ts","sourceRoot":"","sources":["../../../src/core/cost/session-usage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAoB,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAqB/E,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAqBnF;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAuC9F;AAED,wBAAgB,0CAA0C,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,KAAK,CAqDzF;AAED,wBAAgB,mCAAmC,CAAC,IAAI,EAAE;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE;QACd,eAAe,EAAE,CAChB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,eAAe,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,KAC9D,MAAM,GAAG,SAAS,CAAC;KACxB,CAAC;IACF,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD,GAAG,IAAI,CA0BP","sourcesContent":["import * as fs from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport type { AssistantMessage, Usage } from \"@caupulican/pi-ai\";\nimport { SPAWNED_USAGE_CUSTOM_TYPE, type SpawnedUsageReport } from \"../agent-session.ts\";\nimport { loadEntriesFromFile, type SessionEntry } from \"../session-manager.ts\";\n\nfunction isUsage(value: unknown): value is Usage {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst usage = value as Partial<Usage>;\n\tconst cost = usage.cost as Partial<Usage[\"cost\"]> | undefined;\n\treturn (\n\t\ttypeof usage.input === \"number\" &&\n\t\ttypeof usage.output === \"number\" &&\n\t\ttypeof usage.cacheRead === \"number\" &&\n\t\ttypeof usage.cacheWrite === \"number\" &&\n\t\ttypeof usage.totalTokens === \"number\" &&\n\t\t!!cost &&\n\t\ttypeof cost.input === \"number\" &&\n\t\ttypeof cost.output === \"number\" &&\n\t\ttypeof cost.cacheRead === \"number\" &&\n\t\ttypeof cost.cacheWrite === \"number\" &&\n\t\ttypeof cost.total === \"number\"\n\t);\n}\n\nexport function readAutoLearnSessionIdFromFile(filePath: string): string | undefined {\n\tlet fd: number | undefined;\n\ttry {\n\t\tfd = fs.openSync(filePath, \"r\");\n\t\tconst buffer = Buffer.alloc(64 * 1024);\n\t\tconst bytesRead = fs.readSync(fd, buffer, 0, buffer.length, 0);\n\t\tconst firstLine = buffer.toString(\"utf8\", 0, bytesRead).split(\"\\n\", 1)[0]?.trim();\n\t\tif (!firstLine) return undefined;\n\t\tconst header = JSON.parse(firstLine) as Record<string, unknown>;\n\t\treturn header.type === \"session\" && typeof header.id === \"string\" ? header.id : undefined;\n\t} catch {\n\t\treturn undefined;\n\t} finally {\n\t\tif (fd !== undefined) {\n\t\t\ttry {\n\t\t\t\tfs.closeSync(fd);\n\t\t\t} catch {\n\t\t\t\t// Ignore close errors\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport function findChildSessionFile(sessionDir: string, sessionId: string): string | undefined {\n\tif (!fs.existsSync(sessionDir)) return undefined;\n\n\tconst jsonlFiles: string[] = [];\n\n\tfunction collectJsonlFiles(dirPath: string) {\n\t\tlet currentEntries: fs.Dirent[];\n\t\ttry {\n\t\t\tcurrentEntries = fs.readdirSync(dirPath, { withFileTypes: true });\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t\tfor (const entry of currentEntries) {\n\t\t\tconst fullPath = join(dirPath, entry.name);\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tcollectJsonlFiles(fullPath);\n\t\t\t} else if (entry.isFile() && entry.name.endsWith(\".jsonl\")) {\n\t\t\t\tjsonlFiles.push(fullPath);\n\t\t\t}\n\t\t}\n\t}\n\n\tcollectJsonlFiles(sessionDir);\n\n\tfor (const file of jsonlFiles) {\n\t\tconst base = basename(file);\n\t\tif (base === `${sessionId}.jsonl` || base.endsWith(`_${sessionId}.jsonl`)) {\n\t\t\treturn file;\n\t\t}\n\t}\n\n\tfor (const file of jsonlFiles) {\n\t\tconst headerId = readAutoLearnSessionIdFromFile(file);\n\t\tif (headerId === sessionId) {\n\t\t\treturn file;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nexport function aggregateCumulativeUsageFromSessionEntries(entries: SessionEntry[]): Usage {\n\tlet input = 0;\n\tlet output = 0;\n\tlet cacheRead = 0;\n\tlet cacheWrite = 0;\n\tlet totalTokens = 0;\n\tlet costInput = 0;\n\tlet costOutput = 0;\n\tlet costCacheRead = 0;\n\tlet costCacheWrite = 0;\n\tlet costTotal = 0;\n\n\tconst add = (usage: Usage) => {\n\t\tinput += usage.input;\n\t\toutput += usage.output;\n\t\tcacheRead += usage.cacheRead;\n\t\tcacheWrite += usage.cacheWrite;\n\t\ttotalTokens += usage.totalTokens;\n\t\tcostInput += usage.cost.input;\n\t\tcostOutput += usage.cost.output;\n\t\tcostCacheRead += usage.cost.cacheRead;\n\t\tcostCacheWrite += usage.cost.cacheWrite;\n\t\tcostTotal += usage.cost.total;\n\t};\n\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tconst usage = (entry.message as AssistantMessage).usage;\n\t\t\tif (usage && isUsage(usage)) {\n\t\t\t\tadd(usage);\n\t\t\t}\n\t\t} else if (entry.type === \"custom\" && entry.customType === SPAWNED_USAGE_CUSTOM_TYPE) {\n\t\t\tconst data = entry.data as SpawnedUsageReport | undefined;\n\t\t\tif (data?.usage && isUsage(data.usage)) {\n\t\t\t\tadd(data.usage);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tinput,\n\t\toutput,\n\t\tcacheRead,\n\t\tcacheWrite,\n\t\ttotalTokens,\n\t\tcost: {\n\t\t\tinput: costInput,\n\t\t\toutput: costOutput,\n\t\t\tcacheRead: costCacheRead,\n\t\t\tcacheWrite: costCacheWrite,\n\t\t\ttotal: costTotal,\n\t\t},\n\t};\n}\n\nexport function reportCompletedAutoLearnUsageHelper(args: {\n\trunId: string;\n\tsessionDir: string;\n\tsessionId: string;\n\tlogPath?: string;\n\tparentSession: {\n\t\taddSpawnedUsage: (\n\t\t\tusage: Usage,\n\t\t\topts: { label: string; sourceSessionId: string; reportId: string },\n\t\t) => string | undefined;\n\t};\n\tappendLog?: (logPath: string, message: string) => void;\n}): void {\n\tconst { runId, sessionDir, sessionId, logPath, parentSession, appendLog } = args;\n\tconst sessionFile = findChildSessionFile(sessionDir, sessionId);\n\tif (!sessionFile) {\n\t\tif (logPath && appendLog) {\n\t\t\tappendLog(logPath, `Auto Learn usage report skipped: no child session file found for ${sessionId}.`);\n\t\t}\n\t\treturn;\n\t}\n\tconst fileEntries = loadEntriesFromFile(sessionFile);\n\tconst sessionEntries = fileEntries.filter((entry): entry is SessionEntry => entry.type !== \"session\");\n\tconst usage = aggregateCumulativeUsageFromSessionEntries(sessionEntries);\n\tif (usage.cost.total === 0 && usage.totalTokens === 0) {\n\t\tif (logPath && appendLog) {\n\t\t\tappendLog(logPath, `Auto Learn usage report skipped: child session had no usage for ${sessionId}.`);\n\t\t}\n\t\treturn;\n\t}\n\tparentSession.addSpawnedUsage(usage, {\n\t\tlabel: \"auto-learn\",\n\t\tsourceSessionId: sessionId,\n\t\treportId: `auto-learn:${runId}:${sessionId}`,\n\t});\n\tif (logPath && appendLog) {\n\t\tappendLog(logPath, `Auto Learn usage reported: ${sessionId}.`);\n\t}\n}\n"]}