@bastani/atomic 0.9.5-alpha.9 → 0.9.5

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 (377) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/README.md +2 -2
  3. package/dist/builtin/cursor/CHANGELOG.md +12 -0
  4. package/dist/builtin/cursor/package.json +3 -3
  5. package/dist/builtin/cursor/src/model-mapper.ts +6 -3
  6. package/dist/builtin/intercom/CHANGELOG.md +37 -0
  7. package/dist/builtin/intercom/README.md +4 -2
  8. package/dist/builtin/intercom/broker/broker.ts +6 -114
  9. package/dist/builtin/intercom/broker/client.ts +29 -54
  10. package/dist/builtin/intercom/broker/delivered-message-cache.ts +44 -0
  11. package/dist/builtin/intercom/broker/pending-send-registry.ts +142 -0
  12. package/dist/builtin/intercom/broker/send-handler.ts +106 -0
  13. package/dist/builtin/intercom/broker/send-signature.ts +37 -0
  14. package/dist/builtin/intercom/foreground-detach-handoff.ts +136 -0
  15. package/dist/builtin/intercom/index-heavy.ts +49 -53
  16. package/dist/builtin/intercom/index.ts +278 -262
  17. package/dist/builtin/intercom/lazy-heavy-proxy.ts +114 -0
  18. package/dist/builtin/intercom/lazy-subagent-ack.ts +20 -0
  19. package/dist/builtin/intercom/lazy-tool-execution.ts +39 -0
  20. package/dist/builtin/intercom/lifecycle-lease.ts +51 -0
  21. package/dist/builtin/intercom/lifecycle.ts +37 -20
  22. package/dist/builtin/intercom/package.json +3 -6
  23. package/dist/builtin/intercom/reply-routing.ts +17 -0
  24. package/dist/builtin/intercom/subagent-relay.ts +58 -12
  25. package/dist/builtin/intercom/types.ts +3 -3
  26. package/dist/builtin/mcp/CHANGELOG.md +27 -0
  27. package/dist/builtin/mcp/OAUTH.md +1 -0
  28. package/dist/builtin/mcp/README.md +4 -0
  29. package/dist/builtin/mcp/apps-cancellation.ts +32 -0
  30. package/dist/builtin/mcp/call-tool-result.ts +9 -0
  31. package/dist/builtin/mcp/caller-wait.ts +50 -0
  32. package/dist/builtin/mcp/command-registration.ts +82 -0
  33. package/dist/builtin/mcp/direct-tool-executor.ts +279 -0
  34. package/dist/builtin/mcp/direct-tools.ts +6 -239
  35. package/dist/builtin/mcp/host-html-template.ts +4 -2
  36. package/dist/builtin/mcp/index.ts +258 -250
  37. package/dist/builtin/mcp/init.ts +96 -87
  38. package/dist/builtin/mcp/mcp-auth-flow.ts +247 -237
  39. package/dist/builtin/mcp/mcp-callback-server.ts +89 -68
  40. package/dist/builtin/mcp/mcp-oauth-provider.ts +23 -1
  41. package/dist/builtin/mcp/metadata-hydration.ts +21 -6
  42. package/dist/builtin/mcp/package.json +3 -3
  43. package/dist/builtin/mcp/proxy-auth.ts +4 -4
  44. package/dist/builtin/mcp/proxy-call.ts +111 -40
  45. package/dist/builtin/mcp/proxy-connect.ts +35 -15
  46. package/dist/builtin/mcp/proxy-info-modes.ts +49 -19
  47. package/dist/builtin/mcp/proxy-modes.ts +3 -3
  48. package/dist/builtin/mcp/session-cleanup-barrier.ts +43 -0
  49. package/dist/builtin/mcp/state-lease.ts +12 -0
  50. package/dist/builtin/mcp/ui-server.ts +8 -8
  51. package/dist/builtin/mcp/ui-session.ts +9 -18
  52. package/dist/builtin/subagents/CHANGELOG.md +66 -0
  53. package/dist/builtin/subagents/README.md +30 -29
  54. package/dist/builtin/subagents/agents/code-simplifier.md +2 -2
  55. package/dist/builtin/subagents/agents/codebase-analyzer.md +2 -2
  56. package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
  57. package/dist/builtin/subagents/agents/codebase-online-researcher.md +2 -2
  58. package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
  59. package/dist/builtin/subagents/agents/codebase-research-analyzer.md +2 -2
  60. package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
  61. package/dist/builtin/subagents/agents/debugger.md +2 -2
  62. package/dist/builtin/subagents/agents/worker.md +2 -2
  63. package/dist/builtin/subagents/package.json +5 -5
  64. package/dist/builtin/subagents/prompts/review-loop.md +1 -1
  65. package/dist/builtin/subagents/skills/subagent/SKILL.md +37 -36
  66. package/dist/builtin/subagents/src/extension/api-lifecycle.ts +64 -0
  67. package/dist/builtin/subagents/src/extension/fanout-child.ts +44 -51
  68. package/dist/builtin/subagents/src/extension/index.ts +287 -307
  69. package/dist/builtin/subagents/src/extension/prompt-guidance.ts +7 -10
  70. package/dist/builtin/subagents/src/extension/schemas.ts +22 -5
  71. package/dist/builtin/subagents/src/extension/tool-description.ts +29 -0
  72. package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +13 -2
  73. package/dist/builtin/subagents/src/intercom/result-intercom.ts +4 -4
  74. package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +106 -0
  75. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +3 -2
  76. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +13 -2
  77. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +3 -0
  78. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +1 -1
  79. package/dist/builtin/subagents/src/runs/background/completion-claims.ts +189 -0
  80. package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +44 -7
  81. package/dist/builtin/subagents/src/runs/background/completion-notification.ts +34 -0
  82. package/dist/builtin/subagents/src/runs/background/notify.ts +72 -22
  83. package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +232 -0
  84. package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +151 -0
  85. package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +72 -0
  86. package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +48 -0
  87. package/dist/builtin/subagents/src/runs/background/result-status.ts +81 -0
  88. package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +59 -0
  89. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +172 -238
  90. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +3 -2
  91. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +73 -14
  92. package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +17 -13
  93. package/dist/builtin/subagents/src/runs/background/top-level-async.ts +1 -2
  94. package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +1 -0
  95. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +1 -0
  96. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +1 -0
  97. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +7 -9
  98. package/dist/builtin/subagents/src/runs/foreground/chain-execution-types.ts +3 -13
  99. package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +2 -15
  100. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +2 -2
  101. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +53 -44
  102. package/dist/builtin/subagents/src/runs/foreground/execution-detach-reservations.ts +48 -0
  103. package/dist/builtin/subagents/src/runs/foreground/execution-detach-route.ts +17 -0
  104. package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +39 -26
  105. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +3 -1
  106. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +3 -51
  107. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +6 -11
  108. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-input.ts +11 -2
  109. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +2 -0
  110. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +5 -112
  111. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +2 -0
  112. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +68 -118
  113. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +79 -7
  114. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +2 -2
  115. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +3 -0
  116. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +2 -2
  117. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +27 -11
  118. package/dist/builtin/subagents/src/shared/artifacts.ts +22 -11
  119. package/dist/builtin/subagents/src/shared/event-jsonl-writer.ts +294 -0
  120. package/dist/builtin/subagents/src/shared/exclusive-file-publication.ts +44 -0
  121. package/dist/builtin/subagents/src/shared/jsonl-writer.ts +1 -0
  122. package/dist/builtin/subagents/src/shared/model-info.ts +2 -2
  123. package/dist/builtin/subagents/src/shared/settings.ts +20 -10
  124. package/dist/builtin/subagents/src/shared/types-async.ts +3 -1
  125. package/dist/builtin/subagents/src/shared/types-config.ts +2 -0
  126. package/dist/builtin/subagents/src/shared/types-runtime.ts +3 -2
  127. package/dist/builtin/subagents/src/slash/slash-commands.ts +9 -12
  128. package/dist/builtin/subagents/src/slash/slash-live-state.ts +63 -32
  129. package/dist/builtin/subagents/src/tui/render-result.ts +7 -0
  130. package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -0
  131. package/dist/builtin/subagents/src/tui/render-widget.ts +128 -89
  132. package/dist/builtin/web-access/CHANGELOG.md +28 -0
  133. package/dist/builtin/web-access/README.md +4 -0
  134. package/dist/builtin/web-access/content-tools.ts +8 -3
  135. package/dist/builtin/web-access/index-heavy.ts +1 -1
  136. package/dist/builtin/web-access/index.ts +190 -46
  137. package/dist/builtin/web-access/lifecycle-lease.ts +38 -0
  138. package/dist/builtin/web-access/package.json +2 -2
  139. package/dist/builtin/web-access/result-renderers.ts +1 -1
  140. package/dist/builtin/web-access/summary-review.ts +1 -1
  141. package/dist/builtin/web-access/web-search-activity.ts +1 -1
  142. package/dist/builtin/web-access/web-search-return.ts +7 -0
  143. package/dist/builtin/web-access/web-search-summary.ts +1 -1
  144. package/dist/builtin/web-access/web-search-tool.ts +4 -2
  145. package/dist/builtin/workflows/CHANGELOG.md +68 -0
  146. package/dist/builtin/workflows/README.md +4 -4
  147. package/dist/builtin/workflows/builtin/deep-research-codebase-utils.ts +27 -4
  148. package/dist/builtin/workflows/builtin/goal-runner.ts +47 -26
  149. package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +10 -0
  150. package/dist/builtin/workflows/builtin/ralph-core.ts +9 -9
  151. package/dist/builtin/workflows/builtin/ralph-models.ts +71 -36
  152. package/dist/builtin/workflows/builtin/ralph-runner.ts +20 -31
  153. package/dist/builtin/workflows/package.json +2 -2
  154. package/dist/builtin/workflows/src/durable/stage-primitive.ts +2 -1
  155. package/dist/builtin/workflows/src/engine/primitives/task.ts +2 -1
  156. package/dist/builtin/workflows/src/extension/workflow-prompts.ts +17 -22
  157. package/dist/builtin/workflows/src/extension/workflow-schema.ts +15 -2
  158. package/dist/builtin/workflows/src/runs/foreground/executor-hil.ts +1 -2
  159. package/dist/builtin/workflows/src/runs/shared/model-fallback-candidates.ts +1 -1
  160. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +2 -2
  161. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +2 -2
  162. package/dist/builtin/workflows/src/shared/resume-continuation.ts +2 -0
  163. package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +1 -23
  164. package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +54 -9
  165. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +5 -2
  166. package/dist/cli/args.d.ts.map +1 -1
  167. package/dist/cli/args.js +2 -2
  168. package/dist/cli/args.js.map +1 -1
  169. package/dist/core/agent-session-events.d.ts.map +1 -1
  170. package/dist/core/agent-session-events.js +2 -1
  171. package/dist/core/agent-session-events.js.map +1 -1
  172. package/dist/core/agent-session-message-queue.d.ts.map +1 -1
  173. package/dist/core/agent-session-message-queue.js +1 -1
  174. package/dist/core/agent-session-message-queue.js.map +1 -1
  175. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  176. package/dist/core/agent-session-prompt.js +1 -1
  177. package/dist/core/agent-session-prompt.js.map +1 -1
  178. package/dist/core/agent-session-retry.d.ts.map +1 -1
  179. package/dist/core/agent-session-retry.js +1 -1
  180. package/dist/core/agent-session-retry.js.map +1 -1
  181. package/dist/core/agent-session-services.d.ts.map +1 -1
  182. package/dist/core/agent-session-services.js +3 -2
  183. package/dist/core/agent-session-services.js.map +1 -1
  184. package/dist/core/agent-session-types.d.ts.map +1 -1
  185. package/dist/core/agent-session-types.js +1 -1
  186. package/dist/core/agent-session-types.js.map +1 -1
  187. package/dist/core/anthropic-thinking-guard.d.ts +5 -5
  188. package/dist/core/anthropic-thinking-guard.d.ts.map +1 -1
  189. package/dist/core/anthropic-thinking-guard.js +42 -32
  190. package/dist/core/anthropic-thinking-guard.js.map +1 -1
  191. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  192. package/dist/core/atomic-guide-command.js +15 -15
  193. package/dist/core/atomic-guide-command.js.map +1 -1
  194. package/dist/core/auth-storage.d.ts.map +1 -1
  195. package/dist/core/auth-storage.js +14 -9
  196. package/dist/core/auth-storage.js.map +1 -1
  197. package/dist/core/compaction/compaction.d.ts +2 -0
  198. package/dist/core/compaction/compaction.d.ts.map +1 -1
  199. package/dist/core/compaction/compaction.js +79 -46
  200. package/dist/core/compaction/compaction.js.map +1 -1
  201. package/dist/core/compaction/context-assistant-turns.d.ts +42 -0
  202. package/dist/core/compaction/context-assistant-turns.d.ts.map +1 -0
  203. package/dist/core/compaction/context-assistant-turns.js +87 -0
  204. package/dist/core/compaction/context-assistant-turns.js.map +1 -0
  205. package/dist/core/compaction/context-compaction-critical.d.ts +1 -1
  206. package/dist/core/compaction/context-compaction-critical.d.ts.map +1 -1
  207. package/dist/core/compaction/context-compaction-critical.js +2 -2
  208. package/dist/core/compaction/context-compaction-critical.js.map +1 -1
  209. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts +18 -0
  210. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts.map +1 -0
  211. package/dist/core/compaction/context-compaction-eviction-alternates.js +186 -0
  212. package/dist/core/compaction/context-compaction-eviction-alternates.js.map +1 -0
  213. package/dist/core/compaction/context-compaction-eviction.d.ts +10 -2
  214. package/dist/core/compaction/context-compaction-eviction.d.ts.map +1 -1
  215. package/dist/core/compaction/context-compaction-eviction.js +196 -146
  216. package/dist/core/compaction/context-compaction-eviction.js.map +1 -1
  217. package/dist/core/compaction/context-compaction-prompt.d.ts.map +1 -1
  218. package/dist/core/compaction/context-compaction-prompt.js +1 -1
  219. package/dist/core/compaction/context-compaction-prompt.js.map +1 -1
  220. package/dist/core/compaction/context-compaction-types.d.ts +2 -0
  221. package/dist/core/compaction/context-compaction-types.d.ts.map +1 -1
  222. package/dist/core/compaction/context-compaction-types.js.map +1 -1
  223. package/dist/core/compaction/context-deletion-application.d.ts +5 -4
  224. package/dist/core/compaction/context-deletion-application.d.ts.map +1 -1
  225. package/dist/core/compaction/context-deletion-application.js +17 -15
  226. package/dist/core/compaction/context-deletion-application.js.map +1 -1
  227. package/dist/core/compaction/context-deletion-store.d.ts.map +1 -1
  228. package/dist/core/compaction/context-deletion-store.js +1 -1
  229. package/dist/core/compaction/context-deletion-store.js.map +1 -1
  230. package/dist/core/compaction/context-deletion-targets.d.ts +2 -1
  231. package/dist/core/compaction/context-deletion-targets.d.ts.map +1 -1
  232. package/dist/core/compaction/context-deletion-targets.js +36 -31
  233. package/dist/core/compaction/context-deletion-targets.js.map +1 -1
  234. package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +1 -1
  235. package/dist/core/compaction/context-deletion-tool-helpers.js +116 -43
  236. package/dist/core/compaction/context-deletion-tool-helpers.js.map +1 -1
  237. package/dist/core/compaction/context-transcript-analysis.d.ts +1 -2
  238. package/dist/core/compaction/context-transcript-analysis.d.ts.map +1 -1
  239. package/dist/core/compaction/context-transcript-analysis.js +33 -37
  240. package/dist/core/compaction/context-transcript-analysis.js.map +1 -1
  241. package/dist/core/copilot-model-synthesis.d.ts.map +1 -1
  242. package/dist/core/copilot-model-synthesis.js +3 -1
  243. package/dist/core/copilot-model-synthesis.js.map +1 -1
  244. package/dist/core/extensions/provider-types.d.ts +2 -7
  245. package/dist/core/extensions/provider-types.d.ts.map +1 -1
  246. package/dist/core/extensions/provider-types.js.map +1 -1
  247. package/dist/core/messages.d.ts +9 -0
  248. package/dist/core/messages.d.ts.map +1 -1
  249. package/dist/core/messages.js +100 -18
  250. package/dist/core/messages.js.map +1 -1
  251. package/dist/core/model-registry-builtins.d.ts.map +1 -1
  252. package/dist/core/model-registry-builtins.js +5 -0
  253. package/dist/core/model-registry-builtins.js.map +1 -1
  254. package/dist/core/model-registry-custom-loader.d.ts.map +1 -1
  255. package/dist/core/model-registry-custom-loader.js +49 -8
  256. package/dist/core/model-registry-custom-loader.js.map +1 -1
  257. package/dist/core/model-registry-dynamic.d.ts.map +1 -1
  258. package/dist/core/model-registry-dynamic.js +11 -5
  259. package/dist/core/model-registry-dynamic.js.map +1 -1
  260. package/dist/core/model-registry-loader.d.ts.map +1 -1
  261. package/dist/core/model-registry-loader.js +8 -0
  262. package/dist/core/model-registry-loader.js.map +1 -1
  263. package/dist/core/model-registry-schemas.d.ts +93 -8
  264. package/dist/core/model-registry-schemas.d.ts.map +1 -1
  265. package/dist/core/model-registry-schemas.js +24 -12
  266. package/dist/core/model-registry-schemas.js.map +1 -1
  267. package/dist/core/model-registry-types.d.ts +7 -6
  268. package/dist/core/model-registry-types.d.ts.map +1 -1
  269. package/dist/core/model-registry-types.js.map +1 -1
  270. package/dist/core/model-registry.d.ts +5 -0
  271. package/dist/core/model-registry.d.ts.map +1 -1
  272. package/dist/core/model-registry.js +23 -0
  273. package/dist/core/model-registry.js.map +1 -1
  274. package/dist/core/model-resolver-cli.d.ts.map +1 -1
  275. package/dist/core/model-resolver-cli.js +33 -5
  276. package/dist/core/model-resolver-cli.js.map +1 -1
  277. package/dist/core/model-resolver-initial.d.ts +6 -1
  278. package/dist/core/model-resolver-initial.d.ts.map +1 -1
  279. package/dist/core/model-resolver-initial.js +12 -7
  280. package/dist/core/model-resolver-initial.js.map +1 -1
  281. package/dist/core/model-resolver.d.ts +1 -1
  282. package/dist/core/model-resolver.d.ts.map +1 -1
  283. package/dist/core/model-resolver.js +1 -1
  284. package/dist/core/model-resolver.js.map +1 -1
  285. package/dist/core/resource-loader-context-files.d.ts +1 -0
  286. package/dist/core/resource-loader-context-files.d.ts.map +1 -1
  287. package/dist/core/resource-loader-context-files.js +13 -10
  288. package/dist/core/resource-loader-context-files.js.map +1 -1
  289. package/dist/core/sdk.d.ts.map +1 -1
  290. package/dist/core/sdk.js +2 -2
  291. package/dist/core/sdk.js.map +1 -1
  292. package/dist/core/session-entry-normalization.d.ts +7 -0
  293. package/dist/core/session-entry-normalization.d.ts.map +1 -0
  294. package/dist/core/session-entry-normalization.js +14 -0
  295. package/dist/core/session-entry-normalization.js.map +1 -0
  296. package/dist/core/session-manager-core.d.ts.map +1 -1
  297. package/dist/core/session-manager-core.js +1 -0
  298. package/dist/core/session-manager-core.js.map +1 -1
  299. package/dist/core/session-manager-history.d.ts +2 -2
  300. package/dist/core/session-manager-history.d.ts.map +1 -1
  301. package/dist/core/session-manager-history.js +127 -108
  302. package/dist/core/session-manager-history.js.map +1 -1
  303. package/dist/core/settings-manager-basic-accessors.d.ts +2 -2
  304. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  305. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  306. package/dist/core/settings-types.d.ts +1 -1
  307. package/dist/core/settings-types.d.ts.map +1 -1
  308. package/dist/core/settings-types.js.map +1 -1
  309. package/dist/core/tools/bash.d.ts.map +1 -1
  310. package/dist/core/tools/bash.js +11 -8
  311. package/dist/core/tools/bash.js.map +1 -1
  312. package/dist/main-session.d.ts.map +1 -1
  313. package/dist/main-session.js +1 -0
  314. package/dist/main-session.js.map +1 -1
  315. package/dist/modes/interactive/components/settings-selector-options.d.ts.map +1 -1
  316. package/dist/modes/interactive/components/settings-selector-options.js +3 -1
  317. package/dist/modes/interactive/components/settings-selector-options.js.map +1 -1
  318. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  319. package/dist/modes/interactive/components/thinking-selector.js +2 -1
  320. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  321. package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
  322. package/dist/modes/interactive/interactive-agent-events.js +2 -1
  323. package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
  324. package/dist/modes/interactive/interactive-child-ordering.d.ts +7 -0
  325. package/dist/modes/interactive/interactive-child-ordering.d.ts.map +1 -0
  326. package/dist/modes/interactive/interactive-child-ordering.js +26 -0
  327. package/dist/modes/interactive/interactive-child-ordering.js.map +1 -0
  328. package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
  329. package/dist/modes/interactive/interactive-deferred-startup.js +2 -2
  330. package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
  331. package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
  332. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  333. package/dist/modes/interactive/interactive-mode-deps.js +1 -1
  334. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  335. package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
  336. package/dist/modes/interactive/interactive-model-routing.js +8 -3
  337. package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
  338. package/dist/modes/interactive/theme/theme-class.d.ts +1 -1
  339. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  340. package/dist/modes/interactive/theme/theme-class.js +2 -0
  341. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  342. package/dist/utils/clipboard-image.d.ts.map +1 -1
  343. package/dist/utils/clipboard-image.js +3 -0
  344. package/dist/utils/clipboard-image.js.map +1 -1
  345. package/docs/changelog.mdx +19 -0
  346. package/docs/compaction.md +55 -48
  347. package/docs/custom-provider.md +18 -5
  348. package/docs/extensions.md +7 -3
  349. package/docs/models.md +69 -10
  350. package/docs/providers.md +1 -1
  351. package/docs/quickstart.md +11 -7
  352. package/docs/rpc.md +2 -2
  353. package/docs/sdk.md +1 -1
  354. package/docs/settings.md +3 -3
  355. package/docs/subagents.md +36 -5
  356. package/docs/tools.md +1 -1
  357. package/docs/usage.md +4 -2
  358. package/docs/workflows.md +26 -43
  359. package/examples/extensions/preset.ts +2 -2
  360. package/examples/extensions/subagent/README.md +2 -2
  361. package/examples/extensions/subagent/index.ts +1 -2
  362. package/examples/extensions/subagent/schemas.ts +4 -1
  363. package/examples/sdk/12-full-control.ts +1 -1
  364. package/npm-shrinkwrap.json +48 -51
  365. package/package.json +7 -7
  366. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-behavior.ts +0 -75
  367. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-component.ts +0 -202
  368. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-edit.ts +0 -97
  369. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-editor.ts +0 -160
  370. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-frame.ts +0 -72
  371. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-modes.ts +0 -161
  372. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-selectors.ts +0 -203
  373. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-selectors.ts +0 -234
  374. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-state.ts +0 -103
  375. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-types.ts +0 -29
  376. package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +0 -9
  377. package/dist/builtin/subagents/src/runs/foreground/chain-execution-clarify.ts +0 -117
@@ -24,6 +24,8 @@ export interface CompactableContentBlock {
24
24
  text: string;
25
25
  tokenEstimate: number;
26
26
  protected: boolean;
27
+ /** Visibility computed from the raw durable block before transcript display normalization. */
28
+ llmVisible?: boolean;
27
29
  toolCallId?: string;
28
30
  }
