@bastani/atomic 0.9.8 → 0.9.9-alpha.1

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 (348) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/builtin/cursor/CHANGELOG.md +6 -0
  3. package/dist/builtin/cursor/package.json +2 -2
  4. package/dist/builtin/intercom/CHANGELOG.md +6 -0
  5. package/dist/builtin/intercom/package.json +1 -1
  6. package/dist/builtin/mcp/CHANGELOG.md +6 -0
  7. package/dist/builtin/mcp/package.json +1 -1
  8. package/dist/builtin/subagents/CHANGELOG.md +6 -0
  9. package/dist/builtin/subagents/package.json +1 -1
  10. package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +2 -0
  11. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +7 -1
  12. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +2 -0
  13. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +8 -2
  14. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +2 -0
  15. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +2 -0
  16. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +2 -1
  17. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +2 -0
  18. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +2 -0
  19. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +2 -0
  20. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +2 -0
  21. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +6 -0
  22. package/dist/builtin/subagents/src/shared/types-config.ts +4 -0
  23. package/dist/builtin/subagents/src/shared/types-depth.ts +29 -2
  24. package/dist/builtin/web-access/CHANGELOG.md +6 -0
  25. package/dist/builtin/web-access/package.json +1 -1
  26. package/dist/builtin/workflows/CHANGELOG.md +22 -0
  27. package/dist/builtin/workflows/README.md +17 -8
  28. package/dist/builtin/workflows/builtin/goal-prompts.ts +8 -2
  29. package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +26 -9
  30. package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +1 -1
  31. package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +8 -3
  32. package/dist/builtin/workflows/builtin/ralph-runner.ts +2 -0
  33. package/dist/builtin/workflows/builtin/shared-prompts.ts +24 -1
  34. package/dist/builtin/workflows/package.json +1 -1
  35. package/dist/builtin/workflows/src/durable/backend.ts +53 -15
  36. package/dist/builtin/workflows/src/durable/completed-catalog.ts +245 -0
  37. package/dist/builtin/workflows/src/durable/completed-inspection.ts +213 -0
  38. package/dist/builtin/workflows/src/durable/dbos-backend.ts +120 -170
  39. package/dist/builtin/workflows/src/durable/dbos-envelope.ts +84 -8
  40. package/dist/builtin/workflows/src/durable/dbos-metadata.ts +98 -0
  41. package/dist/builtin/workflows/src/durable/dbos-tombstone.ts +27 -0
  42. package/dist/builtin/workflows/src/durable/factory.ts +1 -1
  43. package/dist/builtin/workflows/src/durable/file-backend.ts +247 -241
  44. package/dist/builtin/workflows/src/durable/file-lock.ts +153 -0
  45. package/dist/builtin/workflows/src/durable/file-state.ts +104 -0
  46. package/dist/builtin/workflows/src/durable/format-version.ts +12 -0
  47. package/dist/builtin/workflows/src/durable/index.ts +12 -0
  48. package/dist/builtin/workflows/src/durable/resume-catalog.ts +16 -27
  49. package/dist/builtin/workflows/src/durable/resume-eligibility.ts +20 -0
  50. package/dist/builtin/workflows/src/durable/resume-runtime.ts +29 -29
  51. package/dist/builtin/workflows/src/durable/scoped-backend.ts +20 -3
  52. package/dist/builtin/workflows/src/durable/stage-primitive.ts +29 -8
  53. package/dist/builtin/workflows/src/durable/types.ts +3 -0
  54. package/dist/builtin/workflows/src/engine/primitives/task.ts +1 -0
  55. package/dist/builtin/workflows/src/engine/run.ts +14 -14
  56. package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +39 -9
  57. package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +10 -0
  58. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +133 -0
  59. package/dist/builtin/workflows/src/extension/runtime.ts +15 -40
  60. package/dist/builtin/workflows/src/extension/wiring.ts +9 -6
  61. package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +226 -0
  62. package/dist/builtin/workflows/src/extension/workflow-prompts.ts +1 -0
  63. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +66 -112
  64. package/dist/builtin/workflows/src/extension/workflow-schema.ts +5 -5
  65. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +16 -1
  66. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +50 -43
  67. package/dist/builtin/workflows/src/runs/foreground/executor-direct-output.ts +91 -0
  68. package/dist/builtin/workflows/src/runs/foreground/executor-direct.ts +95 -46
  69. package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +3 -1
  70. package/dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts +1 -1
  71. package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +3 -0
  72. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +1 -1
  73. package/dist/builtin/workflows/src/runs/foreground/stage-runner-options.ts +36 -7
  74. package/dist/builtin/workflows/src/runs/shared/worktree-cache-lifecycle.ts +25 -0
  75. package/dist/builtin/workflows/src/runs/shared/worktree-cwd.ts +103 -0
  76. package/dist/builtin/workflows/src/runs/shared/worktree-generation.ts +57 -0
  77. package/dist/builtin/workflows/src/runs/shared/worktree-git.ts +134 -8
  78. package/dist/builtin/workflows/src/runs/shared/worktree.ts +2 -0
  79. package/dist/builtin/workflows/src/shared/resumable-workflow-notices.ts +43 -0
  80. package/dist/builtin/workflows/src/shared/timing.ts +4 -0
  81. package/dist/builtin/workflows/src/shared/types.ts +5 -3
  82. package/dist/builtin/workflows/src/tui/graph-view-constants.ts +1 -0
  83. package/dist/builtin/workflows/src/tui/graph-view-input.ts +24 -14
  84. package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +43 -13
  85. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  86. package/dist/core/agent-session-auto-compaction.js +5 -7
  87. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  88. package/dist/core/agent-session-compaction.d.ts +6 -34
  89. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  90. package/dist/core/agent-session-compaction.js +95 -233
  91. package/dist/core/agent-session-compaction.js.map +1 -1
  92. package/dist/core/agent-session-message-queue.d.ts +0 -4
  93. package/dist/core/agent-session-message-queue.d.ts.map +1 -1
  94. package/dist/core/agent-session-message-queue.js +1 -5
  95. package/dist/core/agent-session-message-queue.js.map +1 -1
  96. package/dist/core/agent-session-methods.d.ts +5 -6
  97. package/dist/core/agent-session-methods.d.ts.map +1 -1
  98. package/dist/core/agent-session-methods.js.map +1 -1
  99. package/dist/core/agent-session-types.d.ts +2 -12
  100. package/dist/core/agent-session-types.d.ts.map +1 -1
  101. package/dist/core/agent-session-types.js.map +1 -1
  102. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  103. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  104. package/dist/core/compaction/branch-summarization.js +1 -2
  105. package/dist/core/compaction/branch-summarization.js.map +1 -1
  106. package/dist/core/compaction/compaction-boundary.d.ts +9 -0
  107. package/dist/core/compaction/compaction-boundary.d.ts.map +1 -0
  108. package/dist/core/compaction/compaction-boundary.js +115 -0
  109. package/dist/core/compaction/compaction-boundary.js.map +1 -0
  110. package/dist/core/compaction/compaction-parameters.d.ts +5 -0
  111. package/dist/core/compaction/compaction-parameters.d.ts.map +1 -0
  112. package/dist/core/compaction/compaction-parameters.js +27 -0
  113. package/dist/core/compaction/compaction-parameters.js.map +1 -0
  114. package/dist/core/compaction/compaction-runner.d.ts +14 -0
  115. package/dist/core/compaction/compaction-runner.d.ts.map +1 -0
  116. package/dist/core/compaction/compaction-runner.js +29 -0
  117. package/dist/core/compaction/compaction-runner.js.map +1 -0
  118. package/dist/core/compaction/compaction-types.d.ts +79 -0
  119. package/dist/core/compaction/compaction-types.d.ts.map +1 -0
  120. package/dist/core/compaction/compaction-types.js +6 -0
  121. package/dist/core/compaction/compaction-types.js.map +1 -0
  122. package/dist/core/compaction/deleted-ranges.d.ts +6 -0
  123. package/dist/core/compaction/deleted-ranges.d.ts.map +1 -0
  124. package/dist/core/compaction/deleted-ranges.js +134 -0
  125. package/dist/core/compaction/deleted-ranges.js.map +1 -0
  126. package/dist/core/compaction/index.d.ts +7 -1
  127. package/dist/core/compaction/index.d.ts.map +1 -1
  128. package/dist/core/compaction/index.js +7 -1
  129. package/dist/core/compaction/index.js.map +1 -1
  130. package/dist/core/compaction/range-planner.d.ts +21 -0
  131. package/dist/core/compaction/range-planner.d.ts.map +1 -0
  132. package/dist/core/compaction/range-planner.js +145 -0
  133. package/dist/core/compaction/range-planner.js.map +1 -0
  134. package/dist/core/compaction/transcript-serialization.d.ts +11 -0
  135. package/dist/core/compaction/transcript-serialization.d.ts.map +1 -0
  136. package/dist/core/compaction/transcript-serialization.js +104 -0
  137. package/dist/core/compaction/transcript-serialization.js.map +1 -0
  138. package/dist/core/extensions/context-types.d.ts +2 -2
  139. package/dist/core/extensions/context-types.d.ts.map +1 -1
  140. package/dist/core/extensions/context-types.js.map +1 -1
  141. package/dist/core/extensions/event-results.d.ts +2 -2
  142. package/dist/core/extensions/event-results.d.ts.map +1 -1
  143. package/dist/core/extensions/event-results.js.map +1 -1
  144. package/dist/core/extensions/session-events.d.ts +7 -7
  145. package/dist/core/extensions/session-events.d.ts.map +1 -1
  146. package/dist/core/extensions/session-events.js.map +1 -1
  147. package/dist/core/index.d.ts +1 -1
  148. package/dist/core/index.d.ts.map +1 -1
  149. package/dist/core/index.js.map +1 -1
  150. package/dist/core/messages.d.ts +4 -0
  151. package/dist/core/messages.d.ts.map +1 -1
  152. package/dist/core/messages.js +11 -0
  153. package/dist/core/messages.js.map +1 -1
  154. package/dist/core/provider-context-usage.d.ts.map +1 -1
  155. package/dist/core/provider-context-usage.js +1 -2
  156. package/dist/core/provider-context-usage.js.map +1 -1
  157. package/dist/core/session-manager-archive.d.ts +2 -1
  158. package/dist/core/session-manager-archive.d.ts.map +1 -1
  159. package/dist/core/session-manager-archive.js +2 -2
  160. package/dist/core/session-manager-archive.js.map +1 -1
  161. package/dist/core/session-manager-classification.d.ts +9 -0
  162. package/dist/core/session-manager-classification.d.ts.map +1 -0
  163. package/dist/core/session-manager-classification.js +37 -0
  164. package/dist/core/session-manager-classification.js.map +1 -0
  165. package/dist/core/session-manager-core.d.ts +4 -4
  166. package/dist/core/session-manager-core.d.ts.map +1 -1
  167. package/dist/core/session-manager-core.js +13 -8
  168. package/dist/core/session-manager-core.js.map +1 -1
  169. package/dist/core/session-manager-entries.d.ts +4 -3
  170. package/dist/core/session-manager-entries.d.ts.map +1 -1
  171. package/dist/core/session-manager-entries.js +12 -10
  172. package/dist/core/session-manager-entries.js.map +1 -1
  173. package/dist/core/session-manager-history.d.ts +6 -23
  174. package/dist/core/session-manager-history.d.ts.map +1 -1
  175. package/dist/core/session-manager-history.js +23 -256
  176. package/dist/core/session-manager-history.js.map +1 -1
  177. package/dist/core/session-manager-list.d.ts.map +1 -1
  178. package/dist/core/session-manager-list.js +3 -3
  179. package/dist/core/session-manager-list.js.map +1 -1
  180. package/dist/core/session-manager-storage.d.ts +1 -1
  181. package/dist/core/session-manager-storage.d.ts.map +1 -1
  182. package/dist/core/session-manager-storage.js +3 -2
  183. package/dist/core/session-manager-storage.js.map +1 -1
  184. package/dist/core/session-manager-types.d.ts +14 -15
  185. package/dist/core/session-manager-types.d.ts.map +1 -1
  186. package/dist/core/session-manager-types.js.map +1 -1
  187. package/dist/core/session-manager.d.ts +3 -2
  188. package/dist/core/session-manager.d.ts.map +1 -1
  189. package/dist/core/session-manager.js +1 -1
  190. package/dist/core/session-manager.js.map +1 -1
  191. package/dist/core/slash-commands.d.ts.map +1 -1
  192. package/dist/core/slash-commands.js +1 -1
  193. package/dist/core/slash-commands.js.map +1 -1
  194. package/dist/index.d.ts +3 -2
  195. package/dist/index.d.ts.map +1 -1
  196. package/dist/index.js +2 -1
  197. package/dist/index.js.map +1 -1
  198. package/dist/main-session.d.ts +1 -0
  199. package/dist/main-session.d.ts.map +1 -1
  200. package/dist/main-session.js +7 -0
  201. package/dist/main-session.js.map +1 -1
  202. package/dist/main.d.ts.map +1 -1
  203. package/dist/main.js +2 -2
  204. package/dist/main.js.map +1 -1
  205. package/dist/modes/interactive/components/chat-message-renderer.d.ts +4 -1
  206. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  207. package/dist/modes/interactive/components/chat-message-renderer.js +12 -22
  208. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  209. package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
  210. package/dist/modes/interactive/components/chat-session-host-events.js +5 -11
  211. package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
  212. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
  213. package/dist/modes/interactive/components/chat-session-host-rendering.js +3 -0
  214. package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
  215. package/dist/modes/interactive/components/chat-session-host-state.d.ts +1 -0
  216. package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
  217. package/dist/modes/interactive/components/chat-session-host-state.js +1 -0
  218. package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
  219. package/dist/modes/interactive/components/chat-session-host-utils.d.ts.map +1 -1
  220. package/dist/modes/interactive/components/chat-session-host-utils.js +1 -1
  221. package/dist/modes/interactive/components/chat-session-host-utils.js.map +1 -1
  222. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  223. package/dist/modes/interactive/components/chat-session-host.js +1 -0
  224. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  225. package/dist/modes/interactive/components/compaction-boundary-message.d.ts +20 -0
  226. package/dist/modes/interactive/components/compaction-boundary-message.d.ts.map +1 -0
  227. package/dist/modes/interactive/components/compaction-boundary-message.js +48 -0
  228. package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -0
  229. package/dist/modes/interactive/components/index.d.ts +1 -1
  230. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  231. package/dist/modes/interactive/components/index.js +1 -1
  232. package/dist/modes/interactive/components/index.js.map +1 -1
  233. package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -1
  234. package/dist/modes/interactive/components/session-selector-list.js +3 -0
  235. package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
  236. package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
  237. package/dist/modes/interactive/interactive-agent-events.js +3 -47
  238. package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
  239. package/dist/modes/interactive/interactive-mode-deps.d.ts +2 -2
  240. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  241. package/dist/modes/interactive/interactive-mode-deps.js +1 -1
  242. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  243. package/dist/modes/interactive/interactive-mode-surface.d.ts +5 -3
  244. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  245. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  246. package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -1
  247. package/dist/modes/interactive/interactive-render-chat.js +21 -12
  248. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  249. package/dist/modes/rpc/rpc-client.d.ts +3 -5
  250. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  251. package/dist/modes/rpc/rpc-client.js +1 -6
  252. package/dist/modes/rpc/rpc-client.js.map +1 -1
  253. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  254. package/dist/modes/rpc/rpc-command-handler.js +0 -4
  255. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  256. package/dist/modes/rpc/rpc-types.d.ts +2 -11
  257. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  258. package/dist/modes/rpc/rpc-types.js.map +1 -1
  259. package/docs/compaction.md +97 -772
  260. package/docs/extensions.md +25 -29
  261. package/docs/json.md +2 -2
  262. package/docs/rpc.md +32 -24
  263. package/docs/sdk.md +3 -3
  264. package/docs/session-format.md +49 -30
  265. package/docs/sessions.md +5 -3
  266. package/docs/settings.md +14 -4
  267. package/docs/usage.md +1 -1
  268. package/docs/workflows.md +30 -15
  269. package/examples/extensions/custom-compaction.ts +14 -58
  270. package/examples/extensions/handoff.ts +2 -3
  271. package/npm-shrinkwrap.json +23 -23
  272. package/package.json +2 -2
  273. package/dist/core/compaction/context-assistant-turns.d.ts +0 -42
  274. package/dist/core/compaction/context-assistant-turns.d.ts.map +0 -1
  275. package/dist/core/compaction/context-assistant-turns.js +0 -87
  276. package/dist/core/compaction/context-assistant-turns.js.map +0 -1
  277. package/dist/core/compaction/context-compaction-critical.d.ts +0 -15
  278. package/dist/core/compaction/context-compaction-critical.d.ts.map +0 -1
  279. package/dist/core/compaction/context-compaction-critical.js +0 -57
  280. package/dist/core/compaction/context-compaction-critical.js.map +0 -1
  281. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts +0 -18
  282. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts.map +0 -1
  283. package/dist/core/compaction/context-compaction-eviction-alternates.js +0 -186
  284. package/dist/core/compaction/context-compaction-eviction-alternates.js.map +0 -1
  285. package/dist/core/compaction/context-compaction-eviction.d.ts +0 -12
  286. package/dist/core/compaction/context-compaction-eviction.d.ts.map +0 -1
  287. package/dist/core/compaction/context-compaction-eviction.js +0 -222
  288. package/dist/core/compaction/context-compaction-eviction.js.map +0 -1
  289. package/dist/core/compaction/context-compaction-metrics.d.ts +0 -28
  290. package/dist/core/compaction/context-compaction-metrics.d.ts.map +0 -1
  291. package/dist/core/compaction/context-compaction-metrics.js +0 -107
  292. package/dist/core/compaction/context-compaction-metrics.js.map +0 -1
  293. package/dist/core/compaction/context-compaction-prompt.d.ts +0 -9
  294. package/dist/core/compaction/context-compaction-prompt.d.ts.map +0 -1
  295. package/dist/core/compaction/context-compaction-prompt.js +0 -163
  296. package/dist/core/compaction/context-compaction-prompt.js.map +0 -1
  297. package/dist/core/compaction/context-compaction-runner.d.ts +0 -11
  298. package/dist/core/compaction/context-compaction-runner.d.ts.map +0 -1
  299. package/dist/core/compaction/context-compaction-runner.js +0 -273
  300. package/dist/core/compaction/context-compaction-runner.js.map +0 -1
  301. package/dist/core/compaction/context-compaction-strategy.d.ts +0 -5
  302. package/dist/core/compaction/context-compaction-strategy.d.ts.map +0 -1
  303. package/dist/core/compaction/context-compaction-strategy.js +0 -27
  304. package/dist/core/compaction/context-compaction-strategy.js.map +0 -1
  305. package/dist/core/compaction/context-compaction-types.d.ts +0 -75
  306. package/dist/core/compaction/context-compaction-types.d.ts.map +0 -1
  307. package/dist/core/compaction/context-compaction-types.js +0 -6
  308. package/dist/core/compaction/context-compaction-types.js.map +0 -1
  309. package/dist/core/compaction/context-compaction.d.ts +0 -10
  310. package/dist/core/compaction/context-compaction.d.ts.map +0 -1
  311. package/dist/core/compaction/context-compaction.js +0 -8
  312. package/dist/core/compaction/context-compaction.js.map +0 -1
  313. package/dist/core/compaction/context-deletion-application.d.ts +0 -14
  314. package/dist/core/compaction/context-deletion-application.d.ts.map +0 -1
  315. package/dist/core/compaction/context-deletion-application.js +0 -261
  316. package/dist/core/compaction/context-deletion-application.js.map +0 -1
  317. package/dist/core/compaction/context-deletion-store.d.ts +0 -78
  318. package/dist/core/compaction/context-deletion-store.d.ts.map +0 -1
  319. package/dist/core/compaction/context-deletion-store.js +0 -162
  320. package/dist/core/compaction/context-deletion-store.js.map +0 -1
  321. package/dist/core/compaction/context-deletion-targets.d.ts +0 -43
  322. package/dist/core/compaction/context-deletion-targets.d.ts.map +0 -1
  323. package/dist/core/compaction/context-deletion-targets.js +0 -292
  324. package/dist/core/compaction/context-deletion-targets.js.map +0 -1
  325. package/dist/core/compaction/context-deletion-tool-definitions.d.ts +0 -193
  326. package/dist/core/compaction/context-deletion-tool-definitions.d.ts.map +0 -1
  327. package/dist/core/compaction/context-deletion-tool-definitions.js +0 -98
  328. package/dist/core/compaction/context-deletion-tool-definitions.js.map +0 -1
  329. package/dist/core/compaction/context-deletion-tool-helpers.d.ts +0 -19
  330. package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +0 -1
  331. package/dist/core/compaction/context-deletion-tool-helpers.js +0 -210
  332. package/dist/core/compaction/context-deletion-tool-helpers.js.map +0 -1
  333. package/dist/core/compaction/context-deletion-tools.d.ts +0 -4
  334. package/dist/core/compaction/context-deletion-tools.d.ts.map +0 -1
  335. package/dist/core/compaction/context-deletion-tools.js +0 -403
  336. package/dist/core/compaction/context-deletion-tools.js.map +0 -1
  337. package/dist/core/compaction/context-transcript-analysis.d.ts +0 -11
  338. package/dist/core/compaction/context-transcript-analysis.d.ts.map +0 -1
  339. package/dist/core/compaction/context-transcript-analysis.js +0 -228
  340. package/dist/core/compaction/context-transcript-analysis.js.map +0 -1
  341. package/dist/core/session-manager-tool-dependencies.d.ts +0 -10
  342. package/dist/core/session-manager-tool-dependencies.d.ts.map +0 -1
  343. package/dist/core/session-manager-tool-dependencies.js +0 -133
  344. package/dist/core/session-manager-tool-dependencies.js.map +0 -1
  345. package/dist/modes/interactive/components/context-compaction-summary-message.d.ts +0 -17
  346. package/dist/modes/interactive/components/context-compaction-summary-message.d.ts.map +0 -1
  347. package/dist/modes/interactive/components/context-compaction-summary-message.js +0 -83
  348. package/dist/modes/interactive/components/context-compaction-summary-message.js.map +0 -1