29
31
  export interface CompactableTranscriptEntry {
@@ -1 +1 @@
1
- {"version":3,"file":"context-compaction-types.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACzG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,eAAO,MAAM,iCAAiC,EAAG,CAAU,CAAC;AAE5D,MAAM,WAAW,2BAA2B;IAC3C,gFAAgF;IAChF,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,eAAe,EAAE,MAAM,CAAC;IACxB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACtC,SAAS,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,OAAO,GAAG,eAAe,CAAC;QAChC,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACH;AAED,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,uBAAuB,EAAE,CAAC;IACzC,OAAO,EAAE,YAAY,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,0BAA0B,EAAE,CAAC;IACtC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,CAAC,EAAE,2BAA2B,CAAC;CACzC;AAED,MAAM,WAAW,4BAA4B;IAC5C,UAAU,EAAE,qBAAqB,CAAC;IAClC,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,UAAU,EAAE,2BAA2B,CAAC;CACxC;AAED,MAAM,WAAW,8BAA8B;IAC9C,cAAc,EAAE,qBAAqB,EAAE,CAAC;IACxC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,KAAK,EAAE,sBAAsB,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAwB,SAAQ,8BAA8B;IAC9E,aAAa,EAAE,OAAO,iCAAiC,CAAC;IACxD,UAAU,EAAE,2BAA2B,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,2BAA2B;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,4CAA4C,EAAG,GAAY,CAAC;AACzE,eAAO,MAAM,2CAA2C,EAAG,EAAW,CAAC;AACvE,eAAO,MAAM,0CAA0C,EAAG,CAAU,CAAC;AACrE,eAAO,MAAM,6BAA6B,EAAG,eAAwB,CAAC","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { ContextCompactionStats, ContextDeletionTarget, SessionEntry } from \"../session-manager.ts\";\nimport type { CompactionSettings } from \"./compaction.ts\";\n\nexport const CONTEXT_COMPACTION_PROMPT_VERSION = 1 as const;\n\nexport interface ContextCompactionParameters {\n\t/** Fraction of compactable context to keep. 0.3 is aggressive, 0.7 is light. */\n\tcompression_ratio: number;\n\t/** Number of recent context-eligible messages to preserve. */\n\tpreserve_recent: number;\n\t/** Focus query for relevance-based pruning. */\n\tquery: string;\n}\n\nexport interface ContextDeletionRequest {\n\tdeletions: Array<{\n\t\tkind: \"entry\" | \"content_block\";\n\t\tentryId: string;\n\t\tblockIndex?: number;\n\t}>;\n}\n\nexport interface CompactableContentBlock {\n\tentryId: string;\n\tblockIndex: number;\n\ttype: string;\n\ttext: string;\n\ttokenEstimate: number;\n\tprotected: boolean;\n\ttoolCallId?: string;\n}\n\nexport interface CompactableTranscriptEntry {\n\tentryId: string;\n\tentryType: SessionEntry[\"type\"];\n\trole: AgentMessage[\"role\"];\n\ttext: string;\n\ttokenEstimate: number;\n\tprotected: boolean;\n\tcontentBlocks: CompactableContentBlock[];\n\tmessage: AgentMessage;\n\ttoolCallIds: string[];\n\ttoolResultFor?: string;\n}\n\nexport interface CompactableTranscript {\n\tentries: CompactableTranscriptEntry[];\n\tprotectedEntryIds: string[];\n\ttokensBefore: number;\n\tsettings: CompactionSettings;\n\tparameters?: ContextCompactionParameters;\n}\n\nexport interface ContextCompactionPreparation {\n\ttranscript: CompactableTranscript;\n\tbranchEntries: SessionEntry[];\n\tparameters: ContextCompactionParameters;\n}\n\nexport interface ValidatedContextDeletionResult {\n\tdeletedTargets: ContextDeletionTarget[];\n\tprotectedEntryIds: string[];\n\tstats: ContextCompactionStats;\n}\n\nexport interface ContextCompactionResult extends ValidatedContextDeletionResult {\n\tpromptVersion: typeof CONTEXT_COMPACTION_PROMPT_VERSION;\n\tparameters: ContextCompactionParameters;\n\tbackupPath?: string;\n}\n\nexport interface ContextCompactionRunOptions {\n\tcontextWindow?: number;\n\tcompression_ratio?: number;\n\tpreserve_recent?: number;\n\tquery?: string;\n}\n\nexport const CONTEXT_COMPACTION_DEFAULT_COMPRESSION_RATIO = 0.5 as const;\nexport const CONTEXT_COMPACTION_TARGET_REDUCTION_PERCENT = 50 as const;\nexport const CONTEXT_COMPACTION_DEFAULT_PRESERVE_RECENT = 2 as const;\nexport const CONTEXT_COMPACTION_AUTO_QUERY = \"auto-detected\" as const;\n"]}
1
+ {"version":3,"file":"context-compaction-types.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACzG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,eAAO,MAAM,iCAAiC,EAAG,CAAU,CAAC;AAE5D,MAAM,WAAW,2BAA2B;IAC3C,gFAAgF;IAChF,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,eAAe,EAAE,MAAM,CAAC;IACxB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACtC,SAAS,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,OAAO,GAAG,eAAe,CAAC;QAChC,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACH;AAED,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,8FAA8F;IAC9F,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,uBAAuB,EAAE,CAAC;IACzC,OAAO,EAAE,YAAY,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,0BAA0B,EAAE,CAAC;IACtC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,CAAC,EAAE,2BAA2B,CAAC;CACzC;AAED,MAAM,WAAW,4BAA4B;IAC5C,UAAU,EAAE,qBAAqB,CAAC;IAClC,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,UAAU,EAAE,2BAA2B,CAAC;CACxC;AAED,MAAM,WAAW,8BAA8B;IAC9C,cAAc,EAAE,qBAAqB,EAAE,CAAC;IACxC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,KAAK,EAAE,sBAAsB,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAwB,SAAQ,8BAA8B;IAC9E,aAAa,EAAE,OAAO,iCAAiC,CAAC;IACxD,UAAU,EAAE,2BAA2B,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,2BAA2B;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,4CAA4C,EAAG,GAAY,CAAC;AACzE,eAAO,MAAM,2CAA2C,EAAG,EAAW,CAAC;AACvE,eAAO,MAAM,0CAA0C,EAAG,CAAU,CAAC;AACrE,eAAO,MAAM,6BAA6B,EAAG,eAAwB,CAAC","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { ContextCompactionStats, ContextDeletionTarget, SessionEntry } from \"../session-manager.ts\";\nimport type { CompactionSettings } from \"./compaction.ts\";\n\nexport const CONTEXT_COMPACTION_PROMPT_VERSION = 1 as const;\n\nexport interface ContextCompactionParameters {\n\t/** Fraction of compactable context to keep. 0.3 is aggressive, 0.7 is light. */\n\tcompression_ratio: number;\n\t/** Number of recent context-eligible messages to preserve. */\n\tpreserve_recent: number;\n\t/** Focus query for relevance-based pruning. */\n\tquery: string;\n}\n\nexport interface ContextDeletionRequest {\n\tdeletions: Array<{\n\t\tkind: \"entry\" | \"content_block\";\n\t\tentryId: string;\n\t\tblockIndex?: number;\n\t}>;\n}\n\nexport interface CompactableContentBlock {\n\tentryId: string;\n\tblockIndex: number;\n\ttype: string;\n\ttext: string;\n\ttokenEstimate: number;\n\tprotected: boolean;\n\t/** Visibility computed from the raw durable block before transcript display normalization. */\n\tllmVisible?: boolean;\n\ttoolCallId?: string;\n}\n\nexport interface CompactableTranscriptEntry {\n\tentryId: string;\n\tentryType: SessionEntry[\"type\"];\n\trole: AgentMessage[\"role\"];\n\ttext: string;\n\ttokenEstimate: number;\n\tprotected: boolean;\n\tcontentBlocks: CompactableContentBlock[];\n\tmessage: AgentMessage;\n\ttoolCallIds: string[];\n\ttoolResultFor?: string;\n}\n\nexport interface CompactableTranscript {\n\tentries: CompactableTranscriptEntry[];\n\tprotectedEntryIds: string[];\n\ttokensBefore: number;\n\tsettings: CompactionSettings;\n\tparameters?: ContextCompactionParameters;\n}\n\nexport interface ContextCompactionPreparation {\n\ttranscript: CompactableTranscript;\n\tbranchEntries: SessionEntry[];\n\tparameters: ContextCompactionParameters;\n}\n\nexport interface ValidatedContextDeletionResult {\n\tdeletedTargets: ContextDeletionTarget[];\n\tprotectedEntryIds: string[];\n\tstats: ContextCompactionStats;\n}\n\nexport interface ContextCompactionResult extends ValidatedContextDeletionResult {\n\tpromptVersion: typeof CONTEXT_COMPACTION_PROMPT_VERSION;\n\tparameters: ContextCompactionParameters;\n\tbackupPath?: string;\n}\n\nexport interface ContextCompactionRunOptions {\n\tcontextWindow?: number;\n\tcompression_ratio?: number;\n\tpreserve_recent?: number;\n\tquery?: string;\n}\n\nexport const CONTEXT_COMPACTION_DEFAULT_COMPRESSION_RATIO = 0.5 as const;\nexport const CONTEXT_COMPACTION_TARGET_REDUCTION_PERCENT = 50 as const;\nexport const CONTEXT_COMPACTION_DEFAULT_PRESERVE_RECENT = 2 as const;\nexport const CONTEXT_COMPACTION_AUTO_QUERY = \"auto-detected\" as const;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"context-compaction-types.js","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-types.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAU,CAAC;AA2E5D,MAAM,CAAC,MAAM,4CAA4C,GAAG,GAAY,CAAC;AACzE,MAAM,CAAC,MAAM,2CAA2C,GAAG,EAAW,CAAC;AACvE,MAAM,CAAC,MAAM,0CAA0C,GAAG,CAAU,CAAC;AACrE,MAAM,CAAC,MAAM,6BAA6B,GAAG,eAAwB,CAAC","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { ContextCompactionStats, ContextDeletionTarget, SessionEntry } from \"../session-manager.ts\";\nimport type { CompactionSettings } from \"./compaction.ts\";\n\nexport const CONTEXT_COMPACTION_PROMPT_VERSION = 1 as const;\n\nexport interface ContextCompactionParameters {\n\t/** Fraction of compactable context to keep. 0.3 is aggressive, 0.7 is light. */\n\tcompression_ratio: number;\n\t/** Number of recent context-eligible messages to preserve. */\n\tpreserve_recent: number;\n\t/** Focus query for relevance-based pruning. */\n\tquery: string;\n}\n\nexport interface ContextDeletionRequest {\n\tdeletions: Array<{\n\t\tkind: \"entry\" | \"content_block\";\n\t\tentryId: string;\n\t\tblockIndex?: number;\n\t}>;\n}\n\nexport interface CompactableContentBlock {\n\tentryId: string;\n\tblockIndex: number;\n\ttype: string;\n\ttext: string;\n\ttokenEstimate: number;\n\tprotected: boolean;\n\ttoolCallId?: string;\n}\n\nexport interface CompactableTranscriptEntry {\n\tentryId: string;\n\tentryType: SessionEntry[\"type\"];\n\trole: AgentMessage[\"role\"];\n\ttext: string;\n\ttokenEstimate: number;\n\tprotected: boolean;\n\tcontentBlocks: CompactableContentBlock[];\n\tmessage: AgentMessage;\n\ttoolCallIds: string[];\n\ttoolResultFor?: string;\n}\n\nexport interface CompactableTranscript {\n\tentries: CompactableTranscriptEntry[];\n\tprotectedEntryIds: string[];\n\ttokensBefore: number;\n\tsettings: CompactionSettings;\n\tparameters?: ContextCompactionParameters;\n}\n\nexport interface ContextCompactionPreparation {\n\ttranscript: CompactableTranscript;\n\tbranchEntries: SessionEntry[];\n\tparameters: ContextCompactionParameters;\n}\n\nexport interface ValidatedContextDeletionResult {\n\tdeletedTargets: ContextDeletionTarget[];\n\tprotectedEntryIds: string[];\n\tstats: ContextCompactionStats;\n}\n\nexport interface ContextCompactionResult extends ValidatedContextDeletionResult {\n\tpromptVersion: typeof CONTEXT_COMPACTION_PROMPT_VERSION;\n\tparameters: ContextCompactionParameters;\n\tbackupPath?: string;\n}\n\nexport interface ContextCompactionRunOptions {\n\tcontextWindow?: number;\n\tcompression_ratio?: number;\n\tpreserve_recent?: number;\n\tquery?: string;\n}\n\nexport const CONTEXT_COMPACTION_DEFAULT_COMPRESSION_RATIO = 0.5 as const;\nexport const CONTEXT_COMPACTION_TARGET_REDUCTION_PERCENT = 50 as const;\nexport const CONTEXT_COMPACTION_DEFAULT_PRESERVE_RECENT = 2 as const;\nexport const CONTEXT_COMPACTION_AUTO_QUERY = \"auto-detected\" as const;\n"]}
1
+ {"version":3,"file":"context-compaction-types.js","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-types.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAU,CAAC;AA6E5D,MAAM,CAAC,MAAM,4CAA4C,GAAG,GAAY,CAAC;AACzE,MAAM,CAAC,MAAM,2CAA2C,GAAG,EAAW,CAAC;AACvE,MAAM,CAAC,MAAM,0CAA0C,GAAG,CAAU,CAAC;AACrE,MAAM,CAAC,MAAM,6BAA6B,GAAG,eAAwB,CAAC","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { ContextCompactionStats, ContextDeletionTarget, SessionEntry } from \"../session-manager.ts\";\nimport type { CompactionSettings } from \"./compaction.ts\";\n\nexport const CONTEXT_COMPACTION_PROMPT_VERSION = 1 as const;\n\nexport interface ContextCompactionParameters {\n\t/** Fraction of compactable context to keep. 0.3 is aggressive, 0.7 is light. */\n\tcompression_ratio: number;\n\t/** Number of recent context-eligible messages to preserve. */\n\tpreserve_recent: number;\n\t/** Focus query for relevance-based pruning. */\n\tquery: string;\n}\n\nexport interface ContextDeletionRequest {\n\tdeletions: Array<{\n\t\tkind: \"entry\" | \"content_block\";\n\t\tentryId: string;\n\t\tblockIndex?: number;\n\t}>;\n}\n\nexport interface CompactableContentBlock {\n\tentryId: string;\n\tblockIndex: number;\n\ttype: string;\n\ttext: string;\n\ttokenEstimate: number;\n\tprotected: boolean;\n\t/** Visibility computed from the raw durable block before transcript display normalization. */\n\tllmVisible?: boolean;\n\ttoolCallId?: string;\n}\n\nexport interface CompactableTranscriptEntry {\n\tentryId: string;\n\tentryType: SessionEntry[\"type\"];\n\trole: AgentMessage[\"role\"];\n\ttext: string;\n\ttokenEstimate: number;\n\tprotected: boolean;\n\tcontentBlocks: CompactableContentBlock[];\n\tmessage: AgentMessage;\n\ttoolCallIds: string[];\n\ttoolResultFor?: string;\n}\n\nexport interface CompactableTranscript {\n\tentries: CompactableTranscriptEntry[];\n\tprotectedEntryIds: string[];\n\ttokensBefore: number;\n\tsettings: CompactionSettings;\n\tparameters?: ContextCompactionParameters;\n}\n\nexport interface ContextCompactionPreparation {\n\ttranscript: CompactableTranscript;\n\tbranchEntries: SessionEntry[];\n\tparameters: ContextCompactionParameters;\n}\n\nexport interface ValidatedContextDeletionResult {\n\tdeletedTargets: ContextDeletionTarget[];\n\tprotectedEntryIds: string[];\n\tstats: ContextCompactionStats;\n}\n\nexport interface ContextCompactionResult extends ValidatedContextDeletionResult {\n\tpromptVersion: typeof CONTEXT_COMPACTION_PROMPT_VERSION;\n\tparameters: ContextCompactionParameters;\n\tbackupPath?: string;\n}\n\nexport interface ContextCompactionRunOptions {\n\tcontextWindow?: number;\n\tcompression_ratio?: number;\n\tpreserve_recent?: number;\n\tquery?: string;\n}\n\nexport const CONTEXT_COMPACTION_DEFAULT_COMPRESSION_RATIO = 0.5 as const;\nexport const CONTEXT_COMPACTION_TARGET_REDUCTION_PERCENT = 50 as const;\nexport const CONTEXT_COMPACTION_DEFAULT_PRESERVE_RECENT = 2 as const;\nexport const CONTEXT_COMPACTION_AUTO_QUERY = \"auto-detected\" as const;\n"]}
@@ -1,12 +1,13 @@
1
1
  import type { ContextCompactionStats, ContextDeletionTarget } from "../session-manager.ts";
2
2
  import type { CompactableTranscript, ContextDeletionRequest, ValidatedContextDeletionResult } from "./context-compaction-types.ts";
3
+ export declare function reconcileToolDependencies(transcript: CompactableTranscript, initialTargets: readonly ContextDeletionTarget[]): ContextDeletionTarget[];
3
4
  export declare function computeContextCompactionStats(transcript: CompactableTranscript, targets: readonly ContextDeletionTarget[]): ContextCompactionStats;
4
5
  /**
5
- * An entry "bears task context" when it carries the user's intent for the session: a real `user`
6
- * message, an extension-injected `custom` message, or a branch summary (`branchSummary` role /
7
- * `branch_summary` entry type) that recaps an earlier branch's task.
6
+ * A provider-visible task entry carries session intent through a real `user` message,
7
+ * extension-injected `custom` message, or branch summary. Proposed block deletions count,
8
+ * so an entry with only omitted whitespace remaining cannot satisfy the task floor.
8
9
  *
9
- * Verbatim compaction must always leave at least one task-bearing entry in context.
10
+ * Verbatim compaction must always leave at least one provider-visible task entry in context.
10
11
  */
11
12
  export declare function validateContextDeletionRequest(request: ContextDeletionRequest, transcript: CompactableTranscript): ValidatedContextDeletionResult;
12
13
  export declare function contextDeletionRequestFromObject(value: unknown, source: string): ContextDeletionRequest;
@@ -1 +1 @@
1
- {"version":3,"file":"context-deletion-application.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-application.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,KAAK,EACX,qBAAqB,EAErB,sBAAsB,EACtB,8BAA8B,EAC9B,MAAM,+BAA+B,CAAC;AAyKvC,wBAAgB,6BAA6B,CAC5C,UAAU,EAAE,qBAAqB,EACjC,OAAO,EAAE,SAAS,qBAAqB,EAAE,GACvC,sBAAsB,CAmCxB;AAED;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC7C,OAAO,EAAE,sBAAsB,EAC/B,UAAU,EAAE,qBAAqB,GAC/B,8BAA8B,CAsGhC;AAED,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,sBAAsB,CAKvG","sourcesContent":["import type { ContextCompactionStats, ContextDeletionTarget } from \"../session-manager.ts\";\nimport type {\n\tCompactableTranscript,\n\tCompactableTranscriptEntry,\n\tContextDeletionRequest,\n\tValidatedContextDeletionResult,\n} from \"./context-compaction-types.ts\";\nimport { assistantEntryHasThinkingContentBlock } from \"./context-transcript-analysis.ts\";\nimport {\n\taddToolCallDeletion,\n\tassertIdOnlyDeletionTarget,\n\tassertNoAssistantThinkingContentBlockDeletionTargets,\n\tassertNoLatestAssistantThinkingDeletionTargets,\n\tassertNoRecentContextDeletionTargets,\n\tcanonicalizeEntryTargets,\n\tcanDeleteTarget,\n\tdeleteEntryTarget,\n\tfirstToolCallBlockTarget,\n\tformatProtectedDeletionError,\n\tformatProtectedToolDependencyError,\n\tformatRecentContextDeletionError,\n\tgetDeletedContentBlocks,\n\tgetDeletedEntryIds,\n\tgetRecentContextEntryIds,\n\tisRecentTarget,\n\tisTaskBearingEntry,\n\tisToolCallBlockDeleted,\n\tnormalizeRawTarget,\n\trawTargetKey,\n\ttargetKey,\n} from \"./context-deletion-targets.ts\";\n\nlet warnedReconciliationNonConvergence = false;\n\nfunction reconcileToolDependencies(\n\ttranscript: CompactableTranscript,\n\tinitialTargets: readonly ContextDeletionTarget[],\n): ContextDeletionTarget[] {\n\tconst targets = [...initialTargets];\n\tconst callEntries = new Map<string, CompactableTranscriptEntry>();\n\tconst entriesWithToolCalls = new Set<CompactableTranscriptEntry>();\n\tconst resultEntries = new Map<string, CompactableTranscriptEntry[]>();\n\n\tfor (const entry of transcript.entries) {\n\t\tfor (const callId of entry.toolCallIds) {\n\t\t\tcallEntries.set(callId, entry);\n\t\t\tentriesWithToolCalls.add(entry);\n\t\t}\n\t\tif (entry.toolResultFor) {\n\t\t\tconst results = resultEntries.get(entry.toolResultFor) ?? [];\n\t\t\tresults.push(entry);\n\t\t\tresultEntries.set(entry.toolResultFor, results);\n\t\t}\n\t}\n\n\t// Bounded fixpoint repair: each pass can add/remove paired call/result targets. In practice this\n\t// converges within one or two passes; the cap protects against accidental oscillation.\n\tlet changed = true;\n\tlet remainingPasses = Math.max(1, transcript.entries.length * 2);\n\twhile (changed && remainingPasses > 0) {\n\t\tchanged = false;\n\t\tremainingPasses -= 1;\n\t\tlet deletedEntryIds = getDeletedEntryIds(targets);\n\t\tlet deletedContentBlocks = getDeletedContentBlocks(targets);\n\t\tconst recordChange = (nextChanged: boolean): void => {\n\t\t\tif (!nextChanged) return;\n\t\t\tchanged = true;\n\t\t\tdeletedEntryIds = getDeletedEntryIds(targets);\n\t\t\tdeletedContentBlocks = getDeletedContentBlocks(targets);\n\t\t};\n\n\t\tfor (const [callId, callEntry] of callEntries) {\n\t\t\tconst callDeleted = isToolCallBlockDeleted(callEntry, callId, deletedEntryIds, deletedContentBlocks);\n\t\t\tconst results = resultEntries.get(callId) ?? [];\n\n\t\t\tif (callDeleted) {\n\t\t\t\tconst retainedProtectedResult = results.find(\n\t\t\t\t\t(entry) =>\n\t\t\t\t\t\t!deletedEntryIds.has(entry.entryId) &&\n\t\t\t\t\t\t!canDeleteTarget(transcript, { kind: \"entry\", entryId: entry.entryId }),\n\t\t\t\t);\n\t\t\t\tif (retainedProtectedResult) {\n\t\t\t\t\tconst retainedResultTarget: ContextDeletionTarget = { kind: \"entry\", entryId: retainedProtectedResult.entryId };\n\t\t\t\t\tif (isRecentTarget(transcript, retainedResultTarget)) {\n\t\t\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, retainedResultTarget));\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tformatProtectedToolDependencyError(\n\t\t\t\t\t\t\ttranscript,\n\t\t\t\t\t\t\tretainedResultTarget,\n\t\t\t\t\t\t\t`Cannot delete tool call ${callId} because its paired tool result entry ${retainedProtectedResult.entryId} is protected.`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tfor (const result of results) {\n\t\t\t\t\t\trecordChange(deleteEntryTarget(targets, result.entryId));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isToolCallBlockDeleted(callEntry, callId, deletedEntryIds, deletedContentBlocks)) continue;\n\n\t\t\tfor (const result of results) {\n\t\t\t\tif (!deletedEntryIds.has(result.entryId)) continue;\n\t\t\t\trecordChange(deleteEntryTarget(targets, result.entryId));\n\t\t\t\tconst callEntryTarget: ContextDeletionTarget = { kind: \"entry\", entryId: callEntry.entryId };\n\t\t\t\tconst callBlockTarget = assistantEntryHasThinkingContentBlock(callEntry)\n\t\t\t\t\t? callEntryTarget\n\t\t\t\t\t: firstToolCallBlockTarget(callEntry, callId) ?? callEntryTarget;\n\t\t\t\tif (!canDeleteTarget(transcript, callBlockTarget)) {\n\t\t\t\t\tif (isRecentTarget(transcript, callBlockTarget)) {\n\t\t\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, callBlockTarget));\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tformatProtectedToolDependencyError(\n\t\t\t\t\t\t\ttranscript,\n\t\t\t\t\t\t\tcallBlockTarget,\n\t\t\t\t\t\t\t`Cannot delete tool result entry ${result.entryId} because that would require deleting protected tool block for tool call ${callId}.`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\trecordChange(addToolCallDeletion(transcript, targets, callEntry, callId));\n\t\t\t}\n\t\t}\n\n\t\tfor (const entry of entriesWithToolCalls) {\n\t\t\trecordChange(canonicalizeEntryTargets(transcript, targets, entry));\n\t\t}\n\t}\n\n\tif (changed && !warnedReconciliationNonConvergence) {\n\t\twarnedReconciliationNonConvergence = true;\n\t\tconsole.warn(\n\t\t\t`Context compaction tool dependency reconciliation did not converge within the bounded pass limit; validation will continue with the last reconciled target set. entries=${transcript.entries.length} callEntries=${callEntries.size} targets=${targets.length}`,\n\t\t);\n\t}\n\n\treturn targets;\n}\n\nfunction validateToolDependencies(transcript: CompactableTranscript, targets: readonly ContextDeletionTarget[]): void {\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tconst deletedContentBlocks = getDeletedContentBlocks(targets);\n\tconst callEntries = new Map<string, CompactableTranscriptEntry>();\n\tconst resultEntries = new Map<string, CompactableTranscriptEntry[]>();\n\n\tfor (const entry of transcript.entries) {\n\t\tfor (const callId of entry.toolCallIds) {\n\t\t\tcallEntries.set(callId, entry);\n\t\t}\n\t\tif (entry.toolResultFor) {\n\t\t\tconst results = resultEntries.get(entry.toolResultFor) ?? [];\n\t\t\tresults.push(entry);\n\t\t\tresultEntries.set(entry.toolResultFor, results);\n\t\t}\n\t}\n\n\tfor (const [callId, callEntry] of callEntries) {\n\t\tconst callDeleted = isToolCallBlockDeleted(callEntry, callId, deletedEntryIds, deletedContentBlocks);\n\t\tconst results = resultEntries.get(callId) ?? [];\n\t\tif (callDeleted) {\n\t\t\tconst danglingResult = results.find((entry) => !deletedEntryIds.has(entry.entryId));\n\t\t\tif (danglingResult) {\n\t\t\t\tthrow new Error(`Deleting tool call ${callId} would leave tool result entry ${danglingResult.entryId} orphaned`);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst deletedResult = results.find((entry) => deletedEntryIds.has(entry.entryId));\n\t\tif (deletedResult) {\n\t\t\tthrow new Error(`Deleting tool result entry ${deletedResult.entryId} would leave tool call ${callId} dangling`);\n\t\t}\n\t}\n}\n\nexport function computeContextCompactionStats(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): ContextCompactionStats {\n\tconst entryById = new Map(transcript.entries.map((entry) => [entry.entryId, entry]));\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tlet deletedTokens = 0;\n\tlet objectsDeleted = 0;\n\n\tfor (const entryId of deletedEntryIds) {\n\t\tconst entry = entryById.get(entryId);\n\t\tif (!entry) continue;\n\t\tdeletedTokens += entry.tokenEstimate;\n\t\tobjectsDeleted += 1 + entry.contentBlocks.length;\n\t}\n\n\tfor (const target of targets) {\n\t\tif (target.kind !== \"content_block\" || deletedEntryIds.has(target.entryId)) continue;\n\t\tconst entry = entryById.get(target.entryId);\n\t\tif (!entry) continue;\n\t\tconst block = entry.contentBlocks.find((item) => item.blockIndex === target.blockIndex);\n\t\tif (!block) continue;\n\t\tdeletedTokens += block.tokenEstimate;\n\t\tobjectsDeleted += 1;\n\t}\n\n\tconst objectsBefore = transcript.entries.length + transcript.entries.reduce((total, entry) => total + entry.contentBlocks.length, 0);\n\tconst tokensBefore = transcript.tokensBefore;\n\tconst tokensAfter = Math.max(0, tokensBefore - deletedTokens);\n\tconst percentReduction = tokensBefore > 0 ? Math.round(((tokensBefore - tokensAfter) / tokensBefore) * 1000) / 10 : 0;\n\treturn {\n\t\tobjectsBefore,\n\t\tobjectsAfter: Math.max(0, objectsBefore - objectsDeleted),\n\t\tobjectsDeleted,\n\t\ttokensBefore,\n\t\ttokensAfter,\n\t\tpercentReduction,\n\t};\n}\n\n/**\n * An entry \"bears task context\" when it carries the user's intent for the session: a real `user`\n * message, an extension-injected `custom` message, or a branch summary (`branchSummary` role /\n * `branch_summary` entry type) that recaps an earlier branch's task.\n *\n * Verbatim compaction must always leave at least one task-bearing entry in context.\n */\nexport function validateContextDeletionRequest(\n\trequest: ContextDeletionRequest,\n\ttranscript: CompactableTranscript,\n): ValidatedContextDeletionResult {\n\tif (!request || typeof request !== \"object\" || !Array.isArray(request.deletions)) {\n\t\tthrow new Error(\"Context deletion request must be an object with a deletions array\");\n\t}\n\n\tconst entryById = new Map(transcript.entries.map((entry) => [entry.entryId, entry]));\n\tconst recentEntryIds = getRecentContextEntryIds(transcript);\n\tconst seen = new Set<string>();\n\tconst deletedTargets: ContextDeletionTarget[] = [];\n\n\tfor (const deletion of request.deletions) {\n\t\tif (!deletion || typeof deletion !== \"object\") {\n\t\t\tthrow new Error(\"Deletion target must be an object\");\n\t\t}\n\t\tif (deletion.kind !== \"entry\" && deletion.kind !== \"content_block\") {\n\t\t\tthrow new Error(`Unsupported deletion target kind: ${String((deletion as { kind?: unknown }).kind)}`);\n\t\t}\n\t\tassertIdOnlyDeletionTarget(deletion as Record<string, unknown>);\n\t\tif (typeof deletion.entryId !== \"string\" || deletion.entryId.length === 0) {\n\t\t\tthrow new Error(\"Deletion target entryId must be a non-empty string\");\n\t\t}\n\t\tconst entry = entryById.get(deletion.entryId);\n\t\tif (!entry) {\n\t\t\tthrow new Error(`Unknown deletion target entryId: ${deletion.entryId}`);\n\t\t}\n\t\tconst normalized = normalizeRawTarget(deletion);\n\t\tif (deletion.kind === \"entry\") {\n\t\t\tif (recentEntryIds.has(deletion.entryId)) {\n\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, normalized));\n\t\t\t}\n\t\t\tif (!canDeleteTarget(transcript, normalized)) {\n\t\t\t\tthrow new Error(formatProtectedDeletionError(transcript, normalized));\n\t\t\t}\n\t\t}\n\t\tif (deletion.kind === \"content_block\") {\n\t\t\tif (typeof deletion.blockIndex !== \"number\" || !Number.isInteger(deletion.blockIndex) || deletion.blockIndex < 0) {\n\t\t\t\tthrow new Error(`Invalid content block index for entry ${deletion.entryId}`);\n\t\t\t}\n\t\t\tif (recentEntryIds.has(deletion.entryId)) {\n\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, normalized));\n\t\t\t}\n\t\t\tconst block = entry.contentBlocks.find((item) => item.blockIndex === deletion.blockIndex);\n\t\t\tif (!block) {\n\t\t\t\tif (entry.protected) {\n\t\t\t\t\tthrow new Error(formatProtectedDeletionError(transcript, normalized));\n\t\t\t\t}\n\t\t\t\tthrow new Error(`Unknown content block ${deletion.blockIndex} for entry ${deletion.entryId}`);\n\t\t\t}\n\t\t\tif (!canDeleteTarget(transcript, normalized)) {\n\t\t\t\tthrow new Error(formatProtectedDeletionError(transcript, normalized));\n\t\t\t}\n\t\t\tif (entry.contentBlocks.length <= 1) {\n\t\t\t\tthrow new Error(`Deleting the only content block of ${deletion.entryId} must be an entry deletion`);\n\t\t\t}\n\t\t}\n\n\t\tconst key = rawTargetKey(deletion);\n\t\tif (seen.has(key)) {\n\t\t\tthrow new Error(`Duplicate deletion target: ${key}`);\n\t\t}\n\t\tseen.add(key);\n\t\tdeletedTargets.push(normalized);\n\t}\n\n\tconst reconciledTargets = reconcileToolDependencies(transcript, deletedTargets);\n\t// Tool reconciliation can add targets after the per-request checks above, so\n\t// these post-reconcile assertions remain authoritative.\n\tassertNoRecentContextDeletionTargets(transcript, reconciledTargets);\n\tassertNoAssistantThinkingContentBlockDeletionTargets(transcript, reconciledTargets);\n\tassertNoLatestAssistantThinkingDeletionTargets(transcript, reconciledTargets);\n\tconst reconciledDeletedEntryIds = getDeletedEntryIds(reconciledTargets);\n\n\tfor (const target of reconciledTargets) {\n\t\tif (target.kind === \"content_block\" && reconciledDeletedEntryIds.has(target.entryId)) {\n\t\t\tthrow new Error(`Deletion target ${targetKey(target)} overlaps with entry deletion`);\n\t\t}\n\t}\n\n\tconst deletedContentBlocks = getDeletedContentBlocks(reconciledTargets);\n\tfor (const [entryId, blockIndexes] of deletedContentBlocks) {\n\t\tconst entry = entryById.get(entryId);\n\t\tif (entry?.contentBlocks.every((block) => blockIndexes.has(block.blockIndex))) {\n\t\t\tthrow new Error(`Content-block deletions for ${entryId} would remove every content block`);\n\t\t}\n\t}\n\n\tvalidateToolDependencies(transcript, reconciledTargets);\n\n\tconst remainingEntries = transcript.entries.filter((entry) => !reconciledDeletedEntryIds.has(entry.entryId));\n\tif (remainingEntries.length === 0) {\n\t\tthrow new Error(\"Deletion request would remove all context entries\");\n\t}\n\tconst hasTaskBearingContext = remainingEntries.some(isTaskBearingEntry);\n\tif (!hasTaskBearingContext) {\n\t\tthrow new Error(\"Deletion request would leave no user task in context\");\n\t}\n\n\treturn {\n\t\tdeletedTargets: reconciledTargets,\n\t\tprotectedEntryIds: [...transcript.protectedEntryIds],\n\t\tstats: computeContextCompactionStats(transcript, reconciledTargets),\n\t};\n}\n\nexport function contextDeletionRequestFromObject(value: unknown, source: string): ContextDeletionRequest {\n\tif (!value || typeof value !== \"object\" || !Array.isArray((value as { deletions?: unknown }).deletions)) {\n\t\tthrow new Error(`${source} must contain a deletions array`);\n\t}\n\treturn value as ContextDeletionRequest;\n}\n\n"]}
1
+ {"version":3,"file":"context-deletion-application.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-application.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,KAAK,EACX,qBAAqB,EAErB,sBAAsB,EACtB,8BAA8B,EAC9B,MAAM,+BAA+B,CAAC;AA4BvC,wBAAgB,yBAAyB,CACxC,UAAU,EAAE,qBAAqB,EACjC,cAAc,EAAE,SAAS,qBAAqB,EAAE,GAC9C,qBAAqB,EAAE,CAqGzB;AAqCD,wBAAgB,6BAA6B,CAC5C,UAAU,EAAE,qBAAqB,EACjC,OAAO,EAAE,SAAS,qBAAqB,EAAE,GACvC,sBAAsB,CAsCxB;AAED;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC7C,OAAO,EAAE,sBAAsB,EAC/B,UAAU,EAAE,qBAAqB,GAC/B,8BAA8B,CAwGhC;AAED,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,sBAAsB,CAKvG","sourcesContent":["import type { ContextCompactionStats, ContextDeletionTarget } from \"../session-manager.ts\";\nimport type {\n\tCompactableTranscript,\n\tCompactableTranscriptEntry,\n\tContextDeletionRequest,\n\tValidatedContextDeletionResult,\n} from \"./context-compaction-types.ts\";\nimport { assistantEntryHasThinkingContentBlock } from \"./context-assistant-turns.js\";\nimport {\n\taddToolCallDeletion,\n\tassertIdOnlyDeletionTarget,\n\tassertNoAssistantThinkingContentBlockDeletionTargets,\n\tassertNoLatestAssistantThinkingDeletionTargets,\n\tassertNoRecentContextDeletionTargets,\n\tcanonicalizeEntryTargets,\n\tcanDeleteTarget,\n\tdeleteEntryTarget,\n\tfirstToolCallBlockTarget,\n\tformatProtectedDeletionError,\n\tformatProtectedToolDependencyError,\n\tformatRecentContextDeletionError,\n\tgetDeletedContentBlocks,\n\tgetDeletedEntryIds,\n\tgetRecentContextEntryIds,\n\tisRecentTarget,\n\tisTaskBearingEntry,\n\tisToolCallBlockDeleted,\n\tnormalizeRawTarget,\n\trawTargetKey,\n\ttargetKey,\n} from \"./context-deletion-targets.ts\";\n\nlet warnedReconciliationNonConvergence = false;\n\nexport function reconcileToolDependencies(\n\ttranscript: CompactableTranscript,\n\tinitialTargets: readonly ContextDeletionTarget[],\n): ContextDeletionTarget[] {\n\tconst targets = [...initialTargets];\n\tconst callEntries = new Map<string, CompactableTranscriptEntry>();\n\tconst entriesWithToolCalls = new Set<CompactableTranscriptEntry>();\n\tconst resultEntries = new Map<string, CompactableTranscriptEntry[]>();\n\n\tfor (const entry of transcript.entries) {\n\t\tfor (const callId of entry.toolCallIds) {\n\t\t\tcallEntries.set(callId, entry);\n\t\t\tentriesWithToolCalls.add(entry);\n\t\t}\n\t\tif (entry.toolResultFor) {\n\t\t\tconst results = resultEntries.get(entry.toolResultFor) ?? [];\n\t\t\tresults.push(entry);\n\t\t\tresultEntries.set(entry.toolResultFor, results);\n\t\t}\n\t}\n\n\t// Bounded fixpoint repair: each pass can add/remove paired call/result targets. In practice this\n\t// converges within one or two passes; the cap protects against accidental oscillation.\n\tlet changed = true;\n\tlet remainingPasses = Math.max(1, transcript.entries.length * 2);\n\twhile (changed && remainingPasses > 0) {\n\t\tchanged = false;\n\t\tremainingPasses -= 1;\n\t\tlet deletedEntryIds = getDeletedEntryIds(targets);\n\t\tlet deletedContentBlocks = getDeletedContentBlocks(targets);\n\t\tconst recordChange = (nextChanged: boolean): void => {\n\t\t\tif (!nextChanged) return;\n\t\t\tchanged = true;\n\t\t\tdeletedEntryIds = getDeletedEntryIds(targets);\n\t\t\tdeletedContentBlocks = getDeletedContentBlocks(targets);\n\t\t};\n\n\t\tfor (const [callId, callEntry] of callEntries) {\n\t\t\tconst callDeleted = isToolCallBlockDeleted(callEntry, callId, deletedEntryIds, deletedContentBlocks);\n\t\t\tconst results = resultEntries.get(callId) ?? [];\n\n\t\t\tif (callDeleted) {\n\t\t\t\tconst retainedProtectedResult = results.find(\n\t\t\t\t\t(entry) =>\n\t\t\t\t\t\t!deletedEntryIds.has(entry.entryId) &&\n\t\t\t\t\t\t!canDeleteTarget(transcript, { kind: \"entry\", entryId: entry.entryId }),\n\t\t\t\t);\n\t\t\t\tif (retainedProtectedResult) {\n\t\t\t\t\tconst retainedResultTarget: ContextDeletionTarget = { kind: \"entry\", entryId: retainedProtectedResult.entryId };\n\t\t\t\t\tif (isRecentTarget(transcript, retainedResultTarget)) {\n\t\t\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, retainedResultTarget));\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tformatProtectedToolDependencyError(\n\t\t\t\t\t\t\ttranscript,\n\t\t\t\t\t\t\tretainedResultTarget,\n\t\t\t\t\t\t\t`Cannot delete tool call ${callId} because its paired tool result entry ${retainedProtectedResult.entryId} is protected.`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tfor (const result of results) {\n\t\t\t\t\t\trecordChange(deleteEntryTarget(targets, result.entryId));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isToolCallBlockDeleted(callEntry, callId, deletedEntryIds, deletedContentBlocks)) continue;\n\n\t\t\tfor (const result of results) {\n\t\t\t\tif (!deletedEntryIds.has(result.entryId)) continue;\n\t\t\t\trecordChange(deleteEntryTarget(targets, result.entryId));\n\t\t\t\tconst callEntryTarget: ContextDeletionTarget = { kind: \"entry\", entryId: callEntry.entryId };\n\t\t\t\tconst callBlockTarget = assistantEntryHasThinkingContentBlock(callEntry)\n\t\t\t\t\t? callEntryTarget\n\t\t\t\t\t: firstToolCallBlockTarget(callEntry, callId) ?? callEntryTarget;\n\t\t\t\tif (!canDeleteTarget(transcript, callBlockTarget)) {\n\t\t\t\t\tif (isRecentTarget(transcript, callBlockTarget)) {\n\t\t\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, callBlockTarget));\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tformatProtectedToolDependencyError(\n\t\t\t\t\t\t\ttranscript,\n\t\t\t\t\t\t\tcallBlockTarget,\n\t\t\t\t\t\t\t`Cannot delete tool result entry ${result.entryId} because that would require deleting protected tool block for tool call ${callId}.`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\trecordChange(addToolCallDeletion(transcript, targets, callEntry, callId));\n\t\t\t}\n\t\t}\n\n\t\tfor (const entry of entriesWithToolCalls) {\n\t\t\trecordChange(canonicalizeEntryTargets(transcript, targets, entry));\n\t\t}\n\t}\n\n\tif (changed && !warnedReconciliationNonConvergence) {\n\t\twarnedReconciliationNonConvergence = true;\n\t\tconsole.warn(\n\t\t\t`Context compaction tool dependency reconciliation did not converge within the bounded pass limit; validation will continue with the last reconciled target set. entries=${transcript.entries.length} callEntries=${callEntries.size} targets=${targets.length}`,\n\t\t);\n\t}\n\n\treturn targets;\n}\n\nfunction validateToolDependencies(transcript: CompactableTranscript, targets: readonly ContextDeletionTarget[]): void {\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tconst deletedContentBlocks = getDeletedContentBlocks(targets);\n\tconst callEntries = new Map<string, CompactableTranscriptEntry>();\n\tconst resultEntries = new Map<string, CompactableTranscriptEntry[]>();\n\n\tfor (const entry of transcript.entries) {\n\t\tfor (const callId of entry.toolCallIds) {\n\t\t\tcallEntries.set(callId, entry);\n\t\t}\n\t\tif (entry.toolResultFor) {\n\t\t\tconst results = resultEntries.get(entry.toolResultFor) ?? [];\n\t\t\tresults.push(entry);\n\t\t\tresultEntries.set(entry.toolResultFor, results);\n\t\t}\n\t}\n\n\tfor (const [callId, callEntry] of callEntries) {\n\t\tconst callDeleted = isToolCallBlockDeleted(callEntry, callId, deletedEntryIds, deletedContentBlocks);\n\t\tconst results = resultEntries.get(callId) ?? [];\n\t\tif (callDeleted) {\n\t\t\tconst danglingResult = results.find((entry) => !deletedEntryIds.has(entry.entryId));\n\t\t\tif (danglingResult) {\n\t\t\t\tthrow new Error(`Deleting tool call ${callId} would leave tool result entry ${danglingResult.entryId} orphaned`);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst deletedResult = results.find((entry) => deletedEntryIds.has(entry.entryId));\n\t\tif (deletedResult) {\n\t\t\tthrow new Error(`Deleting tool result entry ${deletedResult.entryId} would leave tool call ${callId} dangling`);\n\t\t}\n\t}\n}\n\nexport function computeContextCompactionStats(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): ContextCompactionStats {\n\tconst entryById = new Map(transcript.entries.map((entry) => [entry.entryId, entry]));\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tlet deletedTokens = 0;\n\tlet objectsDeleted = 0;\n\n\tfor (const entryId of deletedEntryIds) {\n\t\tconst entry = entryById.get(entryId);\n\t\tif (!entry) continue;\n\t\tdeletedTokens += entry.tokenEstimate;\n\t\tobjectsDeleted += 1 + entry.contentBlocks.length;\n\t}\n\n\tconst deletedContentBlocks = getDeletedContentBlocks(targets);\n\tfor (const [entryId, blockIndexes] of deletedContentBlocks) {\n\t\tif (deletedEntryIds.has(entryId)) continue;\n\t\tconst entry = entryById.get(entryId);\n\t\tif (!entry) continue;\n\t\tconst deletedBlocks = entry.contentBlocks.filter((block) => blockIndexes.has(block.blockIndex));\n\t\tobjectsDeleted += deletedBlocks.length;\n\t\tdeletedTokens +=\n\t\t\tisTaskBearingEntry(entry) && !isTaskBearingEntry(entry, blockIndexes)\n\t\t\t\t? entry.tokenEstimate\n\t\t\t\t: deletedBlocks.reduce((total, block) => total + block.tokenEstimate, 0);\n\t}\n\n\tconst objectsBefore = transcript.entries.length + transcript.entries.reduce((total, entry) => total + entry.contentBlocks.length, 0);\n\tconst tokensBefore = transcript.tokensBefore;\n\tconst tokensAfter = Math.max(0, tokensBefore - deletedTokens);\n\tconst percentReduction = tokensBefore > 0 ? Math.round(((tokensBefore - tokensAfter) / tokensBefore) * 1000) / 10 : 0;\n\treturn {\n\t\tobjectsBefore,\n\t\tobjectsAfter: Math.max(0, objectsBefore - objectsDeleted),\n\t\tobjectsDeleted,\n\t\ttokensBefore,\n\t\ttokensAfter,\n\t\tpercentReduction,\n\t};\n}\n\n/**\n * A provider-visible task entry carries session intent through a real `user` message,\n * extension-injected `custom` message, or branch summary. Proposed block deletions count,\n * so an entry with only omitted whitespace remaining cannot satisfy the task floor.\n *\n * Verbatim compaction must always leave at least one provider-visible task entry in context.\n */\nexport function validateContextDeletionRequest(\n\trequest: ContextDeletionRequest,\n\ttranscript: CompactableTranscript,\n): ValidatedContextDeletionResult {\n\tif (!request || typeof request !== \"object\" || !Array.isArray(request.deletions)) {\n\t\tthrow new Error(\"Context deletion request must be an object with a deletions array\");\n\t}\n\n\tconst entryById = new Map(transcript.entries.map((entry) => [entry.entryId, entry]));\n\tconst recentEntryIds = getRecentContextEntryIds(transcript);\n\tconst seen = new Set<string>();\n\tconst deletedTargets: ContextDeletionTarget[] = [];\n\n\tfor (const deletion of request.deletions) {\n\t\tif (!deletion || typeof deletion !== \"object\") {\n\t\t\tthrow new Error(\"Deletion target must be an object\");\n\t\t}\n\t\tif (deletion.kind !== \"entry\" && deletion.kind !== \"content_block\") {\n\t\t\tthrow new Error(`Unsupported deletion target kind: ${String((deletion as { kind?: unknown }).kind)}`);\n\t\t}\n\t\tassertIdOnlyDeletionTarget(deletion as Record<string, unknown>);\n\t\tif (typeof deletion.entryId !== \"string\" || deletion.entryId.length === 0) {\n\t\t\tthrow new Error(\"Deletion target entryId must be a non-empty string\");\n\t\t}\n\t\tconst entry = entryById.get(deletion.entryId);\n\t\tif (!entry) {\n\t\t\tthrow new Error(`Unknown deletion target entryId: ${deletion.entryId}`);\n\t\t}\n\t\tconst normalized = normalizeRawTarget(deletion);\n\t\tif (deletion.kind === \"entry\") {\n\t\t\tif (recentEntryIds.has(deletion.entryId)) {\n\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, normalized));\n\t\t\t}\n\t\t\tif (!canDeleteTarget(transcript, normalized)) {\n\t\t\t\tthrow new Error(formatProtectedDeletionError(transcript, normalized));\n\t\t\t}\n\t\t}\n\t\tif (deletion.kind === \"content_block\") {\n\t\t\tif (typeof deletion.blockIndex !== \"number\" || !Number.isInteger(deletion.blockIndex) || deletion.blockIndex < 0) {\n\t\t\t\tthrow new Error(`Invalid content block index for entry ${deletion.entryId}`);\n\t\t\t}\n\t\t\tif (recentEntryIds.has(deletion.entryId)) {\n\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, normalized));\n\t\t\t}\n\t\t\tconst block = entry.contentBlocks.find((item) => item.blockIndex === deletion.blockIndex);\n\t\t\tif (!block) {\n\t\t\t\tif (entry.protected) {\n\t\t\t\t\tthrow new Error(formatProtectedDeletionError(transcript, normalized));\n\t\t\t\t}\n\t\t\t\tthrow new Error(`Unknown content block ${deletion.blockIndex} for entry ${deletion.entryId}`);\n\t\t\t}\n\t\t\tif (!canDeleteTarget(transcript, normalized)) {\n\t\t\t\tthrow new Error(formatProtectedDeletionError(transcript, normalized));\n\t\t\t}\n\t\t\tif (entry.contentBlocks.length <= 1) {\n\t\t\t\tthrow new Error(`Deleting the only content block of ${deletion.entryId} must be an entry deletion`);\n\t\t\t}\n\t\t}\n\n\t\tconst key = rawTargetKey(deletion);\n\t\tif (seen.has(key)) {\n\t\t\tthrow new Error(`Duplicate deletion target: ${key}`);\n\t\t}\n\t\tseen.add(key);\n\t\tdeletedTargets.push(normalized);\n\t}\n\n\tconst reconciledTargets = reconcileToolDependencies(transcript, deletedTargets);\n\t// Tool reconciliation can add targets after the per-request checks above, so\n\t// these post-reconcile assertions remain authoritative.\n\tassertNoRecentContextDeletionTargets(transcript, reconciledTargets);\n\tassertNoAssistantThinkingContentBlockDeletionTargets(transcript, reconciledTargets);\n\tassertNoLatestAssistantThinkingDeletionTargets(transcript, reconciledTargets);\n\tconst reconciledDeletedEntryIds = getDeletedEntryIds(reconciledTargets);\n\n\tfor (const target of reconciledTargets) {\n\t\tif (target.kind === \"content_block\" && reconciledDeletedEntryIds.has(target.entryId)) {\n\t\t\tthrow new Error(`Deletion target ${targetKey(target)} overlaps with entry deletion`);\n\t\t}\n\t}\n\n\tconst deletedContentBlocks = getDeletedContentBlocks(reconciledTargets);\n\tfor (const [entryId, blockIndexes] of deletedContentBlocks) {\n\t\tconst entry = entryById.get(entryId);\n\t\tif (entry?.contentBlocks.every((block) => blockIndexes.has(block.blockIndex))) {\n\t\t\tthrow new Error(`Content-block deletions for ${entryId} would remove every content block`);\n\t\t}\n\t}\n\n\tvalidateToolDependencies(transcript, reconciledTargets);\n\n\tconst remainingEntries = transcript.entries.filter((entry) => !reconciledDeletedEntryIds.has(entry.entryId));\n\tif (remainingEntries.length === 0) {\n\t\tthrow new Error(\"Deletion request would remove all context entries\");\n\t}\n\tconst hasTaskBearingContext = remainingEntries.some((entry) =>\n\t\tisTaskBearingEntry(entry, deletedContentBlocks.get(entry.entryId)),\n\t);\n\tif (!hasTaskBearingContext) {\n\t\tthrow new Error(\"Deletion request would leave no user task in context\");\n\t}\n\n\treturn {\n\t\tdeletedTargets: reconciledTargets,\n\t\tprotectedEntryIds: [...transcript.protectedEntryIds],\n\t\tstats: computeContextCompactionStats(transcript, reconciledTargets),\n\t};\n}\n\nexport function contextDeletionRequestFromObject(value: unknown, source: string): ContextDeletionRequest {\n\tif (!value || typeof value !== \"object\" || !Array.isArray((value as { deletions?: unknown }).deletions)) {\n\t\tthrow new Error(`${source} must contain a deletions array`);\n\t}\n\treturn value as ContextDeletionRequest;\n}\n\n"]}
@@ -1,7 +1,7 @@
1
- import { assistantEntryHasThinkingContentBlock } from "./context-transcript-analysis.js";
1
+ import { assistantEntryHasThinkingContentBlock } from "./context-assistant-turns.js";
2
2
  import { addToolCallDeletion, assertIdOnlyDeletionTarget, assertNoAssistantThinkingContentBlockDeletionTargets, assertNoLatestAssistantThinkingDeletionTargets, assertNoRecentContextDeletionTargets, canonicalizeEntryTargets, canDeleteTarget, deleteEntryTarget, firstToolCallBlockTarget, formatProtectedDeletionError, formatProtectedToolDependencyError, formatRecentContextDeletionError, getDeletedContentBlocks, getDeletedEntryIds, getRecentContextEntryIds, isRecentTarget, isTaskBearingEntry, isToolCallBlockDeleted, normalizeRawTarget, rawTargetKey, targetKey, } from "./context-deletion-targets.js";