@@ -1,98 +0,0 @@
1
- import { StringEnum } from "@earendil-works/pi-ai/compat";
2
- import { Type } from "typebox";
3
- export const CONTEXT_DELETE_TOOL_NAME = "context_delete";
4
- export const CONTEXT_GREP_DELETE_TOOL_NAME = "context_grep_delete";
5
- export const CONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME = "context_search_transcript";
6
- export const CONTEXT_READ_ENTRY_TOOL_NAME = "context_read_entry";
7
- export const CONTEXT_COMPACTION_BUDGET_TOOL_NAME = "context_compaction_budget";
8
- export const CONTEXT_GREP_DELETE_DEFAULT_MAX_MATCHES = 50;
9
- export const CONTEXT_GREP_DELETE_MAX_REGEX_PATTERN_CHARS = 512;
10
- export const CONTEXT_GREP_DELETE_MAX_REGEX_SCAN_CHARS = 250_000;
11
- export const CONTEXT_READ_ENTRY_DEFAULT_MAX_CHARS = 4000;
12
- export const CONTEXT_READ_ENTRY_MAX_CHARS = 12_000;
13
- export const CONTEXT_SEARCH_DEFAULT_MAX_MATCHES = 20;
14
- export const CONTEXT_SEARCH_MAX_MATCHES = 100;
15
- export const CONTEXT_SEARCH_DEFAULT_CONTEXT_CHARS = 160;
16
- export const CONTEXT_SEARCH_MAX_CONTEXT_CHARS = 500;
17
- export const ContextDeleteToolParameters = Type.Object({
18
- deletions: Type.Array(Type.Object({
19
- kind: StringEnum(["entry", "content_block"], {
20
- description: "Delete an entire transcript entry or a single content block within one entry.",
21
- }),
22
- entryId: Type.String({ minLength: 1, description: "Stable transcript entry id to delete from." }),
23
- blockIndex: Type.Optional(Type.Integer({
24
- minimum: 0,
25
- description: "Required when kind is content_block; omit when kind is entry.",
26
- })),
27
- }, { additionalProperties: false }), {
28
- description: "ID-only deletion targets. Include only kind, entryId, and blockIndex when needed; do not include transcript text, block contents, summaries, or replacement content. Invalid targets are rejected by the tool with correction guidance.",
29
- }),
30
- }, { additionalProperties: false });
31
- export const ContextGrepDeleteToolParameters = Type.Object({
32
- pattern: Type.String({ minLength: 1, description: "Literal text or regular expression to match in transcript text." }),
33
- regex: Type.Optional(Type.Boolean({ description: "Treat pattern as a JavaScript regular expression. Defaults to false." })),
34
- caseSensitive: Type.Optional(Type.Boolean({ description: "Use case-sensitive matching. Defaults to false." })),
35
- target: Type.Optional(StringEnum(["entry", "content_block"], {
36
- description: "Delete whole matching entries or matching content blocks. Defaults to entry.",
37
- })),
38
- maxMatches: Type.Optional(Type.Integer({
39
- minimum: 1,
40
- maximum: 200,
41
- description: "Per-call safety cap. If more not-yet-deleted candidate targets are found in this tool call, no deletions are applied. Defaults to 50. This is not a cumulative compaction cap; call the tool again for additional batches.",
42
- })),
43
- expectedMatchCount: Type.Optional(Type.Integer({
44
- minimum: 0,
45
- description: "Optional safety check. If the match count differs, no deletions are applied.",
46
- })),
47
- }, { additionalProperties: false });
48
- export const ContextSearchTranscriptToolParameters = Type.Object({
49
- pattern: Type.String({ minLength: 1, description: "Literal text or regular expression to search for." }),
50
- regex: Type.Optional(Type.Boolean({ description: "Treat pattern as a JavaScript regular expression. Defaults to false." })),
51
- caseSensitive: Type.Optional(Type.Boolean({ description: "Use case-sensitive matching. Defaults to false." })),
52
- target: Type.Optional(StringEnum(["entry", "content_block"], {
53
- description: "Search whole entry text or individual content-block text. Defaults to entry.",
54
- })),
55
- maxMatches: Type.Optional(Type.Integer({ minimum: 1, maximum: CONTEXT_SEARCH_MAX_MATCHES, description: "Maximum matches to return. Defaults to 20." })),
56
- contextChars: Type.Optional(Type.Integer({
57
- minimum: 0,
58
- maximum: CONTEXT_SEARCH_MAX_CONTEXT_CHARS,
59
- description: "Characters of context to include before and after each match. Defaults to 160.",
60
- })),
61
- }, { additionalProperties: false });
62
- export const ContextReadEntryToolParameters = Type.Object({
63
- entryId: Type.String({ minLength: 1, description: "Stable transcript entry id to read." }),
64
- blockIndex: Type.Optional(Type.Integer({ minimum: 0, description: "Optional content block index to read instead of the whole entry text." })),
65
- offset: Type.Optional(Type.Integer({ minimum: 0, description: "Character offset to begin reading. Defaults to 0." })),
66
- maxChars: Type.Optional(Type.Integer({
67
- minimum: 1,
68
- maximum: CONTEXT_READ_ENTRY_MAX_CHARS,
69
- description: "Maximum characters to return. Defaults to 4000; keep reads small to avoid overflowing context.",
70
- })),
71
- }, { additionalProperties: false });
72
- export const ContextCompactionBudgetToolParameters = Type.Object({}, { additionalProperties: false });
73
- export const CONTEXT_DELETE_TOOL = {
74
- name: CONTEXT_DELETE_TOOL_NAME,
75
- description: "Record context compaction deletion targets directly against the transcript.",
76
- parameters: ContextDeleteToolParameters,
77
- };
78
- export const CONTEXT_GREP_DELETE_TOOL = {
79
- name: CONTEXT_GREP_DELETE_TOOL_NAME,
80
- description: "Bulk-delete transcript entries or content blocks matching a guarded grep/regex query.",
81
- parameters: ContextGrepDeleteToolParameters,
82
- };
83
- export const CONTEXT_SEARCH_TRANSCRIPT_TOOL = {
84
- name: CONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME,
85
- description: "Search the full transcript working copy and return small snippets without mutating deletion state.",
86
- parameters: ContextSearchTranscriptToolParameters,
87
- };
88
- export const CONTEXT_READ_ENTRY_TOOL = {
89
- name: CONTEXT_READ_ENTRY_TOOL_NAME,
90
- description: "Read a small slice of one transcript entry or content block from the full transcript working copy.",
91
- parameters: ContextReadEntryToolParameters,
92
- };
93
- export const CONTEXT_COMPACTION_BUDGET_TOOL = {
94
- name: CONTEXT_COMPACTION_BUDGET_TOOL_NAME,
95
- description: "Report current context-window fullness and reduction progress for the selected deletion targets without mutating deletion state.",
96
- parameters: ContextCompactionBudgetToolParameters,
97
- };
98
- //# sourceMappingURL=context-deletion-tool-definitions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-deletion-tool-definitions.js","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-tool-definitions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { StringEnum } from \"@earendil-works/pi-ai/compat\";\nimport { Type } from \"typebox\";\nimport type { ContextCompactionStats, ContextDeletionTarget } from \"../session-manager.ts\";\nimport type { ContextDeletionRequest, ValidatedContextDeletionResult } from \"./context-compaction-types.ts\";\n\nexport const CONTEXT_DELETE_TOOL_NAME = \"context_delete\";\nexport const CONTEXT_GREP_DELETE_TOOL_NAME = \"context_grep_delete\";\nexport const CONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME = \"context_search_transcript\";\nexport const CONTEXT_READ_ENTRY_TOOL_NAME = \"context_read_entry\";\nexport const CONTEXT_COMPACTION_BUDGET_TOOL_NAME = \"context_compaction_budget\";\nexport const CONTEXT_GREP_DELETE_DEFAULT_MAX_MATCHES = 50;\nexport const CONTEXT_GREP_DELETE_MAX_REGEX_PATTERN_CHARS = 512;\nexport const CONTEXT_GREP_DELETE_MAX_REGEX_SCAN_CHARS = 250_000;\nexport const CONTEXT_READ_ENTRY_DEFAULT_MAX_CHARS = 4000;\nexport const CONTEXT_READ_ENTRY_MAX_CHARS = 12_000;\nexport const CONTEXT_SEARCH_DEFAULT_MAX_MATCHES = 20;\nexport const CONTEXT_SEARCH_MAX_MATCHES = 100;\nexport const CONTEXT_SEARCH_DEFAULT_CONTEXT_CHARS = 160;\nexport const CONTEXT_SEARCH_MAX_CONTEXT_CHARS = 500;\n\n\nexport const ContextDeleteToolParameters = Type.Object(\n\t{\n\t\tdeletions: Type.Array(\n\t\t\tType.Object(\n\t\t\t\t{\n\t\t\t\t\tkind: StringEnum([\"entry\", \"content_block\"] as const, {\n\t\t\t\t\t\tdescription: \"Delete an entire transcript entry or a single content block within one entry.\",\n\t\t\t\t\t}),\n\t\t\t\t\tentryId: Type.String({ minLength: 1, description: \"Stable transcript entry id to delete from.\" }),\n\t\t\t\t\tblockIndex: Type.Optional(\n\t\t\t\t\t\tType.Integer({\n\t\t\t\t\t\t\tminimum: 0,\n\t\t\t\t\t\t\tdescription: \"Required when kind is content_block; omit when kind is entry.\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t\t{ additionalProperties: false },\n\t\t\t),\n\t\t\t{\n\t\t\t\tdescription:\n\t\t\t\t\t\"ID-only deletion targets. Include only kind, entryId, and blockIndex when needed; do not include transcript text, block contents, summaries, or replacement content. Invalid targets are rejected by the tool with correction guidance.\",\n\t\t\t},\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\nexport const ContextGrepDeleteToolParameters = Type.Object(\n\t{\n\t\tpattern: Type.String({ minLength: 1, description: \"Literal text or regular expression to match in transcript text.\" }),\n\t\tregex: Type.Optional(Type.Boolean({ description: \"Treat pattern as a JavaScript regular expression. Defaults to false.\" })),\n\t\tcaseSensitive: Type.Optional(Type.Boolean({ description: \"Use case-sensitive matching. Defaults to false.\" })),\n\t\ttarget: Type.Optional(\n\t\t\tStringEnum([\"entry\", \"content_block\"] as const, {\n\t\t\t\tdescription: \"Delete whole matching entries or matching content blocks. Defaults to entry.\",\n\t\t\t}),\n\t\t),\n\t\tmaxMatches: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tminimum: 1,\n\t\t\t\tmaximum: 200,\n\t\t\t\tdescription:\n\t\t\t\t\t\"Per-call safety cap. If more not-yet-deleted candidate targets are found in this tool call, no deletions are applied. Defaults to 50. This is not a cumulative compaction cap; call the tool again for additional batches.\",\n\t\t\t}),\n\t\t),\n\t\texpectedMatchCount: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tminimum: 0,\n\t\t\t\tdescription: \"Optional safety check. If the match count differs, no deletions are applied.\",\n\t\t\t}),\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\nexport const ContextSearchTranscriptToolParameters = Type.Object(\n\t{\n\t\tpattern: Type.String({ minLength: 1, description: \"Literal text or regular expression to search for.\" }),\n\t\tregex: Type.Optional(Type.Boolean({ description: \"Treat pattern as a JavaScript regular expression. Defaults to false.\" })),\n\t\tcaseSensitive: Type.Optional(Type.Boolean({ description: \"Use case-sensitive matching. Defaults to false.\" })),\n\t\ttarget: Type.Optional(\n\t\t\tStringEnum([\"entry\", \"content_block\"] as const, {\n\t\t\t\tdescription: \"Search whole entry text or individual content-block text. Defaults to entry.\",\n\t\t\t}),\n\t\t),\n\t\tmaxMatches: Type.Optional(\n\t\t\tType.Integer({ minimum: 1, maximum: CONTEXT_SEARCH_MAX_MATCHES, description: \"Maximum matches to return. Defaults to 20.\" }),\n\t\t),\n\t\tcontextChars: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tminimum: 0,\n\t\t\t\tmaximum: CONTEXT_SEARCH_MAX_CONTEXT_CHARS,\n\t\t\t\tdescription: \"Characters of context to include before and after each match. Defaults to 160.\",\n\t\t\t}),\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\nexport const ContextReadEntryToolParameters = Type.Object(\n\t{\n\t\tentryId: Type.String({ minLength: 1, description: \"Stable transcript entry id to read.\" }),\n\t\tblockIndex: Type.Optional(\n\t\t\tType.Integer({ minimum: 0, description: \"Optional content block index to read instead of the whole entry text.\" }),\n\t\t),\n\t\toffset: Type.Optional(Type.Integer({ minimum: 0, description: \"Character offset to begin reading. Defaults to 0.\" })),\n\t\tmaxChars: Type.Optional(\n\t\t\tType.Integer({\n\t\t\t\tminimum: 1,\n\t\t\t\tmaximum: CONTEXT_READ_ENTRY_MAX_CHARS,\n\t\t\t\tdescription: \"Maximum characters to return. Defaults to 4000; keep reads small to avoid overflowing context.\",\n\t\t\t}),\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\nexport const ContextCompactionBudgetToolParameters = Type.Object({}, { additionalProperties: false });\n\nexport const CONTEXT_DELETE_TOOL = {\n\tname: CONTEXT_DELETE_TOOL_NAME,\n\tdescription: \"Record context compaction deletion targets directly against the transcript.\",\n\tparameters: ContextDeleteToolParameters,\n} as const;\n\nexport const CONTEXT_GREP_DELETE_TOOL = {\n\tname: CONTEXT_GREP_DELETE_TOOL_NAME,\n\tdescription: \"Bulk-delete transcript entries or content blocks matching a guarded grep/regex query.\",\n\tparameters: ContextGrepDeleteToolParameters,\n} as const;\n\nexport const CONTEXT_SEARCH_TRANSCRIPT_TOOL = {\n\tname: CONTEXT_SEARCH_TRANSCRIPT_TOOL_NAME,\n\tdescription: \"Search the full transcript working copy and return small snippets without mutating deletion state.\",\n\tparameters: ContextSearchTranscriptToolParameters,\n} as const;\n\nexport const CONTEXT_READ_ENTRY_TOOL = {\n\tname: CONTEXT_READ_ENTRY_TOOL_NAME,\n\tdescription: \"Read a small slice of one transcript entry or content block from the full transcript working copy.\",\n\tparameters: ContextReadEntryToolParameters,\n} as const;\n\nexport const CONTEXT_COMPACTION_BUDGET_TOOL = {\n\tname: CONTEXT_COMPACTION_BUDGET_TOOL_NAME,\n\tdescription:\n\t\t\"Report current context-window fullness and reduction progress for the selected deletion targets without mutating deletion state.\",\n\tparameters: ContextCompactionBudgetToolParameters,\n} as const;\n\nexport interface ContextDeletionToolDetails {\n\tdeletions: ContextDeletionRequest[\"deletions\"];\n\tdeletedTargets: ContextDeletionTarget[];\n\tstats: ContextCompactionStats;\n\tcallCount: number;\n\terror?: string;\n}\n\nexport interface ContextGrepDeletionMatch {\n\tentryId: string;\n\ttarget: \"entry\" | \"content_block\";\n\tblockIndex?: number;\n\ttext: string;\n}\n\nexport interface ContextGrepDeletionSkipped {\n\tentryId?: string;\n\ttarget?: \"entry\" | \"content_block\";\n\tblockIndex?: number;\n\treason:\n\t\t| \"protected_entry\"\n\t\t| \"protected_block\"\n\t\t| \"assistant_thinking_entry\"\n\t\t| \"assistant_thinking_block\"\n\t\t| \"already_deleted\"\n\t\t| \"max_matches_exceeded\"\n\t\t| \"expected_match_count_mismatch\";\n\ttext?: string;\n}\n\nexport interface ContextGrepDeletionToolDetails {\n\tpattern: string;\n\tregex: boolean;\n\tcaseSensitive: boolean;\n\ttarget: \"entry\" | \"content_block\";\n\tmatches: ContextGrepDeletionMatch[];\n\tskipped: ContextGrepDeletionSkipped[];\n\tdeletedTargets: ContextDeletionTarget[];\n\tstats: ContextCompactionStats;\n\tcallCount: number;\n\terror?: string;\n}\n\nexport interface ContextTranscriptSearchMatch {\n\tentryId: string;\n\ttarget: \"entry\" | \"content_block\";\n\tblockIndex?: number;\n\tmatchIndex: number;\n\tsnippet: string;\n\tprotected: boolean;\n}\n\nexport interface ContextTranscriptSearchToolDetails {\n\tpattern: string;\n\tregex: boolean;\n\tcaseSensitive: boolean;\n\ttarget: \"entry\" | \"content_block\";\n\tmatches: ContextTranscriptSearchMatch[];\n\ttruncated: boolean;\n\tcallCount: number;\n\terror?: string;\n}\n\nexport interface ContextReadEntryToolDetails {\n\tentryId: string;\n\tblockIndex?: number;\n\toffset: number;\n\tmaxChars: number;\n\ttotalChars: number;\n\ttext: string;\n\ttruncatedBefore: boolean;\n\ttruncatedAfter: boolean;\n\tcallCount: number;\n\terror?: string;\n}\n\nexport interface ContextCompactionBudgetToolDetails {\n\tcontextWindow?: number;\n\tcompression_ratio: number;\n\ttokensBefore: number;\n\tcurrentTokensAfter: number;\n\tdeletedTokens: number;\n\tcurrentReductionPercent: number;\n\ttargetReductionPercent: number;\n\ttargetTokensAfter: number;\n\ttokensToDeleteForTarget: number;\n\tcontextWindowBeforePercent?: number;\n\tcontextWindowAfterPercent?: number;\n\t/** Total estimated tokens consumed by image content blocks still remaining after selected deletions. */\n\tremainingImageTokens: number;\n\t/** Number of image content blocks still remaining after selected deletions. */\n\timageBlockCount: number;\n\t/** Image tokens as a percentage of the remaining context (post-deletion token total). */\n\timageTokenPercent: number;\n\tcallCount: number;\n}\n\nexport interface ContextDeletionToolController {\n\ttool: AgentTool<typeof ContextDeleteToolParameters, ContextDeletionToolDetails>;\n\tgrepTool: AgentTool<typeof ContextGrepDeleteToolParameters, ContextGrepDeletionToolDetails>;\n\tsearchTool: AgentTool<typeof ContextSearchTranscriptToolParameters, ContextTranscriptSearchToolDetails>;\n\treadEntryTool: AgentTool<typeof ContextReadEntryToolParameters, ContextReadEntryToolDetails>;\n\tbudgetTool: AgentTool<typeof ContextCompactionBudgetToolParameters, ContextCompactionBudgetToolDetails>;\n\ttools: AgentTool[];\n\tgetDeletionRequest(): ContextDeletionRequest;\n\tgetValidatedResult(): ValidatedContextDeletionResult | undefined;\n\tgetLastError(): string | undefined;\n\tgetCallCount(): number;\n}\n"]}
@@ -1,19 +0,0 @@
1
- import type { ContextDeletionTarget } from "../session-manager.ts";
2
- import type { CompactableTranscript } from "./context-compaction-types.ts";
3
- import type { ContextGrepDeletionMatch, ContextGrepDeletionSkipped } from "./context-deletion-tool-definitions.ts";
4
- export declare function escapeRegExpLiteral(text: string): string;
5
- export declare function assertSafeRegexPattern(pattern: string): void;
6
- export declare function createGrepMatcher(pattern: string, regex: boolean, caseSensitive: boolean): RegExp;
7
- export declare function assertSafeRegexScan(scanChars: number): void;
8
- export declare function clampInteger(value: number | undefined, defaultValue: number, minimum: number, maximum: number): number;
9
- export declare function textSlice(text: string, offset: number, maxChars: number): string;
10
- export declare function findMatchIndex(matcher: RegExp, text: string): number;
11
- export declare function snippetForMatch(text: string, matchIndex: number, contextChars: number): string;
12
- export declare function currentTargetDeleted(targets: readonly ContextDeletionTarget[], target: ContextDeletionTarget): boolean;
13
- export declare function addGrepCandidate(candidates: ContextDeletionTarget[], matches: ContextGrepDeletionMatch[], seenTargets: Set<string>, candidate: ContextDeletionTarget, match: ContextGrepDeletionMatch): void;
14
- export declare function pushProtectedGrepSkip(skipped: ContextGrepDeletionSkipped[], match: ContextGrepDeletionMatch): void;
15
- export declare function filterProtectedGrepCandidates(candidates: readonly ContextDeletionTarget[], matches: readonly ContextGrepDeletionMatch[], currentTargets: readonly ContextDeletionTarget[], transcript: CompactableTranscript, skipped: ContextGrepDeletionSkipped[]): {
16
- candidates: ContextDeletionTarget[];
17
- matches: ContextGrepDeletionMatch[];
18
- };
19
- //# sourceMappingURL=context-deletion-tool-helpers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-deletion-tool-helpers.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-tool-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,KAAK,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,wCAAwC,CAAC;AAoBnH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AACD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAkB5D;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,GAAG,MAAM,CAUjG;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAK3D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAGtH;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAIpE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAM9F;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,qBAAqB,EAAE,EAAE,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAKtH;AAED,wBAAgB,gBAAgB,CAC/B,UAAU,EAAE,qBAAqB,EAAE,EACnC,OAAO,EAAE,wBAAwB,EAAE,EACnC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,SAAS,EAAE,qBAAqB,EAChC,KAAK,EAAE,wBAAwB,GAC7B,IAAI,CAMN;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,0BAA0B,EAAE,EAAE,KAAK,EAAE,wBAAwB,GAAG,IAAI,CAQlH;AAoCD,wBAAgB,6BAA6B,CAC5C,UAAU,EAAE,SAAS,qBAAqB,EAAE,EAC5C,OAAO,EAAE,SAAS,wBAAwB,EAAE,EAC5C,cAAc,EAAE,SAAS,qBAAqB,EAAE,EAChD,UAAU,EAAE,qBAAqB,EACjC,OAAO,EAAE,0BAA0B,EAAE,GACnC;IAAE,UAAU,EAAE,qBAAqB,EAAE,CAAC;IAAC,OAAO,EAAE,wBAAwB,EAAE,CAAA;CAAE,CAmG9E","sourcesContent":["import type { ContextDeletionTarget } from \"../session-manager.ts\";\nimport type { CompactableTranscript } from \"./context-compaction-types.ts\";\nimport type { ContextGrepDeletionMatch, ContextGrepDeletionSkipped } from \"./context-deletion-tool-definitions.ts\";\nimport {\n\tCONTEXT_GREP_DELETE_MAX_REGEX_PATTERN_CHARS,\n\tCONTEXT_GREP_DELETE_MAX_REGEX_SCAN_CHARS,\n} from \"./context-deletion-tool-definitions.ts\";\nimport { formatErrorMessage } from \"./context-compaction-metrics.ts\";\nimport { reconcileToolDependencies, validateContextDeletionRequest } from \"./context-deletion-application.ts\";\nimport {\n\tdeletionRequestFromTargets,\n\tgetDeletedContentBlocks,\n\tgetDeletedEntryIds,\n\tmergeContextDeletionTargets,\n\ttargetKey,\n} from \"./context-deletion-targets.ts\";\nimport {\n\tanalyzeCompactableAssistantTurns,\n\tisTranscriptEntryEffectivelyDeleted,\n\ttranscriptEntryStartsNewTurn,\n} from \"./context-assistant-turns.js\";\n\nexport function escapeRegExpLiteral(text: string): string {\n\treturn text.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\nexport function assertSafeRegexPattern(pattern: string): void {\n\tif (pattern.length > CONTEXT_GREP_DELETE_MAX_REGEX_PATTERN_CHARS) {\n\t\tthrow new Error(\n\t\t\t`Regex pattern is too long (${pattern.length} characters); maximum is ${CONTEXT_GREP_DELETE_MAX_REGEX_PATTERN_CHARS}`,\n\t\t);\n\t}\n\n\t// Heuristic ReDoS guard for common catastrophic-backtracking shapes. JavaScript's RegExp engine\n\t// does not expose a timeout, so reject nested quantified groups and backreferences instead of\n\t// relying only on transcript scan-size caps.\n\tconst hasNestedQuantifiedGroup = /\\((?:[^()\\\\]|\\\\.)*[+*](?:[^()\\\\]|\\\\.)*\\)\\s*(?:[+*]|\\{\\d)/u.test(pattern);\n\tconst hasQuantifiedAlternation = /\\((?:[^()\\\\]|\\\\.)*\\|(?:[^()\\\\]|\\\\.)*\\)\\s*(?:[+*]|\\{\\d)/u.test(pattern);\n\tconst hasBackreference = /\\\\[1-9]/u.test(pattern);\n\tif (hasNestedQuantifiedGroup || hasQuantifiedAlternation || hasBackreference) {\n\t\tthrow new Error(\n\t\t\t\"Regex pattern is not allowed because it may cause excessive backtracking; use a literal pattern or exact deletion targets instead.\",\n\t\t);\n\t}\n}\n\nexport function createGrepMatcher(pattern: string, regex: boolean, caseSensitive: boolean): RegExp {\n\tif (regex) {\n\t\tassertSafeRegexPattern(pattern);\n\t}\n\n\ttry {\n\t\treturn new RegExp(regex ? pattern : escapeRegExpLiteral(pattern), caseSensitive ? \"u\" : \"iu\");\n\t} catch (error) {\n\t\tthrow new Error(`Invalid grep ${regex ? \"regex\" : \"pattern\"}: ${formatErrorMessage(error)}`);\n\t}\n}\n\nexport function assertSafeRegexScan(scanChars: number): void {\n\tif (scanChars <= CONTEXT_GREP_DELETE_MAX_REGEX_SCAN_CHARS) return;\n\tthrow new Error(\n\t\t`Regex grep would scan ${scanChars} characters; maximum is ${CONTEXT_GREP_DELETE_MAX_REGEX_SCAN_CHARS}. Use a literal pattern or exact deletion targets instead.`,\n\t);\n}\n\nexport function clampInteger(value: number | undefined, defaultValue: number, minimum: number, maximum: number): number {\n\tif (value === undefined) return defaultValue;\n\treturn Math.max(minimum, Math.min(maximum, value));\n}\n\nexport function textSlice(text: string, offset: number, maxChars: number): string {\n\treturn text.slice(offset, Math.min(text.length, offset + maxChars));\n}\n\nexport function findMatchIndex(matcher: RegExp, text: string): number {\n\tconst match = matcher.exec(text);\n\tmatcher.lastIndex = 0;\n\treturn match?.index ?? -1;\n}\n\nexport function snippetForMatch(text: string, matchIndex: number, contextChars: number): string {\n\tconst start = Math.max(0, matchIndex - contextChars);\n\tconst end = Math.min(text.length, matchIndex + contextChars);\n\tconst prefix = start > 0 ? \"…\" : \"\";\n\tconst suffix = end < text.length ? \"…\" : \"\";\n\treturn `${prefix}${text.slice(start, end)}${suffix}`;\n}\n\nexport function currentTargetDeleted(targets: readonly ContextDeletionTarget[], target: ContextDeletionTarget): boolean {\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tif (deletedEntryIds.has(target.entryId)) return true;\n\tif (target.kind === \"entry\") return false;\n\treturn getDeletedContentBlocks(targets).get(target.entryId)?.has(target.blockIndex) === true;\n}\n\nexport function addGrepCandidate(\n\tcandidates: ContextDeletionTarget[],\n\tmatches: ContextGrepDeletionMatch[],\n\tseenTargets: Set<string>,\n\tcandidate: ContextDeletionTarget,\n\tmatch: ContextGrepDeletionMatch,\n): void {\n\tconst key = targetKey(candidate);\n\tif (seenTargets.has(key)) return;\n\tseenTargets.add(key);\n\tcandidates.push(candidate);\n\tmatches.push(match);\n}\n\nexport function pushProtectedGrepSkip(skipped: ContextGrepDeletionSkipped[], match: ContextGrepDeletionMatch): void {\n\tskipped.push({\n\t\tentryId: match.entryId,\n\t\ttarget: match.target,\n\t\t...(match.blockIndex === undefined ? {} : { blockIndex: match.blockIndex }),\n\t\treason: match.target === \"content_block\" ? \"protected_block\" : \"protected_entry\",\n\t\ttext: match.text,\n\t});\n}\n\nfunction assistantTurnsForTargets(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n) {\n\tconst reconciled = reconcileToolDependencies(transcript, targets);\n\treturn { reconciled, ...analyzeCompactableAssistantTurns(transcript, reconciled) };\n}\n\nfunction candidateRemovesBoundary(\n\ttranscript: CompactableTranscript,\n\tcurrentTargets: readonly ContextDeletionTarget[],\n\tcandidate: ContextDeletionTarget,\n): boolean {\n\tconst entry = transcript.entries.find((item) => item.entryId === candidate.entryId);\n\tif (!entry) return false;\n\tconst beforeEntries = getDeletedEntryIds(currentTargets);\n\tconst beforeBlocks = getDeletedContentBlocks(currentTargets);\n\tconst before =\n\t\t!isTranscriptEntryEffectivelyDeleted(entry, beforeEntries, beforeBlocks) &&\n\t\ttranscriptEntryStartsNewTurn(entry, beforeBlocks.get(entry.entryId));\n\tif (!before) return false;\n\ttry {\n\t\tconst after = assistantTurnsForTargets(transcript, mergeContextDeletionTargets(currentTargets, [candidate]));\n\t\treturn isTranscriptEntryEffectivelyDeleted(entry, after.deletedEntryIds, after.deletedContentBlocks) ||\n\t\t\t!transcriptEntryStartsNewTurn(entry, after.deletedContentBlocks.get(entry.entryId));\n\t} catch {\n\t\treturn true;\n\t}\n}\n\ninterface SemanticCandidate {\n\tindex: number;\n\taffectedTurns: Set<number>;\n}\nexport function filterProtectedGrepCandidates(\n\tcandidates: readonly ContextDeletionTarget[],\n\tmatches: readonly ContextGrepDeletionMatch[],\n\tcurrentTargets: readonly ContextDeletionTarget[],\n\ttranscript: CompactableTranscript,\n\tskipped: ContextGrepDeletionSkipped[],\n): { candidates: ContextDeletionTarget[]; matches: ContextGrepDeletionMatch[] } {\n\tconst rejected = new Set<number>();\n\tconst accepted = new Set<number>();\n\tlet acceptedTargets = [...currentTargets];\n\tconst base = assistantTurnsForTargets(transcript, currentTargets);\n\tconst signedTurnByEntryId = new Map<string, number>();\n\tbase.turns.forEach((turn, turnIndex) => {\n\t\tfor (const entryId of turn.signedThinkingEntryIds) signedTurnByEntryId.set(entryId, turnIndex);\n\t});\n\tconst boundaries: number[] = [];\n\tconst ordinary: number[] = [];\n\tconst semantic: SemanticCandidate[] = [];\n\n\tfor (let index = 0; index < candidates.length; index++) {\n\t\tconst candidate = candidates[index]!;\n\t\tif (candidateRemovesBoundary(transcript, currentTargets, candidate)) {\n\t\t\tboundaries.push(index);\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst single = assistantTurnsForTargets(\n\t\t\t\ttranscript,\n\t\t\t\tmergeContextDeletionTargets(currentTargets, [candidate]),\n\t\t\t);\n\t\t\tconst affectedTurns = new Set<number>();\n\t\t\tfor (const entryId of single.deletedEntryIds) {\n\t\t\t\tif (base.deletedEntryIds.has(entryId)) continue;\n\t\t\t\tconst turnIndex = signedTurnByEntryId.get(entryId);\n\t\t\t\tif (turnIndex !== undefined) affectedTurns.add(turnIndex);\n\t\t\t}\n\t\t\tif (affectedTurns.size === 0) ordinary.push(index);\n\t\t\telse semantic.push({ index, affectedTurns });\n\t\t} catch {\n\t\t\trejected.add(index);\n\t\t}\n\t}\n\n\tconst components: SemanticCandidate[][] = [];\n\tfor (const item of semantic) {\n\t\tconst overlapping = components.filter((component) =>\n\t\t\tcomponent.some((member) => [...member.affectedTurns].some((turn) => item.affectedTurns.has(turn))),\n\t\t);\n\t\tif (overlapping.length === 0) {\n\t\t\tcomponents.push([item]);\n\t\t\tcontinue;\n\t\t}\n\t\tconst merged = [item, ...overlapping.flat()];\n\t\tfor (const component of overlapping) components.splice(components.indexOf(component), 1);\n\t\tcomponents.push(merged.sort((left, right) => left.index - right.index));\n\t}\n\n\tfor (const component of components.sort((left, right) => left[0]!.index - right[0]!.index)) {\n\t\tconst indexes = component.map((item) => item.index);\n\t\tconst proposed = mergeContextDeletionTargets(acceptedTargets, indexes.map((index) => candidates[index]!));\n\t\tlet complete = true;\n\t\ttry {\n\t\t\tconst effect = assistantTurnsForTargets(transcript, proposed);\n\t\t\tconst affectedTurns = new Set(component.flatMap((item) => [...item.affectedTurns]));\n\t\t\tfor (const turnIndex of affectedTurns) {\n\t\t\t\tconst turn = base.turns[turnIndex]!;\n\t\t\t\tif (turn.active || !turn.signedThinkingEntryIds.every((entryId) => effect.deletedEntryIds.has(entryId))) {\n\t\t\t\t\tcomplete = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (complete) validateContextDeletionRequest(deletionRequestFromTargets(proposed), transcript);\n\t\t} catch {\n\t\t\tcomplete = false;\n\t\t}\n\t\tif (!complete) {\n\t\t\tfor (const index of indexes) rejected.add(index);\n\t\t\tcontinue;\n\t\t}\n\t\tacceptedTargets = proposed;\n\t\tfor (const index of indexes) accepted.add(index);\n\t}\n\n\tconst acceptIndividually = (indexes: readonly number[]): void => {\n\t\tfor (const index of indexes) {\n\t\t\tconst proposed = mergeContextDeletionTargets(acceptedTargets, [candidates[index]!]);\n\t\t\ttry {\n\t\t\t\tvalidateContextDeletionRequest(deletionRequestFromTargets(proposed), transcript);\n\t\t\t\tacceptedTargets = proposed;\n\t\t\t\taccepted.add(index);\n\t\t\t} catch {\n\t\t\t\trejected.add(index);\n\t\t\t}\n\t\t}\n\t};\n\tacceptIndividually(ordinary);\n\tacceptIndividually(boundaries);\n\n\tfor (let index = 0; index < matches.length; index++) {\n\t\tif (rejected.has(index)) pushProtectedGrepSkip(skipped, matches[index]!);\n\t}\n\treturn {\n\t\tcandidates: candidates.filter((_candidate, index) => accepted.has(index)),\n\t\tmatches: matches.filter((_match, index) => accepted.has(index)),\n\t};\n}\n"]}
@@ -1,210 +0,0 @@
1
- import { CONTEXT_GREP_DELETE_MAX_REGEX_PATTERN_CHARS, CONTEXT_GREP_DELETE_MAX_REGEX_SCAN_CHARS, } from "./context-deletion-tool-definitions.js";
2
- import { formatErrorMessage } from "./context-compaction-metrics.js";
3
- import { reconcileToolDependencies, validateContextDeletionRequest } from "./context-deletion-application.js";
4
- import { deletionRequestFromTargets, getDeletedContentBlocks, getDeletedEntryIds, mergeContextDeletionTargets, targetKey, } from "./context-deletion-targets.js";
5
- import { analyzeCompactableAssistantTurns, isTranscriptEntryEffectivelyDeleted, transcriptEntryStartsNewTurn, } from "./context-assistant-turns.js";
6
- export function escapeRegExpLiteral(text) {
7
- return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8
- }
9
- export function assertSafeRegexPattern(pattern) {
10
- if (pattern.length > CONTEXT_GREP_DELETE_MAX_REGEX_PATTERN_CHARS) {
11
- throw new Error(`Regex pattern is too long (${pattern.length} characters); maximum is ${CONTEXT_GREP_DELETE_MAX_REGEX_PATTERN_CHARS}`);
12
- }
13
- // Heuristic ReDoS guard for common catastrophic-backtracking shapes. JavaScript's RegExp engine
14
- // does not expose a timeout, so reject nested quantified groups and backreferences instead of
15
- // relying only on transcript scan-size caps.
16
- const hasNestedQuantifiedGroup = /\((?:[^()\\]|\\.)*[+*](?:[^()\\]|\\.)*\)\s*(?:[+*]|\{\d)/u.test(pattern);
17
- const hasQuantifiedAlternation = /\((?:[^()\\]|\\.)*\|(?:[^()\\]|\\.)*\)\s*(?:[+*]|\{\d)/u.test(pattern);
18
- const hasBackreference = /\\[1-9]/u.test(pattern);
19
- if (hasNestedQuantifiedGroup || hasQuantifiedAlternation || hasBackreference) {
20
- throw new Error("Regex pattern is not allowed because it may cause excessive backtracking; use a literal pattern or exact deletion targets instead.");
21
- }
22
- }
23
- export function createGrepMatcher(pattern, regex, caseSensitive) {
24
- if (regex) {
25
- assertSafeRegexPattern(pattern);
26
- }
27
- try {
28
- return new RegExp(regex ? pattern : escapeRegExpLiteral(pattern), caseSensitive ? "u" : "iu");
29
- }
30
- catch (error) {
31
- throw new Error(`Invalid grep ${regex ? "regex" : "pattern"}: ${formatErrorMessage(error)}`);
32
- }
33
- }
34
- export function assertSafeRegexScan(scanChars) {
35
- if (scanChars <= CONTEXT_GREP_DELETE_MAX_REGEX_SCAN_CHARS)
36
- return;
37
- throw new Error(`Regex grep would scan ${scanChars} characters; maximum is ${CONTEXT_GREP_DELETE_MAX_REGEX_SCAN_CHARS}. Use a literal pattern or exact deletion targets instead.`);
38
- }
39
- export function clampInteger(value, defaultValue, minimum, maximum) {
40
- if (value === undefined)
41
- return defaultValue;
42
- return Math.max(minimum, Math.min(maximum, value));
43
- }
44
- export function textSlice(text, offset, maxChars) {
45
- return text.slice(offset, Math.min(text.length, offset + maxChars));
46
- }
47
- export function findMatchIndex(matcher, text) {
48
- const match = matcher.exec(text);
49
- matcher.lastIndex = 0;
50
- return match?.index ?? -1;
51
- }
52
- export function snippetForMatch(text, matchIndex, contextChars) {
53
- const start = Math.max(0, matchIndex - contextChars);
54
- const end = Math.min(text.length, matchIndex + contextChars);
55
- const prefix = start > 0 ? "…" : "";
56
- const suffix = end < text.length ? "…" : "";
57
- return `${prefix}${text.slice(start, end)}${suffix}`;
58
- }
59
- export function currentTargetDeleted(targets, target) {
60
- const deletedEntryIds = getDeletedEntryIds(targets);
61
- if (deletedEntryIds.has(target.entryId))
62
- return true;
63
- if (target.kind === "entry")
64
- return false;
65
- return getDeletedContentBlocks(targets).get(target.entryId)?.has(target.blockIndex) === true;
66
- }
67
- export function addGrepCandidate(candidates, matches, seenTargets, candidate, match) {
68
- const key = targetKey(candidate);
69
- if (seenTargets.has(key))
70
- return;
71
- seenTargets.add(key);
72
- candidates.push(candidate);
73
- matches.push(match);
74
- }
75
- export function pushProtectedGrepSkip(skipped, match) {
76
- skipped.push({
77
- entryId: match.entryId,
78
- target: match.target,
79
- ...(match.blockIndex === undefined ? {} : { blockIndex: match.blockIndex }),
80
- reason: match.target === "content_block" ? "protected_block" : "protected_entry",
81
- text: match.text,
82
- });
83
- }
84
- function assistantTurnsForTargets(transcript, targets) {
85
- const reconciled = reconcileToolDependencies(transcript, targets);
86
- return { reconciled, ...analyzeCompactableAssistantTurns(transcript, reconciled) };
87
- }
88
- function candidateRemovesBoundary(transcript, currentTargets, candidate) {
89
- const entry = transcript.entries.find((item) => item.entryId === candidate.entryId);
90
- if (!entry)
91
- return false;
92
- const beforeEntries = getDeletedEntryIds(currentTargets);
93
- const beforeBlocks = getDeletedContentBlocks(currentTargets);
94
- const before = !isTranscriptEntryEffectivelyDeleted(entry, beforeEntries, beforeBlocks) &&
95
- transcriptEntryStartsNewTurn(entry, beforeBlocks.get(entry.entryId));
96
- if (!before)
97
- return false;
98
- try {
99
- const after = assistantTurnsForTargets(transcript, mergeContextDeletionTargets(currentTargets, [candidate]));
100
- return isTranscriptEntryEffectivelyDeleted(entry, after.deletedEntryIds, after.deletedContentBlocks) ||
101
- !transcriptEntryStartsNewTurn(entry, after.deletedContentBlocks.get(entry.entryId));
102
- }
103
- catch {
104
- return true;
105
- }
106
- }
107
- export function filterProtectedGrepCandidates(candidates, matches, currentTargets, transcript, skipped) {
108
- const rejected = new Set();
109
- const accepted = new Set();
110
- let acceptedTargets = [...currentTargets];
111
- const base = assistantTurnsForTargets(transcript, currentTargets);
112
- const signedTurnByEntryId = new Map();
113
- base.turns.forEach((turn, turnIndex) => {
114
- for (const entryId of turn.signedThinkingEntryIds)
115
- signedTurnByEntryId.set(entryId, turnIndex);
116
- });
117
- const boundaries = [];
118
- const ordinary = [];
119
- const semantic = [];
120
- for (let index = 0; index < candidates.length; index++) {
121
- const candidate = candidates[index];
122
- if (candidateRemovesBoundary(transcript, currentTargets, candidate)) {
123
- boundaries.push(index);
124
- continue;
125
- }
126
- try {
127
- const single = assistantTurnsForTargets(transcript, mergeContextDeletionTargets(currentTargets, [candidate]));
128
- const affectedTurns = new Set();
129
- for (const entryId of single.deletedEntryIds) {
130
- if (base.deletedEntryIds.has(entryId))
131
- continue;
132
- const turnIndex = signedTurnByEntryId.get(entryId);
133
- if (turnIndex !== undefined)
134
- affectedTurns.add(turnIndex);
135
- }
136
- if (affectedTurns.size === 0)
137
- ordinary.push(index);
138
- else
139
- semantic.push({ index, affectedTurns });
140
- }
141
- catch {
142
- rejected.add(index);
143
- }
144
- }
145
- const components = [];
146
- for (const item of semantic) {
147
- const overlapping = components.filter((component) => component.some((member) => [...member.affectedTurns].some((turn) => item.affectedTurns.has(turn))));
148
- if (overlapping.length === 0) {
149
- components.push([item]);
150
- continue;
151
- }
152
- const merged = [item, ...overlapping.flat()];
153
- for (const component of overlapping)
154
- components.splice(components.indexOf(component), 1);
155
- components.push(merged.sort((left, right) => left.index - right.index));
156
- }
157
- for (const component of components.sort((left, right) => left[0].index - right[0].index)) {
158
- const indexes = component.map((item) => item.index);
159
- const proposed = mergeContextDeletionTargets(acceptedTargets, indexes.map((index) => candidates[index]));
160
- let complete = true;
161
- try {
162
- const effect = assistantTurnsForTargets(transcript, proposed);
163
- const affectedTurns = new Set(component.flatMap((item) => [...item.affectedTurns]));
164
- for (const turnIndex of affectedTurns) {
165
- const turn = base.turns[turnIndex];
166
- if (turn.active || !turn.signedThinkingEntryIds.every((entryId) => effect.deletedEntryIds.has(entryId))) {
167
- complete = false;
168
- break;
169
- }
170
- }
171
- if (complete)
172
- validateContextDeletionRequest(deletionRequestFromTargets(proposed), transcript);
173
- }
174
- catch {
175
- complete = false;
176
- }
177
- if (!complete) {
178
- for (const index of indexes)
179
- rejected.add(index);
180
- continue;
181
- }
182
- acceptedTargets = proposed;
183
- for (const index of indexes)
184
- accepted.add(index);
185
- }
186
- const acceptIndividually = (indexes) => {
187
- for (const index of indexes) {
188
- const proposed = mergeContextDeletionTargets(acceptedTargets, [candidates[index]]);
189
- try {
190
- validateContextDeletionRequest(deletionRequestFromTargets(proposed), transcript);
191
- acceptedTargets = proposed;
192
- accepted.add(index);
193
- }
194
- catch {
195
- rejected.add(index);
196
- }
197
- }
198
- };
199
- acceptIndividually(ordinary);
200
- acceptIndividually(boundaries);
201
- for (let index = 0; index < matches.length; index++) {
202
- if (rejected.has(index))
203
- pushProtectedGrepSkip(skipped, matches[index]);
204
- }
205
- return {
206
- candidates: candidates.filter((_candidate, index) => accepted.has(index)),
207
- matches: matches.filter((_match, index) => accepted.has(index)),
208
- };
209
- }
210
- //# sourceMappingURL=context-deletion-tool-helpers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-deletion-tool-helpers.js","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-tool-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextDeletionTarget } from \"../session-manager.ts\";\nimport type { CompactableTranscript } from \"./context-compaction-types.ts\";\nimport type { ContextGrepDeletionMatch, ContextGrepDeletionSkipped } from \"./context-deletion-tool-definitions.ts\";\nimport {\n\tCONTEXT_GREP_DELETE_MAX_REGEX_PATTERN_CHARS,\n\tCONTEXT_GREP_DELETE_MAX_REGEX_SCAN_CHARS,\n} from \"./context-deletion-tool-definitions.ts\";\nimport { formatErrorMessage } from \"./context-compaction-metrics.ts\";\nimport { reconcileToolDependencies, validateContextDeletionRequest } from \"./context-deletion-application.ts\";\nimport {\n\tdeletionRequestFromTargets,\n\tgetDeletedContentBlocks,\n\tgetDeletedEntryIds,\n\tmergeContextDeletionTargets,\n\ttargetKey,\n} from \"./context-deletion-targets.ts\";\nimport {\n\tanalyzeCompactableAssistantTurns,\n\tisTranscriptEntryEffectivelyDeleted,\n\ttranscriptEntryStartsNewTurn,\n} from \"./context-assistant-turns.js\";\n\nexport function escapeRegExpLiteral(text: string): string {\n\treturn text.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\nexport function assertSafeRegexPattern(pattern: string): void {\n\tif (pattern.length > CONTEXT_GREP_DELETE_MAX_REGEX_PATTERN_CHARS) {\n\t\tthrow new Error(\n\t\t\t`Regex pattern is too long (${pattern.length} characters); maximum is ${CONTEXT_GREP_DELETE_MAX_REGEX_PATTERN_CHARS}`,\n\t\t);\n\t}\n\n\t// Heuristic ReDoS guard for common catastrophic-backtracking shapes. JavaScript's RegExp engine\n\t// does not expose a timeout, so reject nested quantified groups and backreferences instead of\n\t// relying only on transcript scan-size caps.\n\tconst hasNestedQuantifiedGroup = /\\((?:[^()\\\\]|\\\\.)*[+*](?:[^()\\\\]|\\\\.)*\\)\\s*(?:[+*]|\\{\\d)/u.test(pattern);\n\tconst hasQuantifiedAlternation = /\\((?:[^()\\\\]|\\\\.)*\\|(?:[^()\\\\]|\\\\.)*\\)\\s*(?:[+*]|\\{\\d)/u.test(pattern);\n\tconst hasBackreference = /\\\\[1-9]/u.test(pattern);\n\tif (hasNestedQuantifiedGroup || hasQuantifiedAlternation || hasBackreference) {\n\t\tthrow new Error(\n\t\t\t\"Regex pattern is not allowed because it may cause excessive backtracking; use a literal pattern or exact deletion targets instead.\",\n\t\t);\n\t}\n}\n\nexport function createGrepMatcher(pattern: string, regex: boolean, caseSensitive: boolean): RegExp {\n\tif (regex) {\n\t\tassertSafeRegexPattern(pattern);\n\t}\n\n\ttry {\n\t\treturn new RegExp(regex ? pattern : escapeRegExpLiteral(pattern), caseSensitive ? \"u\" : \"iu\");\n\t} catch (error) {\n\t\tthrow new Error(`Invalid grep ${regex ? \"regex\" : \"pattern\"}: ${formatErrorMessage(error)}`);\n\t}\n}\n\nexport function assertSafeRegexScan(scanChars: number): void {\n\tif (scanChars <= CONTEXT_GREP_DELETE_MAX_REGEX_SCAN_CHARS) return;\n\tthrow new Error(\n\t\t`Regex grep would scan ${scanChars} characters; maximum is ${CONTEXT_GREP_DELETE_MAX_REGEX_SCAN_CHARS}. Use a literal pattern or exact deletion targets instead.`,\n\t);\n}\n\nexport function clampInteger(value: number | undefined, defaultValue: number, minimum: number, maximum: number): number {\n\tif (value === undefined) return defaultValue;\n\treturn Math.max(minimum, Math.min(maximum, value));\n}\n\nexport function textSlice(text: string, offset: number, maxChars: number): string {\n\treturn text.slice(offset, Math.min(text.length, offset + maxChars));\n}\n\nexport function findMatchIndex(matcher: RegExp, text: string): number {\n\tconst match = matcher.exec(text);\n\tmatcher.lastIndex = 0;\n\treturn match?.index ?? -1;\n}\n\nexport function snippetForMatch(text: string, matchIndex: number, contextChars: number): string {\n\tconst start = Math.max(0, matchIndex - contextChars);\n\tconst end = Math.min(text.length, matchIndex + contextChars);\n\tconst prefix = start > 0 ? \"…\" : \"\";\n\tconst suffix = end < text.length ? \"…\" : \"\";\n\treturn `${prefix}${text.slice(start, end)}${suffix}`;\n}\n\nexport function currentTargetDeleted(targets: readonly ContextDeletionTarget[], target: ContextDeletionTarget): boolean {\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tif (deletedEntryIds.has(target.entryId)) return true;\n\tif (target.kind === \"entry\") return false;\n\treturn getDeletedContentBlocks(targets).get(target.entryId)?.has(target.blockIndex) === true;\n}\n\nexport function addGrepCandidate(\n\tcandidates: ContextDeletionTarget[],\n\tmatches: ContextGrepDeletionMatch[],\n\tseenTargets: Set<string>,\n\tcandidate: ContextDeletionTarget,\n\tmatch: ContextGrepDeletionMatch,\n): void {\n\tconst key = targetKey(candidate);\n\tif (seenTargets.has(key)) return;\n\tseenTargets.add(key);\n\tcandidates.push(candidate);\n\tmatches.push(match);\n}\n\nexport function pushProtectedGrepSkip(skipped: ContextGrepDeletionSkipped[], match: ContextGrepDeletionMatch): void {\n\tskipped.push({\n\t\tentryId: match.entryId,\n\t\ttarget: match.target,\n\t\t...(match.blockIndex === undefined ? {} : { blockIndex: match.blockIndex }),\n\t\treason: match.target === \"content_block\" ? \"protected_block\" : \"protected_entry\",\n\t\ttext: match.text,\n\t});\n}\n\nfunction assistantTurnsForTargets(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n) {\n\tconst reconciled = reconcileToolDependencies(transcript, targets);\n\treturn { reconciled, ...analyzeCompactableAssistantTurns(transcript, reconciled) };\n}\n\nfunction candidateRemovesBoundary(\n\ttranscript: CompactableTranscript,\n\tcurrentTargets: readonly ContextDeletionTarget[],\n\tcandidate: ContextDeletionTarget,\n): boolean {\n\tconst entry = transcript.entries.find((item) => item.entryId === candidate.entryId);\n\tif (!entry) return false;\n\tconst beforeEntries = getDeletedEntryIds(currentTargets);\n\tconst beforeBlocks = getDeletedContentBlocks(currentTargets);\n\tconst before =\n\t\t!isTranscriptEntryEffectivelyDeleted(entry, beforeEntries, beforeBlocks) &&\n\t\ttranscriptEntryStartsNewTurn(entry, beforeBlocks.get(entry.entryId));\n\tif (!before) return false;\n\ttry {\n\t\tconst after = assistantTurnsForTargets(transcript, mergeContextDeletionTargets(currentTargets, [candidate]));\n\t\treturn isTranscriptEntryEffectivelyDeleted(entry, after.deletedEntryIds, after.deletedContentBlocks) ||\n\t\t\t!transcriptEntryStartsNewTurn(entry, after.deletedContentBlocks.get(entry.entryId));\n\t} catch {\n\t\treturn true;\n\t}\n}\n\ninterface SemanticCandidate {\n\tindex: number;\n\taffectedTurns: Set<number>;\n}\nexport function filterProtectedGrepCandidates(\n\tcandidates: readonly ContextDeletionTarget[],\n\tmatches: readonly ContextGrepDeletionMatch[],\n\tcurrentTargets: readonly ContextDeletionTarget[],\n\ttranscript: CompactableTranscript,\n\tskipped: ContextGrepDeletionSkipped[],\n): { candidates: ContextDeletionTarget[]; matches: ContextGrepDeletionMatch[] } {\n\tconst rejected = new Set<number>();\n\tconst accepted = new Set<number>();\n\tlet acceptedTargets = [...currentTargets];\n\tconst base = assistantTurnsForTargets(transcript, currentTargets);\n\tconst signedTurnByEntryId = new Map<string, number>();\n\tbase.turns.forEach((turn, turnIndex) => {\n\t\tfor (const entryId of turn.signedThinkingEntryIds) signedTurnByEntryId.set(entryId, turnIndex);\n\t});\n\tconst boundaries: number[] = [];\n\tconst ordinary: number[] = [];\n\tconst semantic: SemanticCandidate[] = [];\n\n\tfor (let index = 0; index < candidates.length; index++) {\n\t\tconst candidate = candidates[index]!;\n\t\tif (candidateRemovesBoundary(transcript, currentTargets, candidate)) {\n\t\t\tboundaries.push(index);\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst single = assistantTurnsForTargets(\n\t\t\t\ttranscript,\n\t\t\t\tmergeContextDeletionTargets(currentTargets, [candidate]),\n\t\t\t);\n\t\t\tconst affectedTurns = new Set<number>();\n\t\t\tfor (const entryId of single.deletedEntryIds) {\n\t\t\t\tif (base.deletedEntryIds.has(entryId)) continue;\n\t\t\t\tconst turnIndex = signedTurnByEntryId.get(entryId);\n\t\t\t\tif (turnIndex !== undefined) affectedTurns.add(turnIndex);\n\t\t\t}\n\t\t\tif (affectedTurns.size === 0) ordinary.push(index);\n\t\t\telse semantic.push({ index, affectedTurns });\n\t\t} catch {\n\t\t\trejected.add(index);\n\t\t}\n\t}\n\n\tconst components: SemanticCandidate[][] = [];\n\tfor (const item of semantic) {\n\t\tconst overlapping = components.filter((component) =>\n\t\t\tcomponent.some((member) => [...member.affectedTurns].some((turn) => item.affectedTurns.has(turn))),\n\t\t);\n\t\tif (overlapping.length === 0) {\n\t\t\tcomponents.push([item]);\n\t\t\tcontinue;\n\t\t}\n\t\tconst merged = [item, ...overlapping.flat()];\n\t\tfor (const component of overlapping) components.splice(components.indexOf(component), 1);\n\t\tcomponents.push(merged.sort((left, right) => left.index - right.index));\n\t}\n\n\tfor (const component of components.sort((left, right) => left[0]!.index - right[0]!.index)) {\n\t\tconst indexes = component.map((item) => item.index);\n\t\tconst proposed = mergeContextDeletionTargets(acceptedTargets, indexes.map((index) => candidates[index]!));\n\t\tlet complete = true;\n\t\ttry {\n\t\t\tconst effect = assistantTurnsForTargets(transcript, proposed);\n\t\t\tconst affectedTurns = new Set(component.flatMap((item) => [...item.affectedTurns]));\n\t\t\tfor (const turnIndex of affectedTurns) {\n\t\t\t\tconst turn = base.turns[turnIndex]!;\n\t\t\t\tif (turn.active || !turn.signedThinkingEntryIds.every((entryId) => effect.deletedEntryIds.has(entryId))) {\n\t\t\t\t\tcomplete = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (complete) validateContextDeletionRequest(deletionRequestFromTargets(proposed), transcript);\n\t\t} catch {\n\t\t\tcomplete = false;\n\t\t}\n\t\tif (!complete) {\n\t\t\tfor (const index of indexes) rejected.add(index);\n\t\t\tcontinue;\n\t\t}\n\t\tacceptedTargets = proposed;\n\t\tfor (const index of indexes) accepted.add(index);\n\t}\n\n\tconst acceptIndividually = (indexes: readonly number[]): void => {\n\t\tfor (const index of indexes) {\n\t\t\tconst proposed = mergeContextDeletionTargets(acceptedTargets, [candidates[index]!]);\n\t\t\ttry {\n\t\t\t\tvalidateContextDeletionRequest(deletionRequestFromTargets(proposed), transcript);\n\t\t\t\tacceptedTargets = proposed;\n\t\t\t\taccepted.add(index);\n\t\t\t} catch {\n\t\t\t\trejected.add(index);\n\t\t\t}\n\t\t}\n\t};\n\tacceptIndividually(ordinary);\n\tacceptIndividually(boundaries);\n\n\tfor (let index = 0; index < matches.length; index++) {\n\t\tif (rejected.has(index)) pushProtectedGrepSkip(skipped, matches[index]!);\n\t}\n\treturn {\n\t\tcandidates: candidates.filter((_candidate, index) => accepted.has(index)),\n\t\tmatches: matches.filter((_match, index) => accepted.has(index)),\n\t};\n}\n"]}
@@ -1,4 +0,0 @@
1
- import { type CompactableTranscript, type ContextCompactionRunOptions } from "./context-compaction-types.ts";
2
- import { type ContextDeletionToolController } from "./context-deletion-tool-definitions.ts";
3
- export declare function createContextDeletionTool(inputTranscript: CompactableTranscript, options?: ContextCompactionRunOptions): ContextDeletionToolController;
4
- //# sourceMappingURL=context-deletion-tools.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-deletion-tools.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-tools.ts"],"names":[],"mappings":"AAEA,OAAO,EAEN,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAEhC,MAAM,+BAA+B,CAAC;AAUvC,OAAO,EAiBN,KAAK,6BAA6B,EAalC,MAAM,wCAAwC,CAAC;AAsBhD,wBAAgB,yBAAyB,CACxC,eAAe,EAAE,qBAAqB,EACtC,OAAO,GAAE,2BAAgC,GACvC,6BAA6B,CA0a/B","sourcesContent":["import type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport type { ContextCompactionStats, ContextDeletionTarget } from \"../session-manager.ts\";\nimport {\n\tCONTEXT_COMPACTION_AUTO_QUERY,\n\ttype CompactableTranscript,\n\ttype ContextCompactionRunOptions,\n\ttype ValidatedContextDeletionResult,\n} from \"./context-compaction-types.ts\";\nimport {\n\tcreateContextCompactionBudgetDetails,\n\tcreateContextDeletionToolResult,\n\tcountRemainingImageBlocks,\n\tfinitePositiveNumber,\n\tformatErrorMessage,\n\tsumRemainingImageTokens,\n} from \"./context-compaction-metrics.ts\";\nimport { getTranscriptCompactionParameters, normalizeContextCompactionParameters } from \"./context-compaction-strategy.ts\";\nimport {\n\tCONTEXT_COMPACTION_BUDGET_TOOL,\n\tCONTEXT_DELETE_TOOL,\n\tCONTEXT_DELETE_TOOL_NAME,\n\tCONTEXT_GREP_DELETE_DEFAULT_MAX_MATCHES,\n\tCONTEXT_GREP_DELETE_TOOL,\n\tCONTEXT_GREP_DELETE_TOOL_NAME,\n\tCONTEXT_READ_ENTRY_DEFAULT_MAX_CHARS,\n\tCONTEXT_READ_ENTRY_MAX_CHARS,\n\tCONTEXT_READ_ENTRY_TOOL,\n\tCONTEXT_READ_ENTRY_TOOL_NAME,\n\tCONTEXT_SEARCH_DEFAULT_CONTEXT_CHARS,\n\tCONTEXT_SEARCH_DEFAULT_MAX_MATCHES,\n\tCONTEXT_SEARCH_MAX_CONTEXT_CHARS,\n\tCONTEXT_SEARCH_MAX_MATCHES,\n\tCONTEXT_SEARCH_TRANSCRIPT_TOOL,\n\ttype ContextCompactionBudgetToolDetails,\n\ttype ContextDeletionToolController,\n\ttype ContextDeletionToolDetails,\n\ttype ContextGrepDeletionMatch,\n\ttype ContextGrepDeletionSkipped,\n\ttype ContextGrepDeletionToolDetails,\n\ttype ContextReadEntryToolDetails,\n\ttype ContextTranscriptSearchMatch,\n\ttype ContextTranscriptSearchToolDetails,\n\tContextCompactionBudgetToolParameters,\n\tContextDeleteToolParameters,\n\tContextGrepDeleteToolParameters,\n\tContextReadEntryToolParameters,\n\tContextSearchTranscriptToolParameters,\n} from \"./context-deletion-tool-definitions.ts\";\nimport { computeContextCompactionStats, contextDeletionRequestFromObject, validateContextDeletionRequest } from \"./context-deletion-application.ts\";\nimport {\n\tcanDeleteTarget,\n\tdeletionRequestFromTargets,\n\tgetRecentContextEntryIds,\n\tisStaleUserImageOnlyEntry,\n\tmergeContextDeletionTargets,\n} from \"./context-deletion-targets.ts\";\nimport { createContextDeletionStore } from \"./context-deletion-store.ts\";\nimport {\n\taddGrepCandidate,\n\tassertSafeRegexScan,\n\tclampInteger,\n\tcreateGrepMatcher,\n\tcurrentTargetDeleted,\n\tfilterProtectedGrepCandidates,\n\tfindMatchIndex,\n\tsnippetForMatch,\n\ttextSlice,\n} from \"./context-deletion-tool-helpers.ts\";\n\nexport function createContextDeletionTool(\n\tinputTranscript: CompactableTranscript,\n\toptions: ContextCompactionRunOptions = {},\n): ContextDeletionToolController {\n\tconst contextWindow = finitePositiveNumber(options.contextWindow);\n\tconst parameters = normalizeContextCompactionParameters(\n\t\t{ ...getTranscriptCompactionParameters(inputTranscript), ...options },\n\t\tinputTranscript.parameters?.query ?? CONTEXT_COMPACTION_AUTO_QUERY,\n\t);\n\tconst transcript: CompactableTranscript = { ...inputTranscript, parameters };\n\tconst store = createContextDeletionStore(transcript);\n\tlet validatedResult: ValidatedContextDeletionResult | undefined;\n\n\tfunction readTargets(): ContextDeletionTarget[] {\n\t\treturn store.readTargets();\n\t}\n\n\tfunction applyValidatedTargets(additionalTargets: readonly ContextDeletionTarget[]): ValidatedContextDeletionResult {\n\t\tconst mergedTargets = mergeContextDeletionTargets(readTargets(), additionalTargets);\n\t\tvalidatedResult = validateContextDeletionRequest(deletionRequestFromTargets(mergedTargets), transcript);\n\t\tstore.replaceTargets(validatedResult.deletedTargets);\n\t\treturn validatedResult;\n\t}\n\n\tfunction currentStats(): ContextCompactionStats {\n\t\treturn validatedResult?.stats ?? computeContextCompactionStats(transcript, readTargets());\n\t}\n\n\tfunction canDeleteProtectedTarget(target: ContextDeletionTarget): boolean {\n\t\treturn canDeleteTarget(transcript, target);\n\t}\n\n\tfunction shouldGrepDeleteContentBlockAsEntry(entryId: string, blockCount: number): boolean {\n\t\tif (blockCount <= 1) return true;\n\t\tconst entry = transcript.entries.find((candidate) => candidate.entryId === entryId);\n\t\treturn entry !== undefined && isStaleUserImageOnlyEntry(transcript, entry);\n\t}\n\n\tconst tool: AgentTool<typeof ContextDeleteToolParameters, ContextDeletionToolDetails> = {\n\t\t...CONTEXT_DELETE_TOOL,\n\t\tlabel: \"context deletion request\",\n\t\texecutionMode: \"parallel\",\n\t\tasync execute(_toolCallId, params) {\n\t\t\treturn store.transaction(() => {\n\t\t\t\tconst callCount = store.incrementCallCount();\n\t\t\t\ttry {\n\t\t\t\t\tconst incomingRequest = contextDeletionRequestFromObject(params, `${CONTEXT_DELETE_TOOL_NAME} arguments`);\n\t\t\t\t\tconst incomingValidated = validateContextDeletionRequest(incomingRequest, transcript);\n\t\t\t\t\tconst applied = applyValidatedTargets(incomingValidated.deletedTargets);\n\t\t\t\t\tstore.clearLastError();\n\t\t\t\t\tconst deletedTargets = readTargets();\n\n\t\t\t\t\tconst details: ContextDeletionToolDetails = {\n\t\t\t\t\t\tdeletions: deletionRequestFromTargets(deletedTargets).deletions,\n\t\t\t\t\t\tdeletedTargets,\n\t\t\t\t\t\tstats: applied.stats,\n\t\t\t\t\t\tcallCount,\n\t\t\t\t\t};\n\t\t\t\t\tconst text = `Recorded ${incomingValidated.deletedTargets.length} deletion target(s); ${deletedTargets.length} total validated deletion target(s) are selected. Continue calling ${CONTEXT_DELETE_TOOL_NAME} or ${CONTEXT_GREP_DELETE_TOOL_NAME} for additional deletions, or respond done when finished.`;\n\t\t\t\t\treturn createContextDeletionToolResult(text, details);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = formatErrorMessage(error);\n\t\t\t\t\tstore.setLastError(message);\n\t\t\t\t\tconst deletedTargets = readTargets();\n\t\t\t\t\tconst details: ContextDeletionToolDetails = {\n\t\t\t\t\t\tdeletions: deletionRequestFromTargets(deletedTargets).deletions,\n\t\t\t\t\t\tdeletedTargets,\n\t\t\t\t\t\tstats: currentStats(),\n\t\t\t\t\t\tcallCount,\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t};\n\t\t\t\t\treturn createContextDeletionToolResult(\n\t\t\t\t\t\t`Error recording context deletion targets: ${message}. No new deletion targets were applied; continue with a corrected tool call.`,\n\t\t\t\t\t\tdetails,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t};\n\n\tconst grepTool: AgentTool<typeof ContextGrepDeleteToolParameters, ContextGrepDeletionToolDetails> = {\n\t\t...CONTEXT_GREP_DELETE_TOOL,\n\t\tlabel: \"context grep delete\",\n\t\texecutionMode: \"parallel\",\n\t\tasync execute(_toolCallId, params) {\n\t\t\treturn store.transaction(() => {\n\t\t\t\tconst callCount = store.incrementCallCount();\n\t\t\t\tconst pattern = params.pattern;\n\t\t\t\tconst regex = params.regex === true;\n\t\t\t\tconst caseSensitive = params.caseSensitive === true;\n\t\t\t\tconst target = params.target ?? \"entry\";\n\t\t\t\tconst maxMatches = params.maxMatches ?? CONTEXT_GREP_DELETE_DEFAULT_MAX_MATCHES;\n\t\t\t\tconst candidates: ContextDeletionTarget[] = [];\n\t\t\t\tconst matches: ContextGrepDeletionMatch[] = [];\n\t\t\t\tlet reportedMatches: ContextGrepDeletionMatch[] = matches;\n\t\t\t\tconst skipped: ContextGrepDeletionSkipped[] = [];\n\t\t\t\tconst seenTargets = new Set<string>();\n\n\t\t\t\ttry {\n\t\t\t\t\tif (regex) {\n\t\t\t\t\t\tassertSafeRegexScan(store.getGrepScanTextLength(target));\n\t\t\t\t\t}\n\t\t\t\t\tconst matcher = createGrepMatcher(pattern, regex, caseSensitive);\n\t\t\t\t\tconst currentTargets = readTargets();\n\t\t\t\t\tconst recentEntryIds = getRecentContextEntryIds(transcript);\n\n\t\t\t\t\tif (target === \"entry\") {\n\t\t\t\t\t\tfor (const entry of store.listEntriesForGrep()) {\n\t\t\t\t\t\t\tif (!matcher.test(entry.text)) continue;\n\t\t\t\t\t\t\tconst candidate: ContextDeletionTarget = { kind: \"entry\", entryId: entry.entry_id };\n\t\t\t\t\t\t\tif (recentEntryIds.has(candidate.entryId)) {\n\t\t\t\t\t\t\t\tskipped.push({ entryId: entry.entry_id, target, reason: \"protected_entry\", text: entry.text });\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (entry.is_protected === 1 && !canDeleteProtectedTarget(candidate)) {\n\t\t\t\t\t\t\t\tskipped.push({ entryId: entry.entry_id, target, reason: \"protected_entry\", text: entry.text });\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (currentTargetDeleted(currentTargets, candidate)) {\n\t\t\t\t\t\t\t\tskipped.push({ entryId: entry.entry_id, target, reason: \"already_deleted\", text: entry.text });\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\taddGrepCandidate(candidates, matches, seenTargets, candidate, {\n\t\t\t\t\t\t\t\tentryId: entry.entry_id,\n\t\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t\t\ttext: entry.text,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor (const block of store.listContentBlocksForGrep()) {\n\t\t\t\t\t\t\tif (!matcher.test(block.text)) continue;\n\t\t\t\t\t\t\tconst candidate: ContextDeletionTarget = shouldGrepDeleteContentBlockAsEntry(block.entry_id, block.block_count)\n\t\t\t\t\t\t\t\t? { kind: \"entry\", entryId: block.entry_id }\n\t\t\t\t\t\t\t\t: { kind: \"content_block\", entryId: block.entry_id, blockIndex: block.block_index };\n\t\t\t\t\t\t\tif (recentEntryIds.has(candidate.entryId)) {\n\t\t\t\t\t\t\t\tskipped.push({\n\t\t\t\t\t\t\t\t\tentryId: block.entry_id,\n\t\t\t\t\t\t\t\t\ttarget: candidate.kind,\n\t\t\t\t\t\t\t\t\t...(candidate.kind === \"content_block\" ? { blockIndex: candidate.blockIndex } : {}),\n\t\t\t\t\t\t\t\t\treason: \"protected_entry\",\n\t\t\t\t\t\t\t\t\ttext: block.text,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (block.entry_protected === 1 && !canDeleteProtectedTarget(candidate)) {\n\t\t\t\t\t\t\t\tskipped.push({\n\t\t\t\t\t\t\t\t\tentryId: block.entry_id,\n\t\t\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t\t\t\tblockIndex: block.block_index,\n\t\t\t\t\t\t\t\t\treason: \"protected_entry\",\n\t\t\t\t\t\t\t\t\ttext: block.text,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (block.block_protected === 1 && !canDeleteProtectedTarget(candidate)) {\n\t\t\t\t\t\t\t\tskipped.push({\n\t\t\t\t\t\t\t\t\tentryId: block.entry_id,\n\t\t\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t\t\t\tblockIndex: block.block_index,\n\t\t\t\t\t\t\t\t\treason: \"protected_block\",\n\t\t\t\t\t\t\t\t\ttext: block.text,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (currentTargetDeleted(currentTargets, candidate)) {\n\t\t\t\t\t\t\t\tskipped.push({\n\t\t\t\t\t\t\t\t\tentryId: block.entry_id,\n\t\t\t\t\t\t\t\t\ttarget: candidate.kind,\n\t\t\t\t\t\t\t\t\t...(candidate.kind === \"content_block\" ? { blockIndex: candidate.blockIndex } : {}),\n\t\t\t\t\t\t\t\t\treason: \"already_deleted\",\n\t\t\t\t\t\t\t\t\ttext: block.text,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\taddGrepCandidate(candidates, matches, seenTargets, candidate, {\n\t\t\t\t\t\t\t\tentryId: block.entry_id,\n\t\t\t\t\t\t\t\ttarget: candidate.kind,\n\t\t\t\t\t\t\t\t...(candidate.kind === \"content_block\" ? { blockIndex: candidate.blockIndex } : {}),\n\t\t\t\t\t\t\t\ttext: block.text,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst eligible = filterProtectedGrepCandidates(candidates, matches, currentTargets, transcript, skipped);\n\t\t\t\t\treportedMatches = eligible.matches;\n\t\t\t\t\tlet applied: ValidatedContextDeletionResult | undefined;\n\t\t\t\t\tif (params.expectedMatchCount !== undefined && eligible.candidates.length !== params.expectedMatchCount) {\n\t\t\t\t\t\tskipped.push({ reason: \"expected_match_count_mismatch\" });\n\t\t\t\t\t} else if (eligible.candidates.length > maxMatches) {\n\t\t\t\t\t\tskipped.push({ reason: \"max_matches_exceeded\" });\n\t\t\t\t\t} else if (eligible.candidates.length > 0) {\n\t\t\t\t\t\tapplied = applyValidatedTargets(eligible.candidates);\n\t\t\t\t\t}\n\t\t\t\t\tstore.clearLastError();\n\t\t\t\t\tconst deletedTargets = readTargets();\n\n\t\t\t\t\tconst details: ContextGrepDeletionToolDetails = {\n\t\t\t\t\t\tpattern,\n\t\t\t\t\t\tregex,\n\t\t\t\t\t\tcaseSensitive,\n\t\t\t\t\t\ttarget,\n\t\t\t\t\t\tmatches: eligible.matches,\n\t\t\t\t\t\tskipped,\n\t\t\t\t\t\tdeletedTargets,\n\t\t\t\t\t\tstats: applied?.stats ?? currentStats(),\n\t\t\t\t\t\tcallCount,\n\t\t\t\t\t};\n\t\t\t\t\tconst text = `Matched ${eligible.matches.length} deletion target(s), skipped ${skipped.length}, and ${applied ? \"applied\" : \"did not apply\"} grep deletion for pattern ${JSON.stringify(pattern)}. Total validated deletion target(s): ${deletedTargets.length}.`;\n\t\t\t\t\treturn createContextDeletionToolResult(text, details);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = formatErrorMessage(error);\n\t\t\t\t\tstore.setLastError(message);\n\t\t\t\t\tconst deletedTargets = readTargets();\n\t\t\t\t\tconst details: ContextGrepDeletionToolDetails = {\n\t\t\t\t\t\tpattern,\n\t\t\t\t\t\tregex,\n\t\t\t\t\t\tcaseSensitive,\n\t\t\t\t\t\ttarget,\n\t\t\t\t\t\tmatches: reportedMatches,\n\t\t\t\t\t\tskipped,\n\t\t\t\t\t\tdeletedTargets,\n\t\t\t\t\t\tstats: currentStats(),\n\t\t\t\t\t\tcallCount,\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t};\n\t\t\t\t\treturn createContextDeletionToolResult(\n\t\t\t\t\t\t`Error applying grep deletion for pattern ${JSON.stringify(pattern)}: ${message}. No new deletion targets were applied; continue with a corrected tool call.`,\n\t\t\t\t\t\tdetails,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t};\n\n\tconst searchTool: AgentTool<typeof ContextSearchTranscriptToolParameters, ContextTranscriptSearchToolDetails> = {\n\t\t...CONTEXT_SEARCH_TRANSCRIPT_TOOL,\n\t\tlabel: \"context transcript search\",\n\t\texecutionMode: \"parallel\",\n\t\tasync execute(_toolCallId, params) {\n\t\t\treturn store.transaction(() => {\n\t\t\t\tconst callCount = store.incrementCallCount();\n\t\t\t\tconst pattern = params.pattern;\n\t\t\t\tconst regex = params.regex === true;\n\t\t\t\tconst caseSensitive = params.caseSensitive === true;\n\t\t\t\tconst target = params.target ?? \"entry\";\n\t\t\t\tconst maxMatches = clampInteger(params.maxMatches, CONTEXT_SEARCH_DEFAULT_MAX_MATCHES, 1, CONTEXT_SEARCH_MAX_MATCHES);\n\t\t\t\tconst contextChars = clampInteger(\n\t\t\t\t\tparams.contextChars,\n\t\t\t\t\tCONTEXT_SEARCH_DEFAULT_CONTEXT_CHARS,\n\t\t\t\t\t0,\n\t\t\t\t\tCONTEXT_SEARCH_MAX_CONTEXT_CHARS,\n\t\t\t\t);\n\t\t\t\tconst matches: ContextTranscriptSearchMatch[] = [];\n\t\t\t\tlet truncated = false;\n\n\t\t\t\ttry {\n\t\t\t\t\tif (regex) {\n\t\t\t\t\t\tassertSafeRegexScan(store.getGrepScanTextLength(target));\n\t\t\t\t\t}\n\t\t\t\t\tconst matcher = createGrepMatcher(pattern, regex, caseSensitive);\n\t\t\t\t\tif (target === \"entry\") {\n\t\t\t\t\t\tfor (const entry of store.listEntriesForGrep()) {\n\t\t\t\t\t\t\tconst matchIndex = findMatchIndex(matcher, entry.text);\n\t\t\t\t\t\t\tif (matchIndex < 0) continue;\n\t\t\t\t\t\t\tif (matches.length >= maxMatches) {\n\t\t\t\t\t\t\t\ttruncated = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tmatches.push({\n\t\t\t\t\t\t\t\tentryId: entry.entry_id,\n\t\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t\t\tmatchIndex,\n\t\t\t\t\t\t\t\tsnippet: snippetForMatch(entry.text, matchIndex, contextChars),\n\t\t\t\t\t\t\t\tprotected: entry.is_protected === 1,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor (const block of store.listContentBlocksForGrep()) {\n\t\t\t\t\t\t\tconst matchIndex = findMatchIndex(matcher, block.text);\n\t\t\t\t\t\t\tif (matchIndex < 0) continue;\n\t\t\t\t\t\t\tif (matches.length >= maxMatches) {\n\t\t\t\t\t\t\t\ttruncated = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tmatches.push({\n\t\t\t\t\t\t\t\tentryId: block.entry_id,\n\t\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t\t\tblockIndex: block.block_index,\n\t\t\t\t\t\t\t\tmatchIndex,\n\t\t\t\t\t\t\t\tsnippet: snippetForMatch(block.text, matchIndex, contextChars),\n\t\t\t\t\t\t\t\tprotected: block.entry_protected === 1 || block.block_protected === 1,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tstore.clearLastError();\n\t\t\t\t\tconst details: ContextTranscriptSearchToolDetails = {\n\t\t\t\t\t\tpattern,\n\t\t\t\t\t\tregex,\n\t\t\t\t\t\tcaseSensitive,\n\t\t\t\t\t\ttarget,\n\t\t\t\t\t\tmatches,\n\t\t\t\t\t\ttruncated,\n\t\t\t\t\t\tcallCount,\n\t\t\t\t\t};\n\t\t\t\t\tconst text = `Found ${matches.length}${truncated ? \"+\" : \"\"} ${target} match(es) for ${JSON.stringify(pattern)}. Use ${CONTEXT_READ_ENTRY_TOOL_NAME} with small maxChars to inspect exact content before deleting.`;\n\t\t\t\t\treturn createContextDeletionToolResult(text, details);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = formatErrorMessage(error);\n\t\t\t\t\tstore.setLastError(message);\n\t\t\t\t\tconst details: ContextTranscriptSearchToolDetails = {\n\t\t\t\t\t\tpattern,\n\t\t\t\t\t\tregex,\n\t\t\t\t\t\tcaseSensitive,\n\t\t\t\t\t\ttarget,\n\t\t\t\t\t\tmatches,\n\t\t\t\t\t\ttruncated,\n\t\t\t\t\t\tcallCount,\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t};\n\t\t\t\t\treturn createContextDeletionToolResult(\n\t\t\t\t\t\t`Error searching transcript for ${JSON.stringify(pattern)}: ${message}. Try a literal pattern or narrower query.`,\n\t\t\t\t\t\tdetails,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t};\n\n\tconst readEntryTool: AgentTool<typeof ContextReadEntryToolParameters, ContextReadEntryToolDetails> = {\n\t\t...CONTEXT_READ_ENTRY_TOOL,\n\t\tlabel: \"context read entry\",\n\t\texecutionMode: \"parallel\",\n\t\tasync execute(_toolCallId, params) {\n\t\t\treturn store.transaction(() => {\n\t\t\t\tconst callCount = store.incrementCallCount();\n\t\t\t\tconst offset = clampInteger(params.offset, 0, 0, Number.MAX_SAFE_INTEGER);\n\t\t\t\tconst maxChars = clampInteger(\n\t\t\t\t\tparams.maxChars,\n\t\t\t\t\tCONTEXT_READ_ENTRY_DEFAULT_MAX_CHARS,\n\t\t\t\t\t1,\n\t\t\t\t\tCONTEXT_READ_ENTRY_MAX_CHARS,\n\t\t\t\t);\n\t\t\t\ttry {\n\t\t\t\t\tconst row =\n\t\t\t\t\t\tparams.blockIndex === undefined\n\t\t\t\t\t\t\t? store.getEntryForRead(params.entryId)\n\t\t\t\t\t\t\t: store.getContentBlockForRead(params.entryId, params.blockIndex);\n\t\t\t\t\tif (!row) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\tparams.blockIndex === undefined\n\t\t\t\t\t\t\t\t? `Unknown transcript entry: ${params.entryId}`\n\t\t\t\t\t\t\t\t: `Unknown transcript content block: ${params.entryId}:${params.blockIndex}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst text = row.text;\n\t\t\t\t\tconst slice = textSlice(text, offset, maxChars);\n\t\t\t\t\tstore.clearLastError();\n\t\t\t\t\tconst details: ContextReadEntryToolDetails = {\n\t\t\t\t\t\tentryId: params.entryId,\n\t\t\t\t\t\t...(params.blockIndex === undefined ? {} : { blockIndex: params.blockIndex }),\n\t\t\t\t\t\toffset,\n\t\t\t\t\t\tmaxChars,\n\t\t\t\t\t\ttotalChars: text.length,\n\t\t\t\t\t\ttext: slice,\n\t\t\t\t\t\ttruncatedBefore: offset > 0,\n\t\t\t\t\t\ttruncatedAfter: offset + maxChars < text.length,\n\t\t\t\t\t\tcallCount,\n\t\t\t\t\t};\n\t\t\t\t\tconst textResult = `Read ${slice.length} of ${text.length} characters from ${params.blockIndex === undefined ? params.entryId : `${params.entryId}:${params.blockIndex}`}. Keep reads small; increase offset for the next slice if needed.`;\n\t\t\t\t\treturn createContextDeletionToolResult(textResult, details);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = formatErrorMessage(error);\n\t\t\t\t\tstore.setLastError(message);\n\t\t\t\t\tconst details: ContextReadEntryToolDetails = {\n\t\t\t\t\t\tentryId: params.entryId,\n\t\t\t\t\t\t...(params.blockIndex === undefined ? {} : { blockIndex: params.blockIndex }),\n\t\t\t\t\t\toffset,\n\t\t\t\t\t\tmaxChars,\n\t\t\t\t\t\ttotalChars: 0,\n\t\t\t\t\t\ttext: \"\",\n\t\t\t\t\t\ttruncatedBefore: false,\n\t\t\t\t\t\ttruncatedAfter: false,\n\t\t\t\t\t\tcallCount,\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t};\n\t\t\t\t\treturn createContextDeletionToolResult(`Error reading transcript entry: ${message}`, details);\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t};\n\n\tconst budgetTool: AgentTool<typeof ContextCompactionBudgetToolParameters, ContextCompactionBudgetToolDetails> = {\n\t\t...CONTEXT_COMPACTION_BUDGET_TOOL,\n\t\tlabel: \"context compaction budget\",\n\t\texecutionMode: \"parallel\",\n\t\tasync execute(_toolCallId) {\n\t\t\treturn store.transaction(() => {\n\t\t\t\tconst callCount = store.incrementCallCount();\n\t\t\t\tstore.clearLastError();\n\t\t\t\tconst liveTargets = readTargets(); // recompute image stats each call (issue #1500)\n\t\t\t\tconst imageTokensRemaining = sumRemainingImageTokens(transcript, liveTargets);\n\t\t\t\tconst imageBlocksRemaining = countRemainingImageBlocks(transcript, liveTargets);\n\t\t\t\tconst details = createContextCompactionBudgetDetails(currentStats(), callCount, contextWindow, parameters, imageTokensRemaining, imageBlocksRemaining);\n\t\t\t\tconst windowText =\n\t\t\t\t\tdetails.contextWindowBeforePercent !== undefined\n\t\t\t\t\t\t? ` Context window fullness: ${details.contextWindowBeforePercent}% before selected deletions, ${details.contextWindowAfterPercent}% after selected deletions.`\n\t\t\t\t\t\t: \" Context window size is unknown for this model, so fullness percentages are unavailable.\";\n\t\t\t\tconst targetText = details.tokensToDeleteForTarget > 0 ? ` Delete about ${details.tokensToDeleteForTarget} more token(s) to reach the ${details.targetReductionPercent}% reduction target.` : ` The selected deletions meet or exceed the ${details.targetReductionPercent}% reduction target.`;\n\t\t\t\tconst imageText = details.remainingImageTokens > 0 ? ` Images account for ${details.imageTokenPercent}% of remaining context (${details.remainingImageTokens} tokens across ${details.imageBlockCount} block(s)); prefer deleting stale/superseded image content blocks when images dominate.` : \"\";\n\t\t\t\treturn createContextDeletionToolResult(\n\t\t\t\t\t`Current selected deletions reduce context by ${details.currentReductionPercent}% (${details.deletedTokens} token(s)); tokens after selected deletions: ${details.currentTokensAfter}/${details.tokensBefore}.${windowText}${targetText}${imageText} Keep maximizing useful retained context while aggressively removing low-value blocks.`,\n\t\t\t\t\tdetails,\n\t\t\t\t);\n\t\t\t});\n\t\t},\n\t};\n\n\treturn {\n\t\ttool,\n\t\tgrepTool,\n\t\tsearchTool,\n\t\treadEntryTool,\n\t\tbudgetTool,\n\t\ttools: [tool, grepTool, searchTool, readEntryTool, budgetTool],\n\t\tgetDeletionRequest: () => deletionRequestFromTargets(readTargets()),\n\t\tgetValidatedResult: () => validatedResult,\n\t\tgetLastError: () => store.getLastError(),\n\t\tgetCallCount: () => store.getCallCount(),\n\t};\n}\n"]}