3
3
  let warnedReconciliationNonConvergence = false;
4
- function reconcileToolDependencies(transcript, initialTargets) {
4
+ export function reconcileToolDependencies(transcript, initialTargets) {
5
5
  const targets = [...initialTargets];
6
6
  const callEntries = new Map();
7
7
  const entriesWithToolCalls = new Set();
@@ -124,17 +124,19 @@ export function computeContextCompactionStats(transcript, targets) {
124
124
  deletedTokens += entry.tokenEstimate;
125
125
  objectsDeleted += 1 + entry.contentBlocks.length;
126
126
  }
127
- for (const target of targets) {
128
- if (target.kind !== "content_block" || deletedEntryIds.has(target.entryId))
127
+ const deletedContentBlocks = getDeletedContentBlocks(targets);
128
+ for (const [entryId, blockIndexes] of deletedContentBlocks) {
129
+ if (deletedEntryIds.has(entryId))
129
130
  continue;
130
- const entry = entryById.get(target.entryId);
131
+ const entry = entryById.get(entryId);
131
132
  if (!entry)
132
133
  continue;
133
- const block = entry.contentBlocks.find((item) => item.blockIndex === target.blockIndex);
134
- if (!block)
135
- continue;
136
- deletedTokens += block.tokenEstimate;
137
- objectsDeleted += 1;
134
+ const deletedBlocks = entry.contentBlocks.filter((block) => blockIndexes.has(block.blockIndex));
135
+ objectsDeleted += deletedBlocks.length;
136
+ deletedTokens +=
137
+ isTaskBearingEntry(entry) && !isTaskBearingEntry(entry, blockIndexes)
138
+ ? entry.tokenEstimate
139
+ : deletedBlocks.reduce((total, block) => total + block.tokenEstimate, 0);
138
140
  }
139
141
  const objectsBefore = transcript.entries.length + transcript.entries.reduce((total, entry) => total + entry.contentBlocks.length, 0);
140
142
  const tokensBefore = transcript.tokensBefore;
@@ -150,11 +152,11 @@ export function computeContextCompactionStats(transcript, targets) {
150
152
  };
151
153
  }
152
154
  /**
153
- * An entry "bears task context" when it carries the user's intent for the session: a real `user`
154
- * message, an extension-injected `custom` message, or a branch summary (`branchSummary` role /
155
- * `branch_summary` entry type) that recaps an earlier branch's task.
155
+ * A provider-visible task entry carries session intent through a real `user` message,
156
+ * extension-injected `custom` message, or branch summary. Proposed block deletions count,
157
+ * so an entry with only omitted whitespace remaining cannot satisfy the task floor.
156
158
  *
157
- * Verbatim compaction must always leave at least one task-bearing entry in context.
159
+ * Verbatim compaction must always leave at least one provider-visible task entry in context.
158
160
  */
159
161
  export function validateContextDeletionRequest(request, transcript) {
160
162
  if (!request || typeof request !== "object" || !Array.isArray(request.deletions)) {
@@ -240,7 +242,7 @@ export function validateContextDeletionRequest(request, transcript) {
240
242
  if (remainingEntries.length === 0) {
241
243
  throw new Error("Deletion request would remove all context entries");
242
244
  }
243
- const hasTaskBearingContext = remainingEntries.some(isTaskBearingEntry);
245
+ const hasTaskBearingContext = remainingEntries.some((entry) => isTaskBearingEntry(entry, deletedContentBlocks.get(entry.entryId)));
244
246
  if (!hasTaskBearingContext) {
245
247
  throw new Error("Deletion request would leave no user task in context");
246
248
  }
@@ -1 +1 @@
1
- {"version":3,"file":"context-deletion-application.js","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-application.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextCompactionStats, ContextDeletionTarget } from \"../session-manager.ts\";\nimport type {\n\tCompactableTranscript,\n\tCompactableTranscriptEntry,\n\tContextDeletionRequest,\n\tValidatedContextDeletionResult,\n} from \"./context-compaction-types.ts\";\nimport { assistantEntryHasThinkingContentBlock } from \"./context-transcript-analysis.ts\";\nimport {\n\taddToolCallDeletion,\n\tassertIdOnlyDeletionTarget,\n\tassertNoAssistantThinkingContentBlockDeletionTargets,\n\tassertNoLatestAssistantThinkingDeletionTargets,\n\tassertNoRecentContextDeletionTargets,\n\tcanonicalizeEntryTargets,\n\tcanDeleteTarget,\n\tdeleteEntryTarget,\n\tfirstToolCallBlockTarget,\n\tformatProtectedDeletionError,\n\tformatProtectedToolDependencyError,\n\tformatRecentContextDeletionError,\n\tgetDeletedContentBlocks,\n\tgetDeletedEntryIds,\n\tgetRecentContextEntryIds,\n\tisRecentTarget,\n\tisTaskBearingEntry,\n\tisToolCallBlockDeleted,\n\tnormalizeRawTarget,\n\trawTargetKey,\n\ttargetKey,\n} from \"./context-deletion-targets.ts\";\n\nlet warnedReconciliationNonConvergence = false;\n\nfunction reconcileToolDependencies(\n\ttranscript: CompactableTranscript,\n\tinitialTargets: readonly ContextDeletionTarget[],\n): ContextDeletionTarget[] {\n\tconst targets = [...initialTargets];\n\tconst callEntries = new Map<string, CompactableTranscriptEntry>();\n\tconst entriesWithToolCalls = new Set<CompactableTranscriptEntry>();\n\tconst resultEntries = new Map<string, CompactableTranscriptEntry[]>();\n\n\tfor (const entry of transcript.entries) {\n\t\tfor (const callId of entry.toolCallIds) {\n\t\t\tcallEntries.set(callId, entry);\n\t\t\tentriesWithToolCalls.add(entry);\n\t\t}\n\t\tif (entry.toolResultFor) {\n\t\t\tconst results = resultEntries.get(entry.toolResultFor) ?? [];\n\t\t\tresults.push(entry);\n\t\t\tresultEntries.set(entry.toolResultFor, results);\n\t\t}\n\t}\n\n\t// Bounded fixpoint repair: each pass can add/remove paired call/result targets. In practice this\n\t// converges within one or two passes; the cap protects against accidental oscillation.\n\tlet changed = true;\n\tlet remainingPasses = Math.max(1, transcript.entries.length * 2);\n\twhile (changed && remainingPasses > 0) {\n\t\tchanged = false;\n\t\tremainingPasses -= 1;\n\t\tlet deletedEntryIds = getDeletedEntryIds(targets);\n\t\tlet deletedContentBlocks = getDeletedContentBlocks(targets);\n\t\tconst recordChange = (nextChanged: boolean): void => {\n\t\t\tif (!nextChanged) return;\n\t\t\tchanged = true;\n\t\t\tdeletedEntryIds = getDeletedEntryIds(targets);\n\t\t\tdeletedContentBlocks = getDeletedContentBlocks(targets);\n\t\t};\n\n\t\tfor (const [callId, callEntry] of callEntries) {\n\t\t\tconst callDeleted = isToolCallBlockDeleted(callEntry, callId, deletedEntryIds, deletedContentBlocks);\n\t\t\tconst results = resultEntries.get(callId) ?? [];\n\n\t\t\tif (callDeleted) {\n\t\t\t\tconst retainedProtectedResult = results.find(\n\t\t\t\t\t(entry) =>\n\t\t\t\t\t\t!deletedEntryIds.has(entry.entryId) &&\n\t\t\t\t\t\t!canDeleteTarget(transcript, { kind: \"entry\", entryId: entry.entryId }),\n\t\t\t\t);\n\t\t\t\tif (retainedProtectedResult) {\n\t\t\t\t\tconst retainedResultTarget: ContextDeletionTarget = { kind: \"entry\", entryId: retainedProtectedResult.entryId };\n\t\t\t\t\tif (isRecentTarget(transcript, retainedResultTarget)) {\n\t\t\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, retainedResultTarget));\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tformatProtectedToolDependencyError(\n\t\t\t\t\t\t\ttranscript,\n\t\t\t\t\t\t\tretainedResultTarget,\n\t\t\t\t\t\t\t`Cannot delete tool call ${callId} because its paired tool result entry ${retainedProtectedResult.entryId} is protected.`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tfor (const result of results) {\n\t\t\t\t\t\trecordChange(deleteEntryTarget(targets, result.entryId));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isToolCallBlockDeleted(callEntry, callId, deletedEntryIds, deletedContentBlocks)) continue;\n\n\t\t\tfor (const result of results) {\n\t\t\t\tif (!deletedEntryIds.has(result.entryId)) continue;\n\t\t\t\trecordChange(deleteEntryTarget(targets, result.entryId));\n\t\t\t\tconst callEntryTarget: ContextDeletionTarget = { kind: \"entry\", entryId: callEntry.entryId };\n\t\t\t\tconst callBlockTarget = assistantEntryHasThinkingContentBlock(callEntry)\n\t\t\t\t\t? callEntryTarget\n\t\t\t\t\t: firstToolCallBlockTarget(callEntry, callId) ?? callEntryTarget;\n\t\t\t\tif (!canDeleteTarget(transcript, callBlockTarget)) {\n\t\t\t\t\tif (isRecentTarget(transcript, callBlockTarget)) {\n\t\t\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, callBlockTarget));\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tformatProtectedToolDependencyError(\n\t\t\t\t\t\t\ttranscript,\n\t\t\t\t\t\t\tcallBlockTarget,\n\t\t\t\t\t\t\t`Cannot delete tool result entry ${result.entryId} because that would require deleting protected tool block for tool call ${callId}.`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\trecordChange(addToolCallDeletion(transcript, targets, callEntry, callId));\n\t\t\t}\n\t\t}\n\n\t\tfor (const entry of entriesWithToolCalls) {\n\t\t\trecordChange(canonicalizeEntryTargets(transcript, targets, entry));\n\t\t}\n\t}\n\n\tif (changed && !warnedReconciliationNonConvergence) {\n\t\twarnedReconciliationNonConvergence = true;\n\t\tconsole.warn(\n\t\t\t`Context compaction tool dependency reconciliation did not converge within the bounded pass limit; validation will continue with the last reconciled target set. entries=${transcript.entries.length} callEntries=${callEntries.size} targets=${targets.length}`,\n\t\t);\n\t}\n\n\treturn targets;\n}\n\nfunction validateToolDependencies(transcript: CompactableTranscript, targets: readonly ContextDeletionTarget[]): void {\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tconst deletedContentBlocks = getDeletedContentBlocks(targets);\n\tconst callEntries = new Map<string, CompactableTranscriptEntry>();\n\tconst resultEntries = new Map<string, CompactableTranscriptEntry[]>();\n\n\tfor (const entry of transcript.entries) {\n\t\tfor (const callId of entry.toolCallIds) {\n\t\t\tcallEntries.set(callId, entry);\n\t\t}\n\t\tif (entry.toolResultFor) {\n\t\t\tconst results = resultEntries.get(entry.toolResultFor) ?? [];\n\t\t\tresults.push(entry);\n\t\t\tresultEntries.set(entry.toolResultFor, results);\n\t\t}\n\t}\n\n\tfor (const [callId, callEntry] of callEntries) {\n\t\tconst callDeleted = isToolCallBlockDeleted(callEntry, callId, deletedEntryIds, deletedContentBlocks);\n\t\tconst results = resultEntries.get(callId) ?? [];\n\t\tif (callDeleted) {\n\t\t\tconst danglingResult = results.find((entry) => !deletedEntryIds.has(entry.entryId));\n\t\t\tif (danglingResult) {\n\t\t\t\tthrow new Error(`Deleting tool call ${callId} would leave tool result entry ${danglingResult.entryId} orphaned`);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst deletedResult = results.find((entry) => deletedEntryIds.has(entry.entryId));\n\t\tif (deletedResult) {\n\t\t\tthrow new Error(`Deleting tool result entry ${deletedResult.entryId} would leave tool call ${callId} dangling`);\n\t\t}\n\t}\n}\n\nexport function computeContextCompactionStats(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): ContextCompactionStats {\n\tconst entryById = new Map(transcript.entries.map((entry) => [entry.entryId, entry]));\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tlet deletedTokens = 0;\n\tlet objectsDeleted = 0;\n\n\tfor (const entryId of deletedEntryIds) {\n\t\tconst entry = entryById.get(entryId);\n\t\tif (!entry) continue;\n\t\tdeletedTokens += entry.tokenEstimate;\n\t\tobjectsDeleted += 1 + entry.contentBlocks.length;\n\t}\n\n\tfor (const target of targets) {\n\t\tif (target.kind !== \"content_block\" || deletedEntryIds.has(target.entryId)) continue;\n\t\tconst entry = entryById.get(target.entryId);\n\t\tif (!entry) continue;\n\t\tconst block = entry.contentBlocks.find((item) => item.blockIndex === target.blockIndex);\n\t\tif (!block) continue;\n\t\tdeletedTokens += block.tokenEstimate;\n\t\tobjectsDeleted += 1;\n\t}\n\n\tconst objectsBefore = transcript.entries.length + transcript.entries.reduce((total, entry) => total + entry.contentBlocks.length, 0);\n\tconst tokensBefore = transcript.tokensBefore;\n\tconst tokensAfter = Math.max(0, tokensBefore - deletedTokens);\n\tconst percentReduction = tokensBefore > 0 ? Math.round(((tokensBefore - tokensAfter) / tokensBefore) * 1000) / 10 : 0;\n\treturn {\n\t\tobjectsBefore,\n\t\tobjectsAfter: Math.max(0, objectsBefore - objectsDeleted),\n\t\tobjectsDeleted,\n\t\ttokensBefore,\n\t\ttokensAfter,\n\t\tpercentReduction,\n\t};\n}\n\n/**\n * An entry \"bears task context\" when it carries the user's intent for the session: a real `user`\n * message, an extension-injected `custom` message, or a branch summary (`branchSummary` role /\n * `branch_summary` entry type) that recaps an earlier branch's task.\n *\n * Verbatim compaction must always leave at least one task-bearing entry in context.\n */\nexport function validateContextDeletionRequest(\n\trequest: ContextDeletionRequest,\n\ttranscript: CompactableTranscript,\n): ValidatedContextDeletionResult {\n\tif (!request || typeof request !== \"object\" || !Array.isArray(request.deletions)) {\n\t\tthrow new Error(\"Context deletion request must be an object with a deletions array\");\n\t}\n\n\tconst entryById = new Map(transcript.entries.map((entry) => [entry.entryId, entry]));\n\tconst recentEntryIds = getRecentContextEntryIds(transcript);\n\tconst seen = new Set<string>();\n\tconst deletedTargets: ContextDeletionTarget[] = [];\n\n\tfor (const deletion of request.deletions) {\n\t\tif (!deletion || typeof deletion !== \"object\") {\n\t\t\tthrow new Error(\"Deletion target must be an object\");\n\t\t}\n\t\tif (deletion.kind !== \"entry\" && deletion.kind !== \"content_block\") {\n\t\t\tthrow new Error(`Unsupported deletion target kind: ${String((deletion as { kind?: unknown }).kind)}`);\n\t\t}\n\t\tassertIdOnlyDeletionTarget(deletion as Record<string, unknown>);\n\t\tif (typeof deletion.entryId !== \"string\" || deletion.entryId.length === 0) {\n\t\t\tthrow new Error(\"Deletion target entryId must be a non-empty string\");\n\t\t}\n\t\tconst entry = entryById.get(deletion.entryId);\n\t\tif (!entry) {\n\t\t\tthrow new Error(`Unknown deletion target entryId: ${deletion.entryId}`);\n\t\t}\n\t\tconst normalized = normalizeRawTarget(deletion);\n\t\tif (deletion.kind === \"entry\") {\n\t\t\tif (recentEntryIds.has(deletion.entryId)) {\n\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, normalized));\n\t\t\t}\n\t\t\tif (!canDeleteTarget(transcript, normalized)) {\n\t\t\t\tthrow new Error(formatProtectedDeletionError(transcript, normalized));\n\t\t\t}\n\t\t}\n\t\tif (deletion.kind === \"content_block\") {\n\t\t\tif (typeof deletion.blockIndex !== \"number\" || !Number.isInteger(deletion.blockIndex) || deletion.blockIndex < 0) {\n\t\t\t\tthrow new Error(`Invalid content block index for entry ${deletion.entryId}`);\n\t\t\t}\n\t\t\tif (recentEntryIds.has(deletion.entryId)) {\n\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, normalized));\n\t\t\t}\n\t\t\tconst block = entry.contentBlocks.find((item) => item.blockIndex === deletion.blockIndex);\n\t\t\tif (!block) {\n\t\t\t\tif (entry.protected) {\n\t\t\t\t\tthrow new Error(formatProtectedDeletionError(transcript, normalized));\n\t\t\t\t}\n\t\t\t\tthrow new Error(`Unknown content block ${deletion.blockIndex} for entry ${deletion.entryId}`);\n\t\t\t}\n\t\t\tif (!canDeleteTarget(transcript, normalized)) {\n\t\t\t\tthrow new Error(formatProtectedDeletionError(transcript, normalized));\n\t\t\t}\n\t\t\tif (entry.contentBlocks.length <= 1) {\n\t\t\t\tthrow new Error(`Deleting the only content block of ${deletion.entryId} must be an entry deletion`);\n\t\t\t}\n\t\t}\n\n\t\tconst key = rawTargetKey(deletion);\n\t\tif (seen.has(key)) {\n\t\t\tthrow new Error(`Duplicate deletion target: ${key}`);\n\t\t}\n\t\tseen.add(key);\n\t\tdeletedTargets.push(normalized);\n\t}\n\n\tconst reconciledTargets = reconcileToolDependencies(transcript, deletedTargets);\n\t// Tool reconciliation can add targets after the per-request checks above, so\n\t// these post-reconcile assertions remain authoritative.\n\tassertNoRecentContextDeletionTargets(transcript, reconciledTargets);\n\tassertNoAssistantThinkingContentBlockDeletionTargets(transcript, reconciledTargets);\n\tassertNoLatestAssistantThinkingDeletionTargets(transcript, reconciledTargets);\n\tconst reconciledDeletedEntryIds = getDeletedEntryIds(reconciledTargets);\n\n\tfor (const target of reconciledTargets) {\n\t\tif (target.kind === \"content_block\" && reconciledDeletedEntryIds.has(target.entryId)) {\n\t\t\tthrow new Error(`Deletion target ${targetKey(target)} overlaps with entry deletion`);\n\t\t}\n\t}\n\n\tconst deletedContentBlocks = getDeletedContentBlocks(reconciledTargets);\n\tfor (const [entryId, blockIndexes] of deletedContentBlocks) {\n\t\tconst entry = entryById.get(entryId);\n\t\tif (entry?.contentBlocks.every((block) => blockIndexes.has(block.blockIndex))) {\n\t\t\tthrow new Error(`Content-block deletions for ${entryId} would remove every content block`);\n\t\t}\n\t}\n\n\tvalidateToolDependencies(transcript, reconciledTargets);\n\n\tconst remainingEntries = transcript.entries.filter((entry) => !reconciledDeletedEntryIds.has(entry.entryId));\n\tif (remainingEntries.length === 0) {\n\t\tthrow new Error(\"Deletion request would remove all context entries\");\n\t}\n\tconst hasTaskBearingContext = remainingEntries.some(isTaskBearingEntry);\n\tif (!hasTaskBearingContext) {\n\t\tthrow new Error(\"Deletion request would leave no user task in context\");\n\t}\n\n\treturn {\n\t\tdeletedTargets: reconciledTargets,\n\t\tprotectedEntryIds: [...transcript.protectedEntryIds],\n\t\tstats: computeContextCompactionStats(transcript, reconciledTargets),\n\t};\n}\n\nexport function contextDeletionRequestFromObject(value: unknown, source: string): ContextDeletionRequest {\n\tif (!value || typeof value !== \"object\" || !Array.isArray((value as { deletions?: unknown }).deletions)) {\n\t\tthrow new Error(`${source} must contain a deletions array`);\n\t}\n\treturn value as ContextDeletionRequest;\n}\n\n"]}
1
+ {"version":3,"file":"context-deletion-application.js","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-application.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextCompactionStats, ContextDeletionTarget } from \"../session-manager.ts\";\nimport type {\n\tCompactableTranscript,\n\tCompactableTranscriptEntry,\n\tContextDeletionRequest,\n\tValidatedContextDeletionResult,\n} from \"./context-compaction-types.ts\";\nimport { assistantEntryHasThinkingContentBlock } from \"./context-assistant-turns.js\";\nimport {\n\taddToolCallDeletion,\n\tassertIdOnlyDeletionTarget,\n\tassertNoAssistantThinkingContentBlockDeletionTargets,\n\tassertNoLatestAssistantThinkingDeletionTargets,\n\tassertNoRecentContextDeletionTargets,\n\tcanonicalizeEntryTargets,\n\tcanDeleteTarget,\n\tdeleteEntryTarget,\n\tfirstToolCallBlockTarget,\n\tformatProtectedDeletionError,\n\tformatProtectedToolDependencyError,\n\tformatRecentContextDeletionError,\n\tgetDeletedContentBlocks,\n\tgetDeletedEntryIds,\n\tgetRecentContextEntryIds,\n\tisRecentTarget,\n\tisTaskBearingEntry,\n\tisToolCallBlockDeleted,\n\tnormalizeRawTarget,\n\trawTargetKey,\n\ttargetKey,\n} from \"./context-deletion-targets.ts\";\n\nlet warnedReconciliationNonConvergence = false;\n\nexport function reconcileToolDependencies(\n\ttranscript: CompactableTranscript,\n\tinitialTargets: readonly ContextDeletionTarget[],\n): ContextDeletionTarget[] {\n\tconst targets = [...initialTargets];\n\tconst callEntries = new Map<string, CompactableTranscriptEntry>();\n\tconst entriesWithToolCalls = new Set<CompactableTranscriptEntry>();\n\tconst resultEntries = new Map<string, CompactableTranscriptEntry[]>();\n\n\tfor (const entry of transcript.entries) {\n\t\tfor (const callId of entry.toolCallIds) {\n\t\t\tcallEntries.set(callId, entry);\n\t\t\tentriesWithToolCalls.add(entry);\n\t\t}\n\t\tif (entry.toolResultFor) {\n\t\t\tconst results = resultEntries.get(entry.toolResultFor) ?? [];\n\t\t\tresults.push(entry);\n\t\t\tresultEntries.set(entry.toolResultFor, results);\n\t\t}\n\t}\n\n\t// Bounded fixpoint repair: each pass can add/remove paired call/result targets. In practice this\n\t// converges within one or two passes; the cap protects against accidental oscillation.\n\tlet changed = true;\n\tlet remainingPasses = Math.max(1, transcript.entries.length * 2);\n\twhile (changed && remainingPasses > 0) {\n\t\tchanged = false;\n\t\tremainingPasses -= 1;\n\t\tlet deletedEntryIds = getDeletedEntryIds(targets);\n\t\tlet deletedContentBlocks = getDeletedContentBlocks(targets);\n\t\tconst recordChange = (nextChanged: boolean): void => {\n\t\t\tif (!nextChanged) return;\n\t\t\tchanged = true;\n\t\t\tdeletedEntryIds = getDeletedEntryIds(targets);\n\t\t\tdeletedContentBlocks = getDeletedContentBlocks(targets);\n\t\t};\n\n\t\tfor (const [callId, callEntry] of callEntries) {\n\t\t\tconst callDeleted = isToolCallBlockDeleted(callEntry, callId, deletedEntryIds, deletedContentBlocks);\n\t\t\tconst results = resultEntries.get(callId) ?? [];\n\n\t\t\tif (callDeleted) {\n\t\t\t\tconst retainedProtectedResult = results.find(\n\t\t\t\t\t(entry) =>\n\t\t\t\t\t\t!deletedEntryIds.has(entry.entryId) &&\n\t\t\t\t\t\t!canDeleteTarget(transcript, { kind: \"entry\", entryId: entry.entryId }),\n\t\t\t\t);\n\t\t\t\tif (retainedProtectedResult) {\n\t\t\t\t\tconst retainedResultTarget: ContextDeletionTarget = { kind: \"entry\", entryId: retainedProtectedResult.entryId };\n\t\t\t\t\tif (isRecentTarget(transcript, retainedResultTarget)) {\n\t\t\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, retainedResultTarget));\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tformatProtectedToolDependencyError(\n\t\t\t\t\t\t\ttranscript,\n\t\t\t\t\t\t\tretainedResultTarget,\n\t\t\t\t\t\t\t`Cannot delete tool call ${callId} because its paired tool result entry ${retainedProtectedResult.entryId} is protected.`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tfor (const result of results) {\n\t\t\t\t\t\trecordChange(deleteEntryTarget(targets, result.entryId));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isToolCallBlockDeleted(callEntry, callId, deletedEntryIds, deletedContentBlocks)) continue;\n\n\t\t\tfor (const result of results) {\n\t\t\t\tif (!deletedEntryIds.has(result.entryId)) continue;\n\t\t\t\trecordChange(deleteEntryTarget(targets, result.entryId));\n\t\t\t\tconst callEntryTarget: ContextDeletionTarget = { kind: \"entry\", entryId: callEntry.entryId };\n\t\t\t\tconst callBlockTarget = assistantEntryHasThinkingContentBlock(callEntry)\n\t\t\t\t\t? callEntryTarget\n\t\t\t\t\t: firstToolCallBlockTarget(callEntry, callId) ?? callEntryTarget;\n\t\t\t\tif (!canDeleteTarget(transcript, callBlockTarget)) {\n\t\t\t\t\tif (isRecentTarget(transcript, callBlockTarget)) {\n\t\t\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, callBlockTarget));\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tformatProtectedToolDependencyError(\n\t\t\t\t\t\t\ttranscript,\n\t\t\t\t\t\t\tcallBlockTarget,\n\t\t\t\t\t\t\t`Cannot delete tool result entry ${result.entryId} because that would require deleting protected tool block for tool call ${callId}.`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\trecordChange(addToolCallDeletion(transcript, targets, callEntry, callId));\n\t\t\t}\n\t\t}\n\n\t\tfor (const entry of entriesWithToolCalls) {\n\t\t\trecordChange(canonicalizeEntryTargets(transcript, targets, entry));\n\t\t}\n\t}\n\n\tif (changed && !warnedReconciliationNonConvergence) {\n\t\twarnedReconciliationNonConvergence = true;\n\t\tconsole.warn(\n\t\t\t`Context compaction tool dependency reconciliation did not converge within the bounded pass limit; validation will continue with the last reconciled target set. entries=${transcript.entries.length} callEntries=${callEntries.size} targets=${targets.length}`,\n\t\t);\n\t}\n\n\treturn targets;\n}\n\nfunction validateToolDependencies(transcript: CompactableTranscript, targets: readonly ContextDeletionTarget[]): void {\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tconst deletedContentBlocks = getDeletedContentBlocks(targets);\n\tconst callEntries = new Map<string, CompactableTranscriptEntry>();\n\tconst resultEntries = new Map<string, CompactableTranscriptEntry[]>();\n\n\tfor (const entry of transcript.entries) {\n\t\tfor (const callId of entry.toolCallIds) {\n\t\t\tcallEntries.set(callId, entry);\n\t\t}\n\t\tif (entry.toolResultFor) {\n\t\t\tconst results = resultEntries.get(entry.toolResultFor) ?? [];\n\t\t\tresults.push(entry);\n\t\t\tresultEntries.set(entry.toolResultFor, results);\n\t\t}\n\t}\n\n\tfor (const [callId, callEntry] of callEntries) {\n\t\tconst callDeleted = isToolCallBlockDeleted(callEntry, callId, deletedEntryIds, deletedContentBlocks);\n\t\tconst results = resultEntries.get(callId) ?? [];\n\t\tif (callDeleted) {\n\t\t\tconst danglingResult = results.find((entry) => !deletedEntryIds.has(entry.entryId));\n\t\t\tif (danglingResult) {\n\t\t\t\tthrow new Error(`Deleting tool call ${callId} would leave tool result entry ${danglingResult.entryId} orphaned`);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst deletedResult = results.find((entry) => deletedEntryIds.has(entry.entryId));\n\t\tif (deletedResult) {\n\t\t\tthrow new Error(`Deleting tool result entry ${deletedResult.entryId} would leave tool call ${callId} dangling`);\n\t\t}\n\t}\n}\n\nexport function computeContextCompactionStats(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): ContextCompactionStats {\n\tconst entryById = new Map(transcript.entries.map((entry) => [entry.entryId, entry]));\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tlet deletedTokens = 0;\n\tlet objectsDeleted = 0;\n\n\tfor (const entryId of deletedEntryIds) {\n\t\tconst entry = entryById.get(entryId);\n\t\tif (!entry) continue;\n\t\tdeletedTokens += entry.tokenEstimate;\n\t\tobjectsDeleted += 1 + entry.contentBlocks.length;\n\t}\n\n\tconst deletedContentBlocks = getDeletedContentBlocks(targets);\n\tfor (const [entryId, blockIndexes] of deletedContentBlocks) {\n\t\tif (deletedEntryIds.has(entryId)) continue;\n\t\tconst entry = entryById.get(entryId);\n\t\tif (!entry) continue;\n\t\tconst deletedBlocks = entry.contentBlocks.filter((block) => blockIndexes.has(block.blockIndex));\n\t\tobjectsDeleted += deletedBlocks.length;\n\t\tdeletedTokens +=\n\t\t\tisTaskBearingEntry(entry) && !isTaskBearingEntry(entry, blockIndexes)\n\t\t\t\t? entry.tokenEstimate\n\t\t\t\t: deletedBlocks.reduce((total, block) => total + block.tokenEstimate, 0);\n\t}\n\n\tconst objectsBefore = transcript.entries.length + transcript.entries.reduce((total, entry) => total + entry.contentBlocks.length, 0);\n\tconst tokensBefore = transcript.tokensBefore;\n\tconst tokensAfter = Math.max(0, tokensBefore - deletedTokens);\n\tconst percentReduction = tokensBefore > 0 ? Math.round(((tokensBefore - tokensAfter) / tokensBefore) * 1000) / 10 : 0;\n\treturn {\n\t\tobjectsBefore,\n\t\tobjectsAfter: Math.max(0, objectsBefore - objectsDeleted),\n\t\tobjectsDeleted,\n\t\ttokensBefore,\n\t\ttokensAfter,\n\t\tpercentReduction,\n\t};\n}\n\n/**\n * A provider-visible task entry carries session intent through a real `user` message,\n * extension-injected `custom` message, or branch summary. Proposed block deletions count,\n * so an entry with only omitted whitespace remaining cannot satisfy the task floor.\n *\n * Verbatim compaction must always leave at least one provider-visible task entry in context.\n */\nexport function validateContextDeletionRequest(\n\trequest: ContextDeletionRequest,\n\ttranscript: CompactableTranscript,\n): ValidatedContextDeletionResult {\n\tif (!request || typeof request !== \"object\" || !Array.isArray(request.deletions)) {\n\t\tthrow new Error(\"Context deletion request must be an object with a deletions array\");\n\t}\n\n\tconst entryById = new Map(transcript.entries.map((entry) => [entry.entryId, entry]));\n\tconst recentEntryIds = getRecentContextEntryIds(transcript);\n\tconst seen = new Set<string>();\n\tconst deletedTargets: ContextDeletionTarget[] = [];\n\n\tfor (const deletion of request.deletions) {\n\t\tif (!deletion || typeof deletion !== \"object\") {\n\t\t\tthrow new Error(\"Deletion target must be an object\");\n\t\t}\n\t\tif (deletion.kind !== \"entry\" && deletion.kind !== \"content_block\") {\n\t\t\tthrow new Error(`Unsupported deletion target kind: ${String((deletion as { kind?: unknown }).kind)}`);\n\t\t}\n\t\tassertIdOnlyDeletionTarget(deletion as Record<string, unknown>);\n\t\tif (typeof deletion.entryId !== \"string\" || deletion.entryId.length === 0) {\n\t\t\tthrow new Error(\"Deletion target entryId must be a non-empty string\");\n\t\t}\n\t\tconst entry = entryById.get(deletion.entryId);\n\t\tif (!entry) {\n\t\t\tthrow new Error(`Unknown deletion target entryId: ${deletion.entryId}`);\n\t\t}\n\t\tconst normalized = normalizeRawTarget(deletion);\n\t\tif (deletion.kind === \"entry\") {\n\t\t\tif (recentEntryIds.has(deletion.entryId)) {\n\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, normalized));\n\t\t\t}\n\t\t\tif (!canDeleteTarget(transcript, normalized)) {\n\t\t\t\tthrow new Error(formatProtectedDeletionError(transcript, normalized));\n\t\t\t}\n\t\t}\n\t\tif (deletion.kind === \"content_block\") {\n\t\t\tif (typeof deletion.blockIndex !== \"number\" || !Number.isInteger(deletion.blockIndex) || deletion.blockIndex < 0) {\n\t\t\t\tthrow new Error(`Invalid content block index for entry ${deletion.entryId}`);\n\t\t\t}\n\t\t\tif (recentEntryIds.has(deletion.entryId)) {\n\t\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, normalized));\n\t\t\t}\n\t\t\tconst block = entry.contentBlocks.find((item) => item.blockIndex === deletion.blockIndex);\n\t\t\tif (!block) {\n\t\t\t\tif (entry.protected) {\n\t\t\t\t\tthrow new Error(formatProtectedDeletionError(transcript, normalized));\n\t\t\t\t}\n\t\t\t\tthrow new Error(`Unknown content block ${deletion.blockIndex} for entry ${deletion.entryId}`);\n\t\t\t}\n\t\t\tif (!canDeleteTarget(transcript, normalized)) {\n\t\t\t\tthrow new Error(formatProtectedDeletionError(transcript, normalized));\n\t\t\t}\n\t\t\tif (entry.contentBlocks.length <= 1) {\n\t\t\t\tthrow new Error(`Deleting the only content block of ${deletion.entryId} must be an entry deletion`);\n\t\t\t}\n\t\t}\n\n\t\tconst key = rawTargetKey(deletion);\n\t\tif (seen.has(key)) {\n\t\t\tthrow new Error(`Duplicate deletion target: ${key}`);\n\t\t}\n\t\tseen.add(key);\n\t\tdeletedTargets.push(normalized);\n\t}\n\n\tconst reconciledTargets = reconcileToolDependencies(transcript, deletedTargets);\n\t// Tool reconciliation can add targets after the per-request checks above, so\n\t// these post-reconcile assertions remain authoritative.\n\tassertNoRecentContextDeletionTargets(transcript, reconciledTargets);\n\tassertNoAssistantThinkingContentBlockDeletionTargets(transcript, reconciledTargets);\n\tassertNoLatestAssistantThinkingDeletionTargets(transcript, reconciledTargets);\n\tconst reconciledDeletedEntryIds = getDeletedEntryIds(reconciledTargets);\n\n\tfor (const target of reconciledTargets) {\n\t\tif (target.kind === \"content_block\" && reconciledDeletedEntryIds.has(target.entryId)) {\n\t\t\tthrow new Error(`Deletion target ${targetKey(target)} overlaps with entry deletion`);\n\t\t}\n\t}\n\n\tconst deletedContentBlocks = getDeletedContentBlocks(reconciledTargets);\n\tfor (const [entryId, blockIndexes] of deletedContentBlocks) {\n\t\tconst entry = entryById.get(entryId);\n\t\tif (entry?.contentBlocks.every((block) => blockIndexes.has(block.blockIndex))) {\n\t\t\tthrow new Error(`Content-block deletions for ${entryId} would remove every content block`);\n\t\t}\n\t}\n\n\tvalidateToolDependencies(transcript, reconciledTargets);\n\n\tconst remainingEntries = transcript.entries.filter((entry) => !reconciledDeletedEntryIds.has(entry.entryId));\n\tif (remainingEntries.length === 0) {\n\t\tthrow new Error(\"Deletion request would remove all context entries\");\n\t}\n\tconst hasTaskBearingContext = remainingEntries.some((entry) =>\n\t\tisTaskBearingEntry(entry, deletedContentBlocks.get(entry.entryId)),\n\t);\n\tif (!hasTaskBearingContext) {\n\t\tthrow new Error(\"Deletion request would leave no user task in context\");\n\t}\n\n\treturn {\n\t\tdeletedTargets: reconciledTargets,\n\t\tprotectedEntryIds: [...transcript.protectedEntryIds],\n\t\tstats: computeContextCompactionStats(transcript, reconciledTargets),\n\t};\n}\n\nexport function contextDeletionRequestFromObject(value: unknown, source: string): ContextDeletionRequest {\n\tif (!value || typeof value !== \"object\" || !Array.isArray((value as { deletions?: unknown }).deletions)) {\n\t\tthrow new Error(`${source} must contain a deletions array`);\n\t}\n\treturn value as ContextDeletionRequest;\n}\n\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"context-deletion-store.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAG3E,MAAM,WAAW,YAAY;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,6BAA6B,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,YAAa,SAAQ,YAAY;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,mBAAoB,SAAQ,mBAAmB;IAC/D,cAAc,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,0BAA0B,EAAE,OAAO,CAAC;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,0BAA0B,EAAE,OAAO,CAAC;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,6BAA6B;IAC7C,eAAe,EAAE,qBAAqB,EAAE,CAAC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAQD,qBAAa,0BAA0B;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqC;IACjE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuB;IACrD,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAsB;IACjE,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,SAAS,CAAqB;IAEtC,YAAY,UAAU,EAAE,qBAAqB,EA8C5C;IAED,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,CAQpC;IAED,WAAW,IAAI,qBAAqB,EAAE,CAErC;IAED,cAAc,CAAC,OAAO,EAAE,SAAS,qBAAqB,EAAE,GAAG,IAAI,CAE9D;IAED,kBAAkB,IAAI,YAAY,EAAE,CAOnC;IAED,wBAAwB,IAAI,mBAAmB,EAAE,CAchD;IAED,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAWzD;IAED,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAe3F;IAED,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,eAAe,GAAG,MAAM,CAG/D;IAED,kBAAkB,IAAI,MAAM,CAG3B;IAED,YAAY,IAAI,MAAM,CAErB;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAElC;IAED,cAAc,IAAI,IAAI,CAErB;IAED,YAAY,IAAI,MAAM,GAAG,SAAS,CAEjC;IAED,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,OAAO;CAKf;AAED,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,qBAAqB,GAAG,0BAA0B,CAExG","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { ContextDeletionTarget } from \"../session-manager.ts\";\nimport type { CompactableTranscript } from \"./context-compaction-types.ts\";\nimport { assistantEntryHasThinkingContentBlock } from \"./context-transcript-analysis.ts\";\n\nexport interface EntryTextRow {\n\tentry_id: string;\n\ttext: string;\n\tis_protected: number;\n\thas_assistant_thinking_blocks: number;\n}\n\nexport interface EntryReadRow extends EntryTextRow {\n\trole: string;\n\ttoken_estimate: number;\n}\n\nexport interface ContentBlockTextRow {\n\tentry_id: string;\n\tblock_index: number;\n\trole: AgentMessage[\"role\"];\n\ttype: string;\n\ttext: string;\n\tentry_protected: number;\n\tblock_protected: number;\n\tblock_count: number;\n\thas_assistant_thinking_blocks: number;\n}\n\nexport interface ContentBlockReadRow extends ContentBlockTextRow {\n\ttoken_estimate: number;\n}\n\nexport interface StoredTranscriptEntry {\n\tentryId: string;\n\trole: AgentMessage[\"role\"];\n\tprotected: boolean;\n\thasAssistantThinkingBlocks: boolean;\n\ttokenEstimate: number;\n\ttext: string;\n}\n\nexport interface StoredContentBlock {\n\tentryPosition: number;\n\tentryId: string;\n\tblockIndex: number;\n\trole: AgentMessage[\"role\"];\n\ttype: string;\n\tprotected: boolean;\n\thasAssistantThinkingBlocks: boolean;\n\ttokenEstimate: number;\n\ttext: string;\n}\n\nexport interface ContextDeletionMemorySnapshot {\n\tdeletionTargets: ContextDeletionTarget[];\n\tcallCount: number;\n\tlastError?: string;\n}\n\nfunction copyDeletionTarget(target: ContextDeletionTarget): ContextDeletionTarget {\n\treturn target.kind === \"entry\"\n\t\t? { kind: \"entry\", entryId: target.entryId }\n\t\t: { kind: \"content_block\", entryId: target.entryId, blockIndex: target.blockIndex };\n}\n\nexport class ContextDeletionMemoryStore {\n\tprivate readonly entries: StoredTranscriptEntry[];\n\tprivate readonly entriesById: Map<string, StoredTranscriptEntry>;\n\tprivate readonly contentBlocks: StoredContentBlock[];\n\tprivate readonly contentBlockCountByEntryId: Map<string, number>;\n\tprivate deletionTargets: ContextDeletionTarget[] = [];\n\tprivate callCount = 0;\n\tprivate lastError: string | undefined;\n\n\tconstructor(transcript: CompactableTranscript) {\n\t\tconst entryIds = new Set<string>();\n\t\tconst blockKeys = new Set<string>();\n\t\tthis.entries = transcript.entries.map((entry) => {\n\t\t\tif (entryIds.has(entry.entryId)) {\n\t\t\t\tthrow new Error(`Duplicate transcript entry id: ${entry.entryId}`);\n\t\t\t}\n\t\t\tentryIds.add(entry.entryId);\n\t\t\treturn {\n\t\t\t\tentryId: entry.entryId,\n\t\t\t\trole: entry.role,\n\t\t\t\tprotected: entry.protected,\n\t\t\t\thasAssistantThinkingBlocks: assistantEntryHasThinkingContentBlock(entry),\n\t\t\t\ttokenEstimate: entry.tokenEstimate,\n\t\t\t\ttext: entry.text,\n\t\t\t};\n\t\t});\n\t\tthis.entriesById = new Map<string, StoredTranscriptEntry>(this.entries.map((entry) => [entry.entryId, entry] as const));\n\t\tthis.contentBlocks = transcript.entries.flatMap((entry, entryPosition) => {\n\t\t\tconst hasAssistantThinkingBlocks = assistantEntryHasThinkingContentBlock(entry);\n\t\t\treturn entry.contentBlocks.map((block) => {\n\t\t\t\tif (block.entryId !== entry.entryId) {\n\t\t\t\t\tthrow new Error(`Transcript content block ${block.entryId}:${block.blockIndex} does not belong to entry ${entry.entryId}`);\n\t\t\t\t}\n\t\t\t\tconst blockKey = `${block.entryId}:${block.blockIndex}`;\n\t\t\t\tif (blockKeys.has(blockKey)) {\n\t\t\t\t\tthrow new Error(`Duplicate transcript content block: ${blockKey}`);\n\t\t\t\t}\n\t\t\t\tblockKeys.add(blockKey);\n\t\t\t\treturn {\n\t\t\t\t\tentryPosition,\n\t\t\t\t\tentryId: block.entryId,\n\t\t\t\t\tblockIndex: block.blockIndex,\n\t\t\t\t\trole: entry.role,\n\t\t\t\t\ttype: block.type,\n\t\t\t\t\tprotected: block.protected,\n\t\t\t\t\thasAssistantThinkingBlocks,\n\t\t\t\t\ttokenEstimate: block.tokenEstimate,\n\t\t\t\t\ttext: block.text,\n\t\t\t\t};\n\t\t\t});\n\t\t});\n\t\tthis.contentBlockCountByEntryId = new Map();\n\t\tfor (const block of this.contentBlocks) {\n\t\t\tthis.contentBlockCountByEntryId.set(block.entryId, (this.contentBlockCountByEntryId.get(block.entryId) ?? 0) + 1);\n\t\t}\n\t}\n\n\ttransaction<T>(operation: () => T): T {\n\t\tconst snapshot = this.snapshot();\n\t\ttry {\n\t\t\treturn operation();\n\t\t} catch (error) {\n\t\t\tthis.restore(snapshot);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\treadTargets(): ContextDeletionTarget[] {\n\t\treturn this.deletionTargets.map(copyDeletionTarget);\n\t}\n\n\treplaceTargets(targets: readonly ContextDeletionTarget[]): void {\n\t\tthis.deletionTargets = targets.map(copyDeletionTarget);\n\t}\n\n\tlistEntriesForGrep(): EntryTextRow[] {\n\t\treturn this.entries.map((entry) => ({\n\t\t\tentry_id: entry.entryId,\n\t\t\ttext: entry.text,\n\t\t\tis_protected: entry.protected ? 1 : 0,\n\t\t\thas_assistant_thinking_blocks: entry.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t}));\n\t}\n\n\tlistContentBlocksForGrep(): ContentBlockTextRow[] {\n\t\treturn [...this.contentBlocks]\n\t\t\t.sort((a, b) => a.entryPosition - b.entryPosition || a.blockIndex - b.blockIndex)\n\t\t\t.map((block) => ({\n\t\t\t\tentry_id: block.entryId,\n\t\t\t\tblock_index: block.blockIndex,\n\t\t\t\trole: block.role,\n\t\t\t\ttype: block.type,\n\t\t\t\ttext: block.text,\n\t\t\t\tentry_protected: this.entriesById.get(block.entryId)?.protected ? 1 : 0,\n\t\t\t\tblock_protected: block.protected ? 1 : 0,\n\t\t\t\tblock_count: this.contentBlockCountByEntryId.get(block.entryId) ?? 0,\n\t\t\t\thas_assistant_thinking_blocks: block.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t\t}));\n\t}\n\n\tgetEntryForRead(entryId: string): EntryReadRow | undefined {\n\t\tconst entry = this.entriesById.get(entryId);\n\t\tif (!entry) return undefined;\n\t\treturn {\n\t\t\tentry_id: entry.entryId,\n\t\t\trole: entry.role,\n\t\t\tis_protected: entry.protected ? 1 : 0,\n\t\t\thas_assistant_thinking_blocks: entry.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t\ttoken_estimate: entry.tokenEstimate,\n\t\t\ttext: entry.text,\n\t\t};\n\t}\n\n\tgetContentBlockForRead(entryId: string, blockIndex: number): ContentBlockReadRow | undefined {\n\t\tconst block = this.contentBlocks.find((candidate) => candidate.entryId === entryId && candidate.blockIndex === blockIndex);\n\t\tif (!block) return undefined;\n\t\treturn {\n\t\t\tentry_id: block.entryId,\n\t\t\tblock_index: block.blockIndex,\n\t\t\trole: block.role,\n\t\t\ttype: block.type,\n\t\t\ttoken_estimate: block.tokenEstimate,\n\t\t\ttext: block.text,\n\t\t\tentry_protected: this.entriesById.get(block.entryId)?.protected ? 1 : 0,\n\t\t\tblock_protected: block.protected ? 1 : 0,\n\t\t\tblock_count: this.contentBlockCountByEntryId.get(block.entryId) ?? 0,\n\t\t\thas_assistant_thinking_blocks: block.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t};\n\t}\n\n\tgetGrepScanTextLength(target: \"entry\" | \"content_block\"): number {\n\t\tconst texts = target === \"entry\" ? this.entries : this.contentBlocks;\n\t\treturn texts.reduce((sum, item) => sum + item.text.length, 0);\n\t}\n\n\tincrementCallCount(): number {\n\t\tthis.callCount += 1;\n\t\treturn this.callCount;\n\t}\n\n\tgetCallCount(): number {\n\t\treturn this.callCount;\n\t}\n\n\tsetLastError(message: string): void {\n\t\tthis.lastError = message;\n\t}\n\n\tclearLastError(): void {\n\t\tthis.lastError = undefined;\n\t}\n\n\tgetLastError(): string | undefined {\n\t\treturn this.lastError;\n\t}\n\n\tprivate snapshot(): ContextDeletionMemorySnapshot {\n\t\treturn {\n\t\t\tdeletionTargets: this.readTargets(),\n\t\t\tcallCount: this.callCount,\n\t\t\t...(this.lastError === undefined ? {} : { lastError: this.lastError }),\n\t\t};\n\t}\n\n\tprivate restore(snapshot: ContextDeletionMemorySnapshot): void {\n\t\tthis.deletionTargets = snapshot.deletionTargets.map(copyDeletionTarget);\n\t\tthis.callCount = snapshot.callCount;\n\t\tthis.lastError = snapshot.lastError;\n\t}\n}\n\nexport function createContextDeletionStore(transcript: CompactableTranscript): ContextDeletionMemoryStore {\n\treturn new ContextDeletionMemoryStore(transcript);\n}\n"]}
1
+ {"version":3,"file":"context-deletion-store.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-store.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { ContextDeletionTarget } from \"../session-manager.ts\";\nimport type { CompactableTranscript } from \"./context-compaction-types.ts\";\nimport { assistantEntryHasThinkingContentBlock } from \"./context-assistant-turns.js\";\n\nexport interface EntryTextRow {\n\tentry_id: string;\n\ttext: string;\n\tis_protected: number;\n\thas_assistant_thinking_blocks: number;\n}\n\nexport interface EntryReadRow extends EntryTextRow {\n\trole: string;\n\ttoken_estimate: number;\n}\n\nexport interface ContentBlockTextRow {\n\tentry_id: string;\n\tblock_index: number;\n\trole: AgentMessage[\"role\"];\n\ttype: string;\n\ttext: string;\n\tentry_protected: number;\n\tblock_protected: number;\n\tblock_count: number;\n\thas_assistant_thinking_blocks: number;\n}\n\nexport interface ContentBlockReadRow extends ContentBlockTextRow {\n\ttoken_estimate: number;\n}\n\nexport interface StoredTranscriptEntry {\n\tentryId: string;\n\trole: AgentMessage[\"role\"];\n\tprotected: boolean;\n\thasAssistantThinkingBlocks: boolean;\n\ttokenEstimate: number;\n\ttext: string;\n}\n\nexport interface StoredContentBlock {\n\tentryPosition: number;\n\tentryId: string;\n\tblockIndex: number;\n\trole: AgentMessage[\"role\"];\n\ttype: string;\n\tprotected: boolean;\n\thasAssistantThinkingBlocks: boolean;\n\ttokenEstimate: number;\n\ttext: string;\n}\n\nexport interface ContextDeletionMemorySnapshot {\n\tdeletionTargets: ContextDeletionTarget[];\n\tcallCount: number;\n\tlastError?: string;\n}\n\nfunction copyDeletionTarget(target: ContextDeletionTarget): ContextDeletionTarget {\n\treturn target.kind === \"entry\"\n\t\t? { kind: \"entry\", entryId: target.entryId }\n\t\t: { kind: \"content_block\", entryId: target.entryId, blockIndex: target.blockIndex };\n}\n\nexport class ContextDeletionMemoryStore {\n\tprivate readonly entries: StoredTranscriptEntry[];\n\tprivate readonly entriesById: Map<string, StoredTranscriptEntry>;\n\tprivate readonly contentBlocks: StoredContentBlock[];\n\tprivate readonly contentBlockCountByEntryId: Map<string, number>;\n\tprivate deletionTargets: ContextDeletionTarget[] = [];\n\tprivate callCount = 0;\n\tprivate lastError: string | undefined;\n\n\tconstructor(transcript: CompactableTranscript) {\n\t\tconst entryIds = new Set<string>();\n\t\tconst blockKeys = new Set<string>();\n\t\tthis.entries = transcript.entries.map((entry) => {\n\t\t\tif (entryIds.has(entry.entryId)) {\n\t\t\t\tthrow new Error(`Duplicate transcript entry id: ${entry.entryId}`);\n\t\t\t}\n\t\t\tentryIds.add(entry.entryId);\n\t\t\treturn {\n\t\t\t\tentryId: entry.entryId,\n\t\t\t\trole: entry.role,\n\t\t\t\tprotected: entry.protected,\n\t\t\t\thasAssistantThinkingBlocks: assistantEntryHasThinkingContentBlock(entry),\n\t\t\t\ttokenEstimate: entry.tokenEstimate,\n\t\t\t\ttext: entry.text,\n\t\t\t};\n\t\t});\n\t\tthis.entriesById = new Map<string, StoredTranscriptEntry>(this.entries.map((entry) => [entry.entryId, entry] as const));\n\t\tthis.contentBlocks = transcript.entries.flatMap((entry, entryPosition) => {\n\t\t\tconst hasAssistantThinkingBlocks = assistantEntryHasThinkingContentBlock(entry);\n\t\t\treturn entry.contentBlocks.map((block) => {\n\t\t\t\tif (block.entryId !== entry.entryId) {\n\t\t\t\t\tthrow new Error(`Transcript content block ${block.entryId}:${block.blockIndex} does not belong to entry ${entry.entryId}`);\n\t\t\t\t}\n\t\t\t\tconst blockKey = `${block.entryId}:${block.blockIndex}`;\n\t\t\t\tif (blockKeys.has(blockKey)) {\n\t\t\t\t\tthrow new Error(`Duplicate transcript content block: ${blockKey}`);\n\t\t\t\t}\n\t\t\t\tblockKeys.add(blockKey);\n\t\t\t\treturn {\n\t\t\t\t\tentryPosition,\n\t\t\t\t\tentryId: block.entryId,\n\t\t\t\t\tblockIndex: block.blockIndex,\n\t\t\t\t\trole: entry.role,\n\t\t\t\t\ttype: block.type,\n\t\t\t\t\tprotected: block.protected,\n\t\t\t\t\thasAssistantThinkingBlocks,\n\t\t\t\t\ttokenEstimate: block.tokenEstimate,\n\t\t\t\t\ttext: block.text,\n\t\t\t\t};\n\t\t\t});\n\t\t});\n\t\tthis.contentBlockCountByEntryId = new Map();\n\t\tfor (const block of this.contentBlocks) {\n\t\t\tthis.contentBlockCountByEntryId.set(block.entryId, (this.contentBlockCountByEntryId.get(block.entryId) ?? 0) + 1);\n\t\t}\n\t}\n\n\ttransaction<T>(operation: () => T): T {\n\t\tconst snapshot = this.snapshot();\n\t\ttry {\n\t\t\treturn operation();\n\t\t} catch (error) {\n\t\t\tthis.restore(snapshot);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\treadTargets(): ContextDeletionTarget[] {\n\t\treturn this.deletionTargets.map(copyDeletionTarget);\n\t}\n\n\treplaceTargets(targets: readonly ContextDeletionTarget[]): void {\n\t\tthis.deletionTargets = targets.map(copyDeletionTarget);\n\t}\n\n\tlistEntriesForGrep(): EntryTextRow[] {\n\t\treturn this.entries.map((entry) => ({\n\t\t\tentry_id: entry.entryId,\n\t\t\ttext: entry.text,\n\t\t\tis_protected: entry.protected ? 1 : 0,\n\t\t\thas_assistant_thinking_blocks: entry.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t}));\n\t}\n\n\tlistContentBlocksForGrep(): ContentBlockTextRow[] {\n\t\treturn [...this.contentBlocks]\n\t\t\t.sort((a, b) => a.entryPosition - b.entryPosition || a.blockIndex - b.blockIndex)\n\t\t\t.map((block) => ({\n\t\t\t\tentry_id: block.entryId,\n\t\t\t\tblock_index: block.blockIndex,\n\t\t\t\trole: block.role,\n\t\t\t\ttype: block.type,\n\t\t\t\ttext: block.text,\n\t\t\t\tentry_protected: this.entriesById.get(block.entryId)?.protected ? 1 : 0,\n\t\t\t\tblock_protected: block.protected ? 1 : 0,\n\t\t\t\tblock_count: this.contentBlockCountByEntryId.get(block.entryId) ?? 0,\n\t\t\t\thas_assistant_thinking_blocks: block.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t\t}));\n\t}\n\n\tgetEntryForRead(entryId: string): EntryReadRow | undefined {\n\t\tconst entry = this.entriesById.get(entryId);\n\t\tif (!entry) return undefined;\n\t\treturn {\n\t\t\tentry_id: entry.entryId,\n\t\t\trole: entry.role,\n\t\t\tis_protected: entry.protected ? 1 : 0,\n\t\t\thas_assistant_thinking_blocks: entry.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t\ttoken_estimate: entry.tokenEstimate,\n\t\t\ttext: entry.text,\n\t\t};\n\t}\n\n\tgetContentBlockForRead(entryId: string, blockIndex: number): ContentBlockReadRow | undefined {\n\t\tconst block = this.contentBlocks.find((candidate) => candidate.entryId === entryId && candidate.blockIndex === blockIndex);\n\t\tif (!block) return undefined;\n\t\treturn {\n\t\t\tentry_id: block.entryId,\n\t\t\tblock_index: block.blockIndex,\n\t\t\trole: block.role,\n\t\t\ttype: block.type,\n\t\t\ttoken_estimate: block.tokenEstimate,\n\t\t\ttext: block.text,\n\t\t\tentry_protected: this.entriesById.get(block.entryId)?.protected ? 1 : 0,\n\t\t\tblock_protected: block.protected ? 1 : 0,\n\t\t\tblock_count: this.contentBlockCountByEntryId.get(block.entryId) ?? 0,\n\t\t\thas_assistant_thinking_blocks: block.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t};\n\t}\n\n\tgetGrepScanTextLength(target: \"entry\" | \"content_block\"): number {\n\t\tconst texts = target === \"entry\" ? this.entries : this.contentBlocks;\n\t\treturn texts.reduce((sum, item) => sum + item.text.length, 0);\n\t}\n\n\tincrementCallCount(): number {\n\t\tthis.callCount += 1;\n\t\treturn this.callCount;\n\t}\n\n\tgetCallCount(): number {\n\t\treturn this.callCount;\n\t}\n\n\tsetLastError(message: string): void {\n\t\tthis.lastError = message;\n\t}\n\n\tclearLastError(): void {\n\t\tthis.lastError = undefined;\n\t}\n\n\tgetLastError(): string | undefined {\n\t\treturn this.lastError;\n\t}\n\n\tprivate snapshot(): ContextDeletionMemorySnapshot {\n\t\treturn {\n\t\t\tdeletionTargets: this.readTargets(),\n\t\t\tcallCount: this.callCount,\n\t\t\t...(this.lastError === undefined ? {} : { lastError: this.lastError }),\n\t\t};\n\t}\n\n\tprivate restore(snapshot: ContextDeletionMemorySnapshot): void {\n\t\tthis.deletionTargets = snapshot.deletionTargets.map(copyDeletionTarget);\n\t\tthis.callCount = snapshot.callCount;\n\t\tthis.lastError = snapshot.lastError;\n\t}\n}\n\nexport function createContextDeletionStore(transcript: CompactableTranscript): ContextDeletionMemoryStore {\n\treturn new ContextDeletionMemoryStore(transcript);\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { assistantEntryHasThinkingContentBlock } from "./context-transcript-analysis.js";
1
+ import { assistantEntryHasThinkingContentBlock } from "./context-assistant-turns.js";
2
2
  function copyDeletionTarget(target) {
3
3
  return target.kind === "entry"
4
4
  ? { kind: "entry", entryId: target.entryId }
@@ -1 +1 @@
1
- {"version":3,"file":"context-deletion-store.js","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-store.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { ContextDeletionTarget } from \"../session-manager.ts\";\nimport type { CompactableTranscript } from \"./context-compaction-types.ts\";\nimport { assistantEntryHasThinkingContentBlock } from \"./context-transcript-analysis.ts\";\n\nexport interface EntryTextRow {\n\tentry_id: string;\n\ttext: string;\n\tis_protected: number;\n\thas_assistant_thinking_blocks: number;\n}\n\nexport interface EntryReadRow extends EntryTextRow {\n\trole: string;\n\ttoken_estimate: number;\n}\n\nexport interface ContentBlockTextRow {\n\tentry_id: string;\n\tblock_index: number;\n\trole: AgentMessage[\"role\"];\n\ttype: string;\n\ttext: string;\n\tentry_protected: number;\n\tblock_protected: number;\n\tblock_count: number;\n\thas_assistant_thinking_blocks: number;\n}\n\nexport interface ContentBlockReadRow extends ContentBlockTextRow {\n\ttoken_estimate: number;\n}\n\nexport interface StoredTranscriptEntry {\n\tentryId: string;\n\trole: AgentMessage[\"role\"];\n\tprotected: boolean;\n\thasAssistantThinkingBlocks: boolean;\n\ttokenEstimate: number;\n\ttext: string;\n}\n\nexport interface StoredContentBlock {\n\tentryPosition: number;\n\tentryId: string;\n\tblockIndex: number;\n\trole: AgentMessage[\"role\"];\n\ttype: string;\n\tprotected: boolean;\n\thasAssistantThinkingBlocks: boolean;\n\ttokenEstimate: number;\n\ttext: string;\n}\n\nexport interface ContextDeletionMemorySnapshot {\n\tdeletionTargets: ContextDeletionTarget[];\n\tcallCount: number;\n\tlastError?: string;\n}\n\nfunction copyDeletionTarget(target: ContextDeletionTarget): ContextDeletionTarget {\n\treturn target.kind === \"entry\"\n\t\t? { kind: \"entry\", entryId: target.entryId }\n\t\t: { kind: \"content_block\", entryId: target.entryId, blockIndex: target.blockIndex };\n}\n\nexport class ContextDeletionMemoryStore {\n\tprivate readonly entries: StoredTranscriptEntry[];\n\tprivate readonly entriesById: Map<string, StoredTranscriptEntry>;\n\tprivate readonly contentBlocks: StoredContentBlock[];\n\tprivate readonly contentBlockCountByEntryId: Map<string, number>;\n\tprivate deletionTargets: ContextDeletionTarget[] = [];\n\tprivate callCount = 0;\n\tprivate lastError: string | undefined;\n\n\tconstructor(transcript: CompactableTranscript) {\n\t\tconst entryIds = new Set<string>();\n\t\tconst blockKeys = new Set<string>();\n\t\tthis.entries = transcript.entries.map((entry) => {\n\t\t\tif (entryIds.has(entry.entryId)) {\n\t\t\t\tthrow new Error(`Duplicate transcript entry id: ${entry.entryId}`);\n\t\t\t}\n\t\t\tentryIds.add(entry.entryId);\n\t\t\treturn {\n\t\t\t\tentryId: entry.entryId,\n\t\t\t\trole: entry.role,\n\t\t\t\tprotected: entry.protected,\n\t\t\t\thasAssistantThinkingBlocks: assistantEntryHasThinkingContentBlock(entry),\n\t\t\t\ttokenEstimate: entry.tokenEstimate,\n\t\t\t\ttext: entry.text,\n\t\t\t};\n\t\t});\n\t\tthis.entriesById = new Map<string, StoredTranscriptEntry>(this.entries.map((entry) => [entry.entryId, entry] as const));\n\t\tthis.contentBlocks = transcript.entries.flatMap((entry, entryPosition) => {\n\t\t\tconst hasAssistantThinkingBlocks = assistantEntryHasThinkingContentBlock(entry);\n\t\t\treturn entry.contentBlocks.map((block) => {\n\t\t\t\tif (block.entryId !== entry.entryId) {\n\t\t\t\t\tthrow new Error(`Transcript content block ${block.entryId}:${block.blockIndex} does not belong to entry ${entry.entryId}`);\n\t\t\t\t}\n\t\t\t\tconst blockKey = `${block.entryId}:${block.blockIndex}`;\n\t\t\t\tif (blockKeys.has(blockKey)) {\n\t\t\t\t\tthrow new Error(`Duplicate transcript content block: ${blockKey}`);\n\t\t\t\t}\n\t\t\t\tblockKeys.add(blockKey);\n\t\t\t\treturn {\n\t\t\t\t\tentryPosition,\n\t\t\t\t\tentryId: block.entryId,\n\t\t\t\t\tblockIndex: block.blockIndex,\n\t\t\t\t\trole: entry.role,\n\t\t\t\t\ttype: block.type,\n\t\t\t\t\tprotected: block.protected,\n\t\t\t\t\thasAssistantThinkingBlocks,\n\t\t\t\t\ttokenEstimate: block.tokenEstimate,\n\t\t\t\t\ttext: block.text,\n\t\t\t\t};\n\t\t\t});\n\t\t});\n\t\tthis.contentBlockCountByEntryId = new Map();\n\t\tfor (const block of this.contentBlocks) {\n\t\t\tthis.contentBlockCountByEntryId.set(block.entryId, (this.contentBlockCountByEntryId.get(block.entryId) ?? 0) + 1);\n\t\t}\n\t}\n\n\ttransaction<T>(operation: () => T): T {\n\t\tconst snapshot = this.snapshot();\n\t\ttry {\n\t\t\treturn operation();\n\t\t} catch (error) {\n\t\t\tthis.restore(snapshot);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\treadTargets(): ContextDeletionTarget[] {\n\t\treturn this.deletionTargets.map(copyDeletionTarget);\n\t}\n\n\treplaceTargets(targets: readonly ContextDeletionTarget[]): void {\n\t\tthis.deletionTargets = targets.map(copyDeletionTarget);\n\t}\n\n\tlistEntriesForGrep(): EntryTextRow[] {\n\t\treturn this.entries.map((entry) => ({\n\t\t\tentry_id: entry.entryId,\n\t\t\ttext: entry.text,\n\t\t\tis_protected: entry.protected ? 1 : 0,\n\t\t\thas_assistant_thinking_blocks: entry.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t}));\n\t}\n\n\tlistContentBlocksForGrep(): ContentBlockTextRow[] {\n\t\treturn [...this.contentBlocks]\n\t\t\t.sort((a, b) => a.entryPosition - b.entryPosition || a.blockIndex - b.blockIndex)\n\t\t\t.map((block) => ({\n\t\t\t\tentry_id: block.entryId,\n\t\t\t\tblock_index: block.blockIndex,\n\t\t\t\trole: block.role,\n\t\t\t\ttype: block.type,\n\t\t\t\ttext: block.text,\n\t\t\t\tentry_protected: this.entriesById.get(block.entryId)?.protected ? 1 : 0,\n\t\t\t\tblock_protected: block.protected ? 1 : 0,\n\t\t\t\tblock_count: this.contentBlockCountByEntryId.get(block.entryId) ?? 0,\n\t\t\t\thas_assistant_thinking_blocks: block.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t\t}));\n\t}\n\n\tgetEntryForRead(entryId: string): EntryReadRow | undefined {\n\t\tconst entry = this.entriesById.get(entryId);\n\t\tif (!entry) return undefined;\n\t\treturn {\n\t\t\tentry_id: entry.entryId,\n\t\t\trole: entry.role,\n\t\t\tis_protected: entry.protected ? 1 : 0,\n\t\t\thas_assistant_thinking_blocks: entry.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t\ttoken_estimate: entry.tokenEstimate,\n\t\t\ttext: entry.text,\n\t\t};\n\t}\n\n\tgetContentBlockForRead(entryId: string, blockIndex: number): ContentBlockReadRow | undefined {\n\t\tconst block = this.contentBlocks.find((candidate) => candidate.entryId === entryId && candidate.blockIndex === blockIndex);\n\t\tif (!block) return undefined;\n\t\treturn {\n\t\t\tentry_id: block.entryId,\n\t\t\tblock_index: block.blockIndex,\n\t\t\trole: block.role,\n\t\t\ttype: block.type,\n\t\t\ttoken_estimate: block.tokenEstimate,\n\t\t\ttext: block.text,\n\t\t\tentry_protected: this.entriesById.get(block.entryId)?.protected ? 1 : 0,\n\t\t\tblock_protected: block.protected ? 1 : 0,\n\t\t\tblock_count: this.contentBlockCountByEntryId.get(block.entryId) ?? 0,\n\t\t\thas_assistant_thinking_blocks: block.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t};\n\t}\n\n\tgetGrepScanTextLength(target: \"entry\" | \"content_block\"): number {\n\t\tconst texts = target === \"entry\" ? this.entries : this.contentBlocks;\n\t\treturn texts.reduce((sum, item) => sum + item.text.length, 0);\n\t}\n\n\tincrementCallCount(): number {\n\t\tthis.callCount += 1;\n\t\treturn this.callCount;\n\t}\n\n\tgetCallCount(): number {\n\t\treturn this.callCount;\n\t}\n\n\tsetLastError(message: string): void {\n\t\tthis.lastError = message;\n\t}\n\n\tclearLastError(): void {\n\t\tthis.lastError = undefined;\n\t}\n\n\tgetLastError(): string | undefined {\n\t\treturn this.lastError;\n\t}\n\n\tprivate snapshot(): ContextDeletionMemorySnapshot {\n\t\treturn {\n\t\t\tdeletionTargets: this.readTargets(),\n\t\t\tcallCount: this.callCount,\n\t\t\t...(this.lastError === undefined ? {} : { lastError: this.lastError }),\n\t\t};\n\t}\n\n\tprivate restore(snapshot: ContextDeletionMemorySnapshot): void {\n\t\tthis.deletionTargets = snapshot.deletionTargets.map(copyDeletionTarget);\n\t\tthis.callCount = snapshot.callCount;\n\t\tthis.lastError = snapshot.lastError;\n\t}\n}\n\nexport function createContextDeletionStore(transcript: CompactableTranscript): ContextDeletionMemoryStore {\n\treturn new ContextDeletionMemoryStore(transcript);\n}\n"]}
1
+ {"version":3,"file":"context-deletion-store.js","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-store.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { ContextDeletionTarget } from \"../session-manager.ts\";\nimport type { CompactableTranscript } from \"./context-compaction-types.ts\";\nimport { assistantEntryHasThinkingContentBlock } from \"./context-assistant-turns.js\";\n\nexport interface EntryTextRow {\n\tentry_id: string;\n\ttext: string;\n\tis_protected: number;\n\thas_assistant_thinking_blocks: number;\n}\n\nexport interface EntryReadRow extends EntryTextRow {\n\trole: string;\n\ttoken_estimate: number;\n}\n\nexport interface ContentBlockTextRow {\n\tentry_id: string;\n\tblock_index: number;\n\trole: AgentMessage[\"role\"];\n\ttype: string;\n\ttext: string;\n\tentry_protected: number;\n\tblock_protected: number;\n\tblock_count: number;\n\thas_assistant_thinking_blocks: number;\n}\n\nexport interface ContentBlockReadRow extends ContentBlockTextRow {\n\ttoken_estimate: number;\n}\n\nexport interface StoredTranscriptEntry {\n\tentryId: string;\n\trole: AgentMessage[\"role\"];\n\tprotected: boolean;\n\thasAssistantThinkingBlocks: boolean;\n\ttokenEstimate: number;\n\ttext: string;\n}\n\nexport interface StoredContentBlock {\n\tentryPosition: number;\n\tentryId: string;\n\tblockIndex: number;\n\trole: AgentMessage[\"role\"];\n\ttype: string;\n\tprotected: boolean;\n\thasAssistantThinkingBlocks: boolean;\n\ttokenEstimate: number;\n\ttext: string;\n}\n\nexport interface ContextDeletionMemorySnapshot {\n\tdeletionTargets: ContextDeletionTarget[];\n\tcallCount: number;\n\tlastError?: string;\n}\n\nfunction copyDeletionTarget(target: ContextDeletionTarget): ContextDeletionTarget {\n\treturn target.kind === \"entry\"\n\t\t? { kind: \"entry\", entryId: target.entryId }\n\t\t: { kind: \"content_block\", entryId: target.entryId, blockIndex: target.blockIndex };\n}\n\nexport class ContextDeletionMemoryStore {\n\tprivate readonly entries: StoredTranscriptEntry[];\n\tprivate readonly entriesById: Map<string, StoredTranscriptEntry>;\n\tprivate readonly contentBlocks: StoredContentBlock[];\n\tprivate readonly contentBlockCountByEntryId: Map<string, number>;\n\tprivate deletionTargets: ContextDeletionTarget[] = [];\n\tprivate callCount = 0;\n\tprivate lastError: string | undefined;\n\n\tconstructor(transcript: CompactableTranscript) {\n\t\tconst entryIds = new Set<string>();\n\t\tconst blockKeys = new Set<string>();\n\t\tthis.entries = transcript.entries.map((entry) => {\n\t\t\tif (entryIds.has(entry.entryId)) {\n\t\t\t\tthrow new Error(`Duplicate transcript entry id: ${entry.entryId}`);\n\t\t\t}\n\t\t\tentryIds.add(entry.entryId);\n\t\t\treturn {\n\t\t\t\tentryId: entry.entryId,\n\t\t\t\trole: entry.role,\n\t\t\t\tprotected: entry.protected,\n\t\t\t\thasAssistantThinkingBlocks: assistantEntryHasThinkingContentBlock(entry),\n\t\t\t\ttokenEstimate: entry.tokenEstimate,\n\t\t\t\ttext: entry.text,\n\t\t\t};\n\t\t});\n\t\tthis.entriesById = new Map<string, StoredTranscriptEntry>(this.entries.map((entry) => [entry.entryId, entry] as const));\n\t\tthis.contentBlocks = transcript.entries.flatMap((entry, entryPosition) => {\n\t\t\tconst hasAssistantThinkingBlocks = assistantEntryHasThinkingContentBlock(entry);\n\t\t\treturn entry.contentBlocks.map((block) => {\n\t\t\t\tif (block.entryId !== entry.entryId) {\n\t\t\t\t\tthrow new Error(`Transcript content block ${block.entryId}:${block.blockIndex} does not belong to entry ${entry.entryId}`);\n\t\t\t\t}\n\t\t\t\tconst blockKey = `${block.entryId}:${block.blockIndex}`;\n\t\t\t\tif (blockKeys.has(blockKey)) {\n\t\t\t\t\tthrow new Error(`Duplicate transcript content block: ${blockKey}`);\n\t\t\t\t}\n\t\t\t\tblockKeys.add(blockKey);\n\t\t\t\treturn {\n\t\t\t\t\tentryPosition,\n\t\t\t\t\tentryId: block.entryId,\n\t\t\t\t\tblockIndex: block.blockIndex,\n\t\t\t\t\trole: entry.role,\n\t\t\t\t\ttype: block.type,\n\t\t\t\t\tprotected: block.protected,\n\t\t\t\t\thasAssistantThinkingBlocks,\n\t\t\t\t\ttokenEstimate: block.tokenEstimate,\n\t\t\t\t\ttext: block.text,\n\t\t\t\t};\n\t\t\t});\n\t\t});\n\t\tthis.contentBlockCountByEntryId = new Map();\n\t\tfor (const block of this.contentBlocks) {\n\t\t\tthis.contentBlockCountByEntryId.set(block.entryId, (this.contentBlockCountByEntryId.get(block.entryId) ?? 0) + 1);\n\t\t}\n\t}\n\n\ttransaction<T>(operation: () => T): T {\n\t\tconst snapshot = this.snapshot();\n\t\ttry {\n\t\t\treturn operation();\n\t\t} catch (error) {\n\t\t\tthis.restore(snapshot);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\treadTargets(): ContextDeletionTarget[] {\n\t\treturn this.deletionTargets.map(copyDeletionTarget);\n\t}\n\n\treplaceTargets(targets: readonly ContextDeletionTarget[]): void {\n\t\tthis.deletionTargets = targets.map(copyDeletionTarget);\n\t}\n\n\tlistEntriesForGrep(): EntryTextRow[] {\n\t\treturn this.entries.map((entry) => ({\n\t\t\tentry_id: entry.entryId,\n\t\t\ttext: entry.text,\n\t\t\tis_protected: entry.protected ? 1 : 0,\n\t\t\thas_assistant_thinking_blocks: entry.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t}));\n\t}\n\n\tlistContentBlocksForGrep(): ContentBlockTextRow[] {\n\t\treturn [...this.contentBlocks]\n\t\t\t.sort((a, b) => a.entryPosition - b.entryPosition || a.blockIndex - b.blockIndex)\n\t\t\t.map((block) => ({\n\t\t\t\tentry_id: block.entryId,\n\t\t\t\tblock_index: block.blockIndex,\n\t\t\t\trole: block.role,\n\t\t\t\ttype: block.type,\n\t\t\t\ttext: block.text,\n\t\t\t\tentry_protected: this.entriesById.get(block.entryId)?.protected ? 1 : 0,\n\t\t\t\tblock_protected: block.protected ? 1 : 0,\n\t\t\t\tblock_count: this.contentBlockCountByEntryId.get(block.entryId) ?? 0,\n\t\t\t\thas_assistant_thinking_blocks: block.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t\t}));\n\t}\n\n\tgetEntryForRead(entryId: string): EntryReadRow | undefined {\n\t\tconst entry = this.entriesById.get(entryId);\n\t\tif (!entry) return undefined;\n\t\treturn {\n\t\t\tentry_id: entry.entryId,\n\t\t\trole: entry.role,\n\t\t\tis_protected: entry.protected ? 1 : 0,\n\t\t\thas_assistant_thinking_blocks: entry.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t\ttoken_estimate: entry.tokenEstimate,\n\t\t\ttext: entry.text,\n\t\t};\n\t}\n\n\tgetContentBlockForRead(entryId: string, blockIndex: number): ContentBlockReadRow | undefined {\n\t\tconst block = this.contentBlocks.find((candidate) => candidate.entryId === entryId && candidate.blockIndex === blockIndex);\n\t\tif (!block) return undefined;\n\t\treturn {\n\t\t\tentry_id: block.entryId,\n\t\t\tblock_index: block.blockIndex,\n\t\t\trole: block.role,\n\t\t\ttype: block.type,\n\t\t\ttoken_estimate: block.tokenEstimate,\n\t\t\ttext: block.text,\n\t\t\tentry_protected: this.entriesById.get(block.entryId)?.protected ? 1 : 0,\n\t\t\tblock_protected: block.protected ? 1 : 0,\n\t\t\tblock_count: this.contentBlockCountByEntryId.get(block.entryId) ?? 0,\n\t\t\thas_assistant_thinking_blocks: block.hasAssistantThinkingBlocks ? 1 : 0,\n\t\t};\n\t}\n\n\tgetGrepScanTextLength(target: \"entry\" | \"content_block\"): number {\n\t\tconst texts = target === \"entry\" ? this.entries : this.contentBlocks;\n\t\treturn texts.reduce((sum, item) => sum + item.text.length, 0);\n\t}\n\n\tincrementCallCount(): number {\n\t\tthis.callCount += 1;\n\t\treturn this.callCount;\n\t}\n\n\tgetCallCount(): number {\n\t\treturn this.callCount;\n\t}\n\n\tsetLastError(message: string): void {\n\t\tthis.lastError = message;\n\t}\n\n\tclearLastError(): void {\n\t\tthis.lastError = undefined;\n\t}\n\n\tgetLastError(): string | undefined {\n\t\treturn this.lastError;\n\t}\n\n\tprivate snapshot(): ContextDeletionMemorySnapshot {\n\t\treturn {\n\t\t\tdeletionTargets: this.readTargets(),\n\t\t\tcallCount: this.callCount,\n\t\t\t...(this.lastError === undefined ? {} : { lastError: this.lastError }),\n\t\t};\n\t}\n\n\tprivate restore(snapshot: ContextDeletionMemorySnapshot): void {\n\t\tthis.deletionTargets = snapshot.deletionTargets.map(copyDeletionTarget);\n\t\tthis.callCount = snapshot.callCount;\n\t\tthis.lastError = snapshot.lastError;\n\t}\n}\n\nexport function createContextDeletionStore(transcript: CompactableTranscript): ContextDeletionMemoryStore {\n\treturn new ContextDeletionMemoryStore(transcript);\n}\n"]}
@@ -34,7 +34,8 @@ export declare function deleteEntryTarget(targets: ContextDeletionTarget[], entr
34
34
  export declare function mergeContextDeletionTargets(baseTargets: readonly ContextDeletionTarget[], additionalTargets: readonly ContextDeletionTarget[]): ContextDeletionTarget[];
35
35
  export declare function canonicalizeEntryTargets(transcript: CompactableTranscript, targets: ContextDeletionTarget[], entry: CompactableTranscriptEntry): boolean;
36
36
  export declare function addToolCallDeletion(transcript: CompactableTranscript, targets: ContextDeletionTarget[], entry: CompactableTranscriptEntry, callId: string): boolean;
37
- export declare function isTaskBearingEntry(entry: CompactableTranscriptEntry): boolean;
37
+ /** Whether a task-bearing entry remains provider-visible after proposed block deletions. */
38
+ export declare function isTaskBearingEntry(entry: CompactableTranscriptEntry, deletedContentBlocks?: ReadonlySet<number>): boolean;
38
39
  export declare function isRecentTarget(transcript: CompactableTranscript, target: ContextDeletionTarget): boolean;
39
40
  export declare function isStaleUserImageOnlyEntry(transcript: CompactableTranscript, entry: CompactableTranscriptEntry): boolean;
40
41
  export declare function canDeleteStaleUserImageContentBlock(transcript: CompactableTranscript, target: ContextDeletionTarget): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"context-deletion-targets.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-targets.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextDeletionTarget } from \"../session-manager.ts\";\nimport type {\n\tCompactableContentBlock,\n\tCompactableTranscript,\n\tCompactableTranscriptEntry,\n\tContextDeletionRequest,\n} from \"./context-compaction-types.ts\";\nimport { getTranscriptCompactionParameters } from \"./context-compaction-strategy.ts\";\nimport { assistantEntryHasThinkingContentBlock } from \"./context-transcript-analysis.ts\";\n\nexport function targetKey(target: ContextDeletionTarget): string {\n\treturn target.kind === \"entry\" ? `entry:${target.entryId}` : `content_block:${target.entryId}:${target.blockIndex}`;\n}\n\nexport function rawTargetKey(target: ContextDeletionRequest[\"deletions\"][number]): string {\n\treturn target.kind === \"entry\" ? `entry:${target.entryId}` : `content_block:${target.entryId}:${target.blockIndex}`;\n}\n\nexport function normalizeRawTarget(target: ContextDeletionRequest[\"deletions\"][number]): ContextDeletionTarget {\n\tif (target.kind === \"entry\") return { kind: \"entry\", entryId: target.entryId };\n\treturn { kind: \"content_block\", entryId: target.entryId, blockIndex: target.blockIndex as number };\n}\n\nexport function assertIdOnlyDeletionTarget(target: Record<string, unknown>): void {\n\tconst allowedKeys = target.kind === \"content_block\" ? new Set([\"kind\", \"entryId\", \"blockIndex\"]) : new Set([\"kind\", \"entryId\"]);\n\tfor (const key of Object.keys(target)) {\n\t\tif (!allowedKeys.has(key)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Deletion target includes unsupported property ${JSON.stringify(key)}; context deletion targets are id-only and must contain only kind, entryId${target.kind === \"content_block\" ? \", and blockIndex\" : \"\"}`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport function rawDeletionFromTarget(target: ContextDeletionTarget): ContextDeletionRequest[\"deletions\"][number] {\n\tif (target.kind === \"entry\") return { kind: \"entry\", entryId: target.entryId };\n\treturn { kind: \"content_block\", entryId: target.entryId, blockIndex: target.blockIndex };\n}\n\nexport function deletionRequestFromTargets(targets: readonly ContextDeletionTarget[]): ContextDeletionRequest {\n\treturn { deletions: targets.map(rawDeletionFromTarget) };\n}\n\nexport function getDeletedEntryIds(targets: readonly ContextDeletionTarget[]): Set<string> {\n\treturn new Set(targets.filter((target) => target.kind === \"entry\").map((target) => target.entryId));\n}\n\nexport function getDeletedContentBlocks(targets: readonly ContextDeletionTarget[]): Map<string, Set<number>> {\n\tconst blocksByEntry = new Map<string, Set<number>>();\n\tfor (const target of targets) {\n\t\tif (target.kind !== \"content_block\") continue;\n\t\tconst blocks = blocksByEntry.get(target.entryId) ?? new Set<number>();\n\t\tblocks.add(target.blockIndex);\n\t\tblocksByEntry.set(target.entryId, blocks);\n\t}\n\treturn blocksByEntry;\n}\n\nexport function recentContextEntryBoundary(transcript: CompactableTranscript): number {\n\tconst { preserve_recent } = getTranscriptCompactionParameters(transcript);\n\treturn preserve_recent > 0 ? Math.max(0, transcript.entries.length - preserve_recent) : transcript.entries.length;\n}\n\nexport function getRecentContextEntryIds(transcript: CompactableTranscript): Set<string> {\n\tconst { preserve_recent } = getTranscriptCompactionParameters(transcript);\n\tif (preserve_recent <= 0) return new Set();\n\treturn new Set(transcript.entries.slice(recentContextEntryBoundary(transcript)).map((entry) => entry.entryId));\n}\n\nexport function isRecentContextEntry(entry: CompactableTranscriptEntry, transcript: CompactableTranscript): boolean {\n\tconst { preserve_recent } = getTranscriptCompactionParameters(transcript);\n\tif (preserve_recent <= 0) return false;\n\tconst entryIndex = transcript.entries.findIndex((candidate) => candidate.entryId === entry.entryId);\n\treturn entryIndex >= 0 && entryIndex >= recentContextEntryBoundary(transcript);\n}\n\nexport function formatRecentContextDeletionError(transcript: CompactableTranscript, target: ContextDeletionTarget): string {\n\tconst { preserve_recent } = getTranscriptCompactionParameters(transcript);\n\tconst recentWindow = `last ${preserve_recent} context ${preserve_recent === 1 ? \"entry\" : \"entries\"}`;\n\tif (target.kind === \"entry\") {\n\t\treturn `Cannot delete recent context entry ${target.entryId} because the ${recentWindow} must remain available for active continuity. Choose an older entry.`;\n\t}\n\treturn `Cannot delete content block ${target.entryId}:${target.blockIndex} because entry ${target.entryId} is one of the ${recentWindow} that must remain available for active continuity. Choose an older entry or content block.`;\n}\n\nexport function deletionGuidance(): string {\n\treturn \"Choose another deletion candidate.\";\n}\n\nexport function findTranscriptEntry(transcript: CompactableTranscript, entryId: string): CompactableTranscriptEntry | undefined {\n\treturn transcript.entries.find((entry) => entry.entryId === entryId);\n}\n\nexport function findTranscriptContentBlock(\n\ttranscript: CompactableTranscript,\n\ttarget: ContextDeletionTarget,\n): CompactableContentBlock | undefined {\n\tif (target.kind !== \"content_block\") return undefined;\n\treturn findTranscriptEntry(transcript, target.entryId)?.contentBlocks.find((block) => block.blockIndex === target.blockIndex);\n}\n\nexport function firstToolCallBlockTarget(\n\tentry: CompactableTranscriptEntry,\n\tcallId: string,\n): ContextDeletionTarget | undefined {\n\tconst blockIndex = toolCallBlockIndexes(entry, callId)[0];\n\treturn blockIndex === undefined ? undefined : { kind: \"content_block\", entryId: entry.entryId, blockIndex };\n}\n\nexport function formatProtectedDeletionError(transcript: CompactableTranscript, target: ContextDeletionTarget): string {\n\tconst entry = findTranscriptEntry(transcript, target.entryId);\n\tif (target.kind === \"entry\") {\n\t\tconst toolResultSuffix = entry?.toolResultFor ? ` for tool call ${entry.toolResultFor}` : \"\";\n\t\tconst toolCallSuffix = entry && entry.toolCallIds.length > 0 ? ` containing tool call ${entry.toolCallIds.join(\", \")}` : \"\";\n\t\treturn `Deletion target ${target.entryId}${toolResultSuffix}${toolCallSuffix} is protected. ${deletionGuidance()}`;\n\t}\n\n\tconst block = findTranscriptContentBlock(transcript, target);\n\tconst toolBlockSuffix = block?.toolCallId ? ` It is a protected tool block for tool call ${block.toolCallId}.` : \"\";\n\treturn `Content block ${target.entryId}:${target.blockIndex} is protected.${toolBlockSuffix} ${deletionGuidance()}`;\n}\n\nexport function formatProtectedToolDependencyError(\n\ttranscript: CompactableTranscript,\n\tblockedTarget: ContextDeletionTarget,\n\tcontext: string,\n): string {\n\tconst protectedMessage = formatProtectedDeletionError(transcript, blockedTarget);\n\treturn `${context} ${protectedMessage}`;\n}\n\nexport function isProtectedContextDeletionErrorMessage(message: string): boolean {\n\treturn (\n\t\t/\\bprotected\\b/i.test(message) ||\n\t\t/Cannot delete (?:recent context entry|content block .* because entry .* is one of the last)/u.test(message) ||\n\t\t/latest assistant message|thinking\\/redacted_thinking block in (?:the latest|a retained) assistant message/u.test(message)\n\t);\n}\n\nexport function assertNoRecentContextDeletionTargets(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): void {\n\tconst recentEntryIds = getRecentContextEntryIds(transcript);\n\tfor (const target of targets) {\n\t\tif (recentEntryIds.has(target.entryId)) {\n\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, target));\n\t\t}\n\t}\n}\n\nexport function latestAssistantEntry(\n\ttranscript: CompactableTranscript,\n\tdeletedEntryIds: ReadonlySet<string> = new Set<string>(),\n): CompactableTranscriptEntry | undefined {\n\tfor (let index = transcript.entries.length - 1; index >= 0; index--) {\n\t\tconst entry = transcript.entries[index];\n\t\tif (entry.role === \"assistant\" && !deletedEntryIds.has(entry.entryId)) return entry;\n\t}\n\treturn undefined;\n}\n\nexport function findAssistantThinkingContentBlockDeletionViolation(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): Extract<ContextDeletionTarget, { kind: \"content_block\" }> | undefined {\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tfor (const target of targets) {\n\t\tif (target.kind !== \"content_block\") continue;\n\t\tif (deletedEntryIds.has(target.entryId)) continue;\n\t\tconst entry = findTranscriptEntry(transcript, target.entryId);\n\t\tif (entry && assistantEntryHasThinkingContentBlock(entry)) return target;\n\t}\n\treturn undefined;\n}\n\nexport function findLatestAssistantThinkingDeletionViolation(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): ContextDeletionTarget | undefined {\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tconst latestRetainedAssistant = latestAssistantEntry(transcript, deletedEntryIds);\n\n\tfor (const target of targets) {\n\t\tif (target.kind === \"entry\") {\n\t\t\tconst entry = findTranscriptEntry(transcript, target.entryId);\n\t\t\tif (!entry || !assistantEntryHasThinkingContentBlock(entry)) continue;\n\t\t\tconst deletedEntryIdsIfTargetWereKept = new Set(deletedEntryIds);\n\t\t\tdeletedEntryIdsIfTargetWereKept.delete(target.entryId);\n\t\t\tif (latestAssistantEntry(transcript, deletedEntryIdsIfTargetWereKept)?.entryId === target.entryId) {\n\t\t\t\treturn target;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\tlatestRetainedAssistant?.entryId === target.entryId &&\n\t\t\tassistantEntryHasThinkingContentBlock(latestRetainedAssistant)\n\t\t) {\n\t\t\treturn target;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport function assertNoAssistantThinkingContentBlockDeletionTargets(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): void {\n\tconst violation = findAssistantThinkingContentBlockDeletionViolation(transcript, targets);\n\tif (!violation) return;\n\tthrow new Error(\n\t\t`Cannot delete content block ${violation.entryId}:${violation.blockIndex} because a thinking/redacted_thinking block in a retained assistant message must remain unmodified; retained assistant messages containing thinking/redacted_thinking content blocks are all-or-nothing`,\n\t);\n}\n\nexport function assertNoLatestAssistantThinkingDeletionTargets(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): void {\n\tconst violation = findLatestAssistantThinkingDeletionViolation(transcript, targets);\n\tif (!violation) return;\n\tif (violation.kind === \"entry\") {\n\t\tthrow new Error(\n\t\t\t`Cannot delete assistant entry ${violation.entryId} because it is the latest assistant message retained after other deletions and contains thinking/redacted_thinking content blocks`,\n\t\t);\n\t}\n\tthrow new Error(\n\t\t`Cannot delete content block ${violation.entryId}:${violation.blockIndex} because a thinking/redacted_thinking block in the latest assistant message must remain unmodified; the latest retained assistant message contains thinking/redacted_thinking content blocks`,\n\t);\n}\n\nexport function isToolCallBlockDeleted(\n\tentry: CompactableTranscriptEntry,\n\tcallId: string,\n\tdeletedEntryIds: ReadonlySet<string>,\n\tdeletedContentBlocks: ReadonlyMap<string, ReadonlySet<number>>,\n): boolean {\n\tif (deletedEntryIds.has(entry.entryId)) return true;\n\tconst deletedBlocks = deletedContentBlocks.get(entry.entryId);\n\tif (!deletedBlocks) return false;\n\treturn entry.contentBlocks.some((block) => block.toolCallId === callId && deletedBlocks.has(block.blockIndex));\n}\n\nexport function toolCallBlockIndexes(entry: CompactableTranscriptEntry, callId: string): number[] {\n\treturn entry.contentBlocks\n\t\t.filter((block) => block.toolCallId === callId)\n\t\t.map((block) => block.blockIndex);\n}\n\nexport function addTarget(targets: ContextDeletionTarget[], target: ContextDeletionTarget): boolean {\n\tif (targets.some((existing) => targetKey(existing) === targetKey(target))) return false;\n\ttargets.push(target);\n\treturn true;\n}\n\nexport function deleteEntryTarget(targets: ContextDeletionTarget[], entryId: string): boolean {\n\tlet changed = false;\n\tfor (let index = targets.length - 1; index >= 0; index--) {\n\t\tconst target = targets[index];\n\t\tif (target.kind === \"content_block\" && target.entryId === entryId) {\n\t\t\ttargets.splice(index, 1);\n\t\t\tchanged = true;\n\t\t}\n\t}\n\treturn addTarget(targets, { kind: \"entry\", entryId }) || changed;\n}\n\nexport function mergeContextDeletionTargets(\n\tbaseTargets: readonly ContextDeletionTarget[],\n\tadditionalTargets: readonly ContextDeletionTarget[],\n): ContextDeletionTarget[] {\n\tconst targets = [...baseTargets];\n\tfor (const target of additionalTargets) {\n\t\tif (target.kind === \"entry\") {\n\t\t\tdeleteEntryTarget(targets, target.entryId);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!getDeletedEntryIds(targets).has(target.entryId)) {\n\t\t\taddTarget(targets, target);\n\t\t}\n\t}\n\treturn targets;\n}\n\nexport function canonicalizeEntryTargets(\n\ttranscript: CompactableTranscript,\n\ttargets: ContextDeletionTarget[],\n\tentry: CompactableTranscriptEntry,\n): boolean {\n\tif (!canDeleteTarget(transcript, { kind: \"entry\", entryId: entry.entryId })) return false;\n\tif (getDeletedEntryIds(targets).has(entry.entryId)) return false;\n\tconst deletedBlocks = getDeletedContentBlocks(targets).get(entry.entryId);\n\tif (!deletedBlocks || !entry.contentBlocks.every((block) => deletedBlocks.has(block.blockIndex))) return false;\n\t// Only repair/promote when dependency reconciliation reaches this entry. Non-tool entries that\n\t// request every block individually stay invalid so the assistant must choose explicit entry deletion.\n\treturn deleteEntryTarget(targets, entry.entryId);\n}\n\nexport function addToolCallDeletion(\n\ttranscript: CompactableTranscript,\n\ttargets: ContextDeletionTarget[],\n\tentry: CompactableTranscriptEntry,\n\tcallId: string,\n): boolean {\n\tif (assistantEntryHasThinkingContentBlock(entry)) {\n\t\tif (!canDeleteTarget(transcript, { kind: \"entry\", entryId: entry.entryId })) return false;\n\t\treturn deleteEntryTarget(targets, entry.entryId);\n\t}\n\n\tlet changed = false;\n\tfor (const blockIndex of toolCallBlockIndexes(entry, callId)) {\n\t\tconst target: ContextDeletionTarget = { kind: \"content_block\", entryId: entry.entryId, blockIndex };\n\t\tif (!canDeleteTarget(transcript, target)) continue;\n\t\tif (!getDeletedEntryIds(targets).has(entry.entryId)) {\n\t\t\tchanged = addTarget(targets, target) || changed;\n\t\t}\n\t}\n\treturn canonicalizeEntryTargets(transcript, targets, entry) || changed;\n}\n\nexport function isTaskBearingEntry(entry: CompactableTranscriptEntry): boolean {\n\treturn (\n\t\tentry.role === \"user\" ||\n\t\tentry.role === \"custom\" ||\n\t\tentry.role === \"branchSummary\" ||\n\t\tentry.entryType === \"branch_summary\"\n\t);\n}\n\nexport function isRecentTarget(transcript: CompactableTranscript, target: ContextDeletionTarget): boolean {\n\tconst entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);\n\treturn entry !== undefined && isRecentContextEntry(entry, transcript);\n}\n\nexport function isStaleUserImageOnlyEntry(transcript: CompactableTranscript, entry: CompactableTranscriptEntry): boolean {\n\tif (entry.role !== \"user\" || isRecentContextEntry(entry, transcript)) return false;\n\tif (entry.contentBlocks.length === 0 || !entry.contentBlocks.every((block) => block.type === \"image\")) return false;\n\treturn transcript.entries.some((candidate) => candidate.entryId !== entry.entryId && isTaskBearingEntry(candidate));\n}\n\nexport function canDeleteStaleUserImageContentBlock(\n\ttranscript: CompactableTranscript,\n\ttarget: ContextDeletionTarget,\n): boolean {\n\tif (target.kind !== \"content_block\") return false;\n\tconst entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);\n\tif (!entry || entry.role !== \"user\" || isRecentTarget(transcript, target)) return false;\n\tconst block = entry.contentBlocks.find((candidate) => candidate.blockIndex === target.blockIndex);\n\tif (!block || block.type !== \"image\") return false;\n\treturn entry.contentBlocks.some((candidate) => candidate.blockIndex !== target.blockIndex && candidate.type !== \"image\");\n}\n\nexport function canDeleteTarget(transcript: CompactableTranscript, target: ContextDeletionTarget): boolean {\n\tconst entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);\n\tif (!entry) return false;\n\tif (isRecentTarget(transcript, target)) return false;\n\tif (target.kind === \"entry\") return isStaleUserImageOnlyEntry(transcript, entry) || !entry.protected;\n\tconst block = entry.contentBlocks.find((candidate) => candidate.blockIndex === target.blockIndex);\n\tif (!block) return false;\n\tif (canDeleteStaleUserImageContentBlock(transcript, target)) return true;\n\tif (entry.protected) return false;\n\treturn !block.protected;\n}\n\n"]}
1
+ {"version":3,"file":"context-deletion-targets.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-deletion-targets.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextDeletionTarget } from \"../session-manager.ts\";\nimport type {\n\tCompactableContentBlock,\n\tCompactableTranscript,\n\tCompactableTranscriptEntry,\n\tContextDeletionRequest,\n} from \"./context-compaction-types.ts\";\nimport { getTranscriptCompactionParameters } from \"./context-compaction-strategy.ts\";\nimport {\n\tanalyzeCompactableAssistantTurns,\n\tassistantEntryHasThinkingContentBlock,\n\tcompactableContentBlockIsLlmVisible,\n\ttranscriptEntryStartsNewTurn,\n} from \"./context-assistant-turns.js\";\n\ninterface AssistantTurnDeletionViolation {\n\tentryId: string;\n\tactive: boolean;\n}\n\nfunction findAssistantTurnDeletionViolation(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): AssistantTurnDeletionViolation | undefined {\n\tconst { deletedEntryIds, turns } = analyzeCompactableAssistantTurns(transcript, targets);\n\tfor (const turn of turns) {\n\t\tif (turn.signedThinkingEntryIds.length === 0) continue;\n\t\tconst deleted = turn.signedThinkingEntryIds.filter((entryId) => deletedEntryIds.has(entryId));\n\t\tif (turn.active && deleted.length > 0) return { entryId: deleted[0]!, active: true };\n\t\tif (!turn.active && deleted.length > 0 && deleted.length < turn.signedThinkingEntryIds.length) {\n\t\t\treturn { entryId: deleted[0]!, active: false };\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport function targetKey(target: ContextDeletionTarget): string {\n\treturn target.kind === \"entry\" ? `entry:${target.entryId}` : `content_block:${target.entryId}:${target.blockIndex}`;\n}\n\nexport function rawTargetKey(target: ContextDeletionRequest[\"deletions\"][number]): string {\n\treturn target.kind === \"entry\" ? `entry:${target.entryId}` : `content_block:${target.entryId}:${target.blockIndex}`;\n}\n\nexport function normalizeRawTarget(target: ContextDeletionRequest[\"deletions\"][number]): ContextDeletionTarget {\n\tif (target.kind === \"entry\") return { kind: \"entry\", entryId: target.entryId };\n\treturn { kind: \"content_block\", entryId: target.entryId, blockIndex: target.blockIndex as number };\n}\n\nexport function assertIdOnlyDeletionTarget(target: Record<string, unknown>): void {\n\tconst allowedKeys = target.kind === \"content_block\" ? new Set([\"kind\", \"entryId\", \"blockIndex\"]) : new Set([\"kind\", \"entryId\"]);\n\tfor (const key of Object.keys(target)) {\n\t\tif (!allowedKeys.has(key)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Deletion target includes unsupported property ${JSON.stringify(key)}; context deletion targets are id-only and must contain only kind, entryId${target.kind === \"content_block\" ? \", and blockIndex\" : \"\"}`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport function rawDeletionFromTarget(target: ContextDeletionTarget): ContextDeletionRequest[\"deletions\"][number] {\n\tif (target.kind === \"entry\") return { kind: \"entry\", entryId: target.entryId };\n\treturn { kind: \"content_block\", entryId: target.entryId, blockIndex: target.blockIndex };\n}\n\nexport function deletionRequestFromTargets(targets: readonly ContextDeletionTarget[]): ContextDeletionRequest {\n\treturn { deletions: targets.map(rawDeletionFromTarget) };\n}\n\nexport function getDeletedEntryIds(targets: readonly ContextDeletionTarget[]): Set<string> {\n\treturn new Set(targets.filter((target) => target.kind === \"entry\").map((target) => target.entryId));\n}\n\nexport function getDeletedContentBlocks(targets: readonly ContextDeletionTarget[]): Map<string, Set<number>> {\n\tconst blocksByEntry = new Map<string, Set<number>>();\n\tfor (const target of targets) {\n\t\tif (target.kind !== \"content_block\") continue;\n\t\tconst blocks = blocksByEntry.get(target.entryId) ?? new Set<number>();\n\t\tblocks.add(target.blockIndex);\n\t\tblocksByEntry.set(target.entryId, blocks);\n\t}\n\treturn blocksByEntry;\n}\n\nexport function recentContextEntryBoundary(transcript: CompactableTranscript): number {\n\tconst { preserve_recent } = getTranscriptCompactionParameters(transcript);\n\treturn preserve_recent > 0 ? Math.max(0, transcript.entries.length - preserve_recent) : transcript.entries.length;\n}\n\nexport function getRecentContextEntryIds(transcript: CompactableTranscript): Set<string> {\n\tconst { preserve_recent } = getTranscriptCompactionParameters(transcript);\n\tif (preserve_recent <= 0) return new Set();\n\treturn new Set(transcript.entries.slice(recentContextEntryBoundary(transcript)).map((entry) => entry.entryId));\n}\n\nexport function isRecentContextEntry(entry: CompactableTranscriptEntry, transcript: CompactableTranscript): boolean {\n\tconst { preserve_recent } = getTranscriptCompactionParameters(transcript);\n\tif (preserve_recent <= 0) return false;\n\tconst entryIndex = transcript.entries.findIndex((candidate) => candidate.entryId === entry.entryId);\n\treturn entryIndex >= 0 && entryIndex >= recentContextEntryBoundary(transcript);\n}\n\nexport function formatRecentContextDeletionError(transcript: CompactableTranscript, target: ContextDeletionTarget): string {\n\tconst { preserve_recent } = getTranscriptCompactionParameters(transcript);\n\tconst recentWindow = `last ${preserve_recent} context ${preserve_recent === 1 ? \"entry\" : \"entries\"}`;\n\tif (target.kind === \"entry\") {\n\t\treturn `Cannot delete recent context entry ${target.entryId} because the ${recentWindow} must remain available for active continuity. Choose an older entry.`;\n\t}\n\treturn `Cannot delete content block ${target.entryId}:${target.blockIndex} because entry ${target.entryId} is one of the ${recentWindow} that must remain available for active continuity. Choose an older entry or content block.`;\n}\n\nexport function deletionGuidance(): string {\n\treturn \"Choose another deletion candidate.\";\n}\n\nexport function findTranscriptEntry(transcript: CompactableTranscript, entryId: string): CompactableTranscriptEntry | undefined {\n\treturn transcript.entries.find((entry) => entry.entryId === entryId);\n}\n\nexport function findTranscriptContentBlock(\n\ttranscript: CompactableTranscript,\n\ttarget: ContextDeletionTarget,\n): CompactableContentBlock | undefined {\n\tif (target.kind !== \"content_block\") return undefined;\n\treturn findTranscriptEntry(transcript, target.entryId)?.contentBlocks.find((block) => block.blockIndex === target.blockIndex);\n}\n\nexport function firstToolCallBlockTarget(\n\tentry: CompactableTranscriptEntry,\n\tcallId: string,\n): ContextDeletionTarget | undefined {\n\tconst blockIndex = toolCallBlockIndexes(entry, callId)[0];\n\treturn blockIndex === undefined ? undefined : { kind: \"content_block\", entryId: entry.entryId, blockIndex };\n}\n\nexport function formatProtectedDeletionError(transcript: CompactableTranscript, target: ContextDeletionTarget): string {\n\tconst entry = findTranscriptEntry(transcript, target.entryId);\n\tif (target.kind === \"entry\") {\n\t\tconst toolResultSuffix = entry?.toolResultFor ? ` for tool call ${entry.toolResultFor}` : \"\";\n\t\tconst toolCallSuffix = entry && entry.toolCallIds.length > 0 ? ` containing tool call ${entry.toolCallIds.join(\", \")}` : \"\";\n\t\treturn `Deletion target ${target.entryId}${toolResultSuffix}${toolCallSuffix} is protected. ${deletionGuidance()}`;\n\t}\n\n\tconst block = findTranscriptContentBlock(transcript, target);\n\tconst toolBlockSuffix = block?.toolCallId ? ` It is a protected tool block for tool call ${block.toolCallId}.` : \"\";\n\treturn `Content block ${target.entryId}:${target.blockIndex} is protected.${toolBlockSuffix} ${deletionGuidance()}`;\n}\n\nexport function formatProtectedToolDependencyError(\n\ttranscript: CompactableTranscript,\n\tblockedTarget: ContextDeletionTarget,\n\tcontext: string,\n): string {\n\tconst protectedMessage = formatProtectedDeletionError(transcript, blockedTarget);\n\treturn `${context} ${protectedMessage}`;\n}\n\n// Keep legacy protection phrases recognizable for callers handling errors\n// produced by older compaction plans and extension versions.\nexport function isProtectedContextDeletionErrorMessage(message: string): boolean {\n\treturn (\n\t\t/\\bprotected\\b/i.test(message) ||\n\t\t/Cannot delete (?:recent context entry|content block .* because entry .* is one of the last)/u.test(message) ||\n\t\t/latest assistant message|active assistant tool-use turn|completed assistant tool-use turn|thinking\\/redacted_thinking block in (?:the latest|a retained) assistant message/u.test(message)\n\t);\n}\n\nexport function assertNoRecentContextDeletionTargets(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): void {\n\tconst recentEntryIds = getRecentContextEntryIds(transcript);\n\tfor (const target of targets) {\n\t\tif (recentEntryIds.has(target.entryId)) {\n\t\t\tthrow new Error(formatRecentContextDeletionError(transcript, target));\n\t\t}\n\t}\n}\n\nexport function latestAssistantEntry(\n\ttranscript: CompactableTranscript,\n\tdeletedEntryIds: ReadonlySet<string> = new Set<string>(),\n): CompactableTranscriptEntry | undefined {\n\tfor (let index = transcript.entries.length - 1; index >= 0; index--) {\n\t\tconst entry = transcript.entries[index];\n\t\tif (entry.role === \"assistant\" && !deletedEntryIds.has(entry.entryId)) return entry;\n\t}\n\treturn undefined;\n}\n\nexport function findAssistantThinkingContentBlockDeletionViolation(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): Extract<ContextDeletionTarget, { kind: \"content_block\" }> | undefined {\n\tconst deletedEntryIds = getDeletedEntryIds(targets);\n\tfor (const target of targets) {\n\t\tif (target.kind !== \"content_block\") continue;\n\t\tif (deletedEntryIds.has(target.entryId)) continue;\n\t\tconst entry = findTranscriptEntry(transcript, target.entryId);\n\t\tif (entry && assistantEntryHasThinkingContentBlock(entry)) return target;\n\t}\n\treturn undefined;\n}\n\nexport function findLatestAssistantThinkingDeletionViolation(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): ContextDeletionTarget | undefined {\n\tconst violation = findAssistantTurnDeletionViolation(transcript, targets);\n\tif (!violation) return undefined;\n\treturn targets.find((target) => target.kind === \"entry\" && target.entryId === violation.entryId);\n}\n\nexport function assertNoAssistantThinkingContentBlockDeletionTargets(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): void {\n\tconst violation = findAssistantThinkingContentBlockDeletionViolation(transcript, targets);\n\tif (!violation) return;\n\tthrow new Error(\n\t\t`Cannot delete content block ${violation.entryId}:${violation.blockIndex} because a thinking/redacted_thinking block in a retained assistant message must remain unmodified; retained assistant messages containing thinking/redacted_thinking content blocks are all-or-nothing`,\n\t);\n}\n\nexport function assertNoLatestAssistantThinkingDeletionTargets(\n\ttranscript: CompactableTranscript,\n\ttargets: readonly ContextDeletionTarget[],\n): void {\n\tconst violation = findAssistantTurnDeletionViolation(transcript, targets);\n\tif (!violation) return;\n\tif (violation.active) {\n\t\tthrow new Error(\n\t\t\t`Cannot delete assistant entry ${violation.entryId} because the active assistant tool-use turn must retain every thinking/redacted_thinking-bearing assistant entry`,\n\t\t);\n\t}\n\tthrow new Error(\n\t\t`Cannot delete assistant entry ${violation.entryId} because a completed assistant tool-use turn must retain all or omit all thinking/redacted_thinking-bearing assistant entries`,\n\t);\n}\n\nexport function isToolCallBlockDeleted(\n\tentry: CompactableTranscriptEntry,\n\tcallId: string,\n\tdeletedEntryIds: ReadonlySet<string>,\n\tdeletedContentBlocks: ReadonlyMap<string, ReadonlySet<number>>,\n): boolean {\n\tif (deletedEntryIds.has(entry.entryId)) return true;\n\tconst deletedBlocks = deletedContentBlocks.get(entry.entryId);\n\tif (!deletedBlocks) return false;\n\treturn entry.contentBlocks.some((block) => block.toolCallId === callId && deletedBlocks.has(block.blockIndex));\n}\n\nexport function toolCallBlockIndexes(entry: CompactableTranscriptEntry, callId: string): number[] {\n\treturn entry.contentBlocks\n\t\t.filter((block) => block.toolCallId === callId)\n\t\t.map((block) => block.blockIndex);\n}\n\nexport function addTarget(targets: ContextDeletionTarget[], target: ContextDeletionTarget): boolean {\n\tif (targets.some((existing) => targetKey(existing) === targetKey(target))) return false;\n\ttargets.push(target);\n\treturn true;\n}\n\nexport function deleteEntryTarget(targets: ContextDeletionTarget[], entryId: string): boolean {\n\tlet changed = false;\n\tfor (let index = targets.length - 1; index >= 0; index--) {\n\t\tconst target = targets[index];\n\t\tif (target.kind === \"content_block\" && target.entryId === entryId) {\n\t\t\ttargets.splice(index, 1);\n\t\t\tchanged = true;\n\t\t}\n\t}\n\treturn addTarget(targets, { kind: \"entry\", entryId }) || changed;\n}\n\nexport function mergeContextDeletionTargets(\n\tbaseTargets: readonly ContextDeletionTarget[],\n\tadditionalTargets: readonly ContextDeletionTarget[],\n): ContextDeletionTarget[] {\n\tconst targets = [...baseTargets];\n\tfor (const target of additionalTargets) {\n\t\tif (target.kind === \"entry\") {\n\t\t\tdeleteEntryTarget(targets, target.entryId);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!getDeletedEntryIds(targets).has(target.entryId)) {\n\t\t\taddTarget(targets, target);\n\t\t}\n\t}\n\treturn targets;\n}\n\nexport function canonicalizeEntryTargets(\n\ttranscript: CompactableTranscript,\n\ttargets: ContextDeletionTarget[],\n\tentry: CompactableTranscriptEntry,\n): boolean {\n\tif (!canDeleteTarget(transcript, { kind: \"entry\", entryId: entry.entryId })) return false;\n\tif (getDeletedEntryIds(targets).has(entry.entryId)) return false;\n\tconst deletedBlocks = getDeletedContentBlocks(targets).get(entry.entryId);\n\tif (!deletedBlocks || !entry.contentBlocks.every((block) => deletedBlocks.has(block.blockIndex))) return false;\n\t// Only repair/promote when dependency reconciliation reaches this entry. Non-tool entries that\n\t// request every block individually stay invalid so the assistant must choose explicit entry deletion.\n\treturn deleteEntryTarget(targets, entry.entryId);\n}\n\nexport function addToolCallDeletion(\n\ttranscript: CompactableTranscript,\n\ttargets: ContextDeletionTarget[],\n\tentry: CompactableTranscriptEntry,\n\tcallId: string,\n): boolean {\n\tif (assistantEntryHasThinkingContentBlock(entry)) {\n\t\tif (!canDeleteTarget(transcript, { kind: \"entry\", entryId: entry.entryId })) return false;\n\t\treturn deleteEntryTarget(targets, entry.entryId);\n\t}\n\n\tlet changed = false;\n\tfor (const blockIndex of toolCallBlockIndexes(entry, callId)) {\n\t\tconst target: ContextDeletionTarget = { kind: \"content_block\", entryId: entry.entryId, blockIndex };\n\t\tif (!canDeleteTarget(transcript, target)) continue;\n\t\tif (!getDeletedEntryIds(targets).has(entry.entryId)) {\n\t\t\tchanged = addTarget(targets, target) || changed;\n\t\t}\n\t}\n\treturn canonicalizeEntryTargets(transcript, targets, entry) || changed;\n}\n\n/** Whether a task-bearing entry remains provider-visible after proposed block deletions. */\nexport function isTaskBearingEntry(\n\tentry: CompactableTranscriptEntry,\n\tdeletedContentBlocks: ReadonlySet<number> = new Set<number>(),\n): boolean {\n\tconst taskRole =\n\t\tentry.role === \"user\" ||\n\t\tentry.role === \"custom\" ||\n\t\tentry.role === \"branchSummary\" ||\n\t\tentry.entryType === \"branch_summary\";\n\treturn taskRole && transcriptEntryStartsNewTurn(entry, deletedContentBlocks);\n}\n\nexport function isRecentTarget(transcript: CompactableTranscript, target: ContextDeletionTarget): boolean {\n\tconst entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);\n\treturn entry !== undefined && isRecentContextEntry(entry, transcript);\n}\n\nexport function isStaleUserImageOnlyEntry(transcript: CompactableTranscript, entry: CompactableTranscriptEntry): boolean {\n\tif (entry.role !== \"user\" || isRecentContextEntry(entry, transcript)) return false;\n\tconst visibleBlocks = entry.contentBlocks.filter((block) => compactableContentBlockIsLlmVisible(entry, block));\n\tif (visibleBlocks.length === 0 || !visibleBlocks.every((block) => block.type === \"image\")) return false;\n\treturn transcript.entries.some(\n\t\t(candidate) => candidate.entryId !== entry.entryId && isTaskBearingEntry(candidate),\n\t);\n}\n\nexport function canDeleteStaleUserImageContentBlock(\n\ttranscript: CompactableTranscript,\n\ttarget: ContextDeletionTarget,\n): boolean {\n\tif (target.kind !== \"content_block\") return false;\n\tconst entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);\n\tif (!entry || entry.role !== \"user\" || isRecentTarget(transcript, target)) return false;\n\tconst block = entry.contentBlocks.find((candidate) => candidate.blockIndex === target.blockIndex);\n\tif (!block || block.type !== \"image\") return false;\n\treturn entry.contentBlocks.some(\n\t\t(candidate) =>\n\t\t\tcandidate.blockIndex !== target.blockIndex &&\n\t\t\tcandidate.type !== \"image\" &&\n\t\t\tcompactableContentBlockIsLlmVisible(entry, candidate),\n\t);\n}\n\nexport function canDeleteTarget(transcript: CompactableTranscript, target: ContextDeletionTarget): boolean {\n\tconst entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);\n\tif (!entry) return false;\n\tif (isRecentTarget(transcript, target)) return false;\n\tif (target.kind === \"entry\") return isStaleUserImageOnlyEntry(transcript, entry) || !entry.protected;\n\tconst block = entry.contentBlocks.find((candidate) => candidate.blockIndex === target.blockIndex);\n\tif (!block) return false;\n\tif (canDeleteStaleUserImageContentBlock(transcript, target)) return true;\n\tif (entry.protected) return false;\n\treturn !block.protected;\n}\n\n"]}