@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
@@ -1,172 +1,222 @@
1
- import { validateContextDeletionRequest } from "./context-deletion-application.js";
2
- import { canDeleteTarget, deletionRequestFromTargets, isTaskBearingEntry } from "./context-deletion-targets.js";
3
1
  import { relaxTranscriptForCriticalEviction } from "./context-compaction-critical.js";
4
- import { assistantEntryHasThinkingContentBlock } from "./context-transcript-analysis.js";
5
- export const CONTEXT_COMPACTION_MAX_EVICTION_PASSES = 50;
2
+ import { alternateBoundaryPlan, assistantTurnsForTargets, currentHistoricalSignedGroups, hasFitBudget, repairSignedTurnTargets, skippedBoundaryRestorationGroups, targetsWithGroup, tryGroup, validateTargets, } from "./context-compaction-eviction-alternates.js";
3
+ import { transcriptEntryStartsNewTurn } from "./context-assistant-turns.js";
4
+ import { canDeleteTarget, getDeletedEntryIds } from "./context-deletion-targets.js";
6
5
  function terminalDeterministicEvictionError(reason, lastValidated, tokenBudget) {
7
6
  const statsText = lastValidated
8
7
  ? `achieved tokensAfter=${lastValidated.stats.tokensAfter}, reduction=${lastValidated.stats.percentReduction}%, deletionTargets=${lastValidated.deletedTargets.length}`
9
8
  : "achieved no validated deletion targets";
10
9
  return new Error(`Context deterministic overflow eviction failed: ${reason}; ${statsText}; budget=${tokenBudget}; nothing more was safely deletable`);
11
10
  }
12
- function hasFitBudget(result, tokenBudget) {
13
- return result !== undefined && result.deletedTargets.length > 0 && result.stats.tokensAfter <= tokenBudget;
14
- }
15
- function isThinkingAssistantEntryTarget(transcript, target) {
16
- if (target.kind !== "entry")
17
- return false;
18
- const entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);
19
- return entry?.role === "assistant" && assistantEntryHasThinkingContentBlock(entry);
20
- }
21
- function isTaskBearingEntryTarget(transcript, target) {
22
- if (target.kind !== "entry")
23
- return false;
24
- const entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);
25
- return entry !== undefined && isTaskBearingEntry(entry);
26
- }
27
- function targetSignature(targets) {
28
- return targets
29
- .map((target) => `${target.kind}:${target.entryId}:${target.kind === "content_block" ? target.blockIndex : ""}`)
30
- .join("|");
31
- }
32
- function entryOrder(transcript, entryId) {
33
- const index = transcript.entries.findIndex((entry) => entry.entryId === entryId);
34
- return index < 0 ? Number.MAX_SAFE_INTEGER : index;
35
- }
36
- function entryTokenEstimate(transcript, entryId) {
37
- return transcript.entries.find((entry) => entry.entryId === entryId)?.tokenEstimate ?? 0;
38
- }
39
- function smallestTaskTarget(transcript, targets) {
40
- return [...targets]
41
- .filter((target) => isTaskBearingEntryTarget(transcript, target))
42
- .sort((left, right) => {
43
- const tokenDelta = entryTokenEstimate(transcript, left.entryId) - entryTokenEstimate(transcript, right.entryId);
44
- if (tokenDelta !== 0)
45
- return tokenDelta;
46
- return entryOrder(transcript, left.entryId) - entryOrder(transcript, right.entryId);
47
- })[0];
48
- }
49
- function newestThinkingTarget(transcript, targets) {
50
- return [...targets]
51
- .filter((target) => isThinkingAssistantEntryTarget(transcript, target))
52
- .sort((left, right) => entryOrder(transcript, right.entryId) - entryOrder(transcript, left.entryId))[0];
53
- }
54
- const THINKING_EXCHANGES = ["keep-all", "drop-all", "retain-newest"];
55
- const TASK_EXCHANGES = ["keep-all", "drop-all", "retain-smallest"];
56
- function shouldDeleteTarget(transcript, target, thinkingExchange, taskExchange, retainedThinking, retainedTask) {
57
- if (thinkingExchange === "drop-all" && isThinkingAssistantEntryTarget(transcript, target))
58
- return false;
59
- if (thinkingExchange === "retain-newest" && retainedThinking !== undefined && targetSignature([target]) === targetSignature([retainedThinking]))
60
- return false;
61
- if (taskExchange === "drop-all" && isTaskBearingEntryTarget(transcript, target))
62
- return false;
63
- if (taskExchange === "retain-smallest" && retainedTask !== undefined && targetSignature([target]) === targetSignature([retainedTask]))
64
- return false;
65
- return true;
66
- }
67
- function buildExchangePlan(transcript, withCandidate, thinkingExchange, taskExchange) {
68
- const retainedThinking = thinkingExchange === "retain-newest" ? newestThinkingTarget(transcript, withCandidate) : undefined;
69
- const retainedTask = taskExchange === "retain-smallest" ? smallestTaskTarget(transcript, withCandidate) : undefined;
70
- return withCandidate.filter((target) => shouldDeleteTarget(transcript, target, thinkingExchange, taskExchange, retainedThinking, retainedTask));
71
- }
72
- function shouldBuildExchangePlan(withCandidate, thinkingExchange, taskExchange) {
73
- if (thinkingExchange === "keep-all" && taskExchange === "keep-all")
74
- return false;
75
- if (thinkingExchange === "retain-newest" && withCandidate.filter((target) => target.kind === "entry").length === 0)
76
- return false;
77
- return true;
78
- }
79
- function addExchangePlan(plans, seen, originalTargets, targets) {
80
- if (targetSignature(targets) === targetSignature(originalTargets))
81
- return;
82
- const signature = targetSignature(targets);
83
- if (seen.has(signature))
84
- return;
85
- seen.add(signature);
86
- plans.push([...targets]);
87
- }
88
- function exchangePlans(transcript, planned, entryId) {
89
- const currentTarget = { kind: "entry", entryId };
90
- const withCandidate = [...planned, currentTarget];
91
- const plans = [];
92
- const seen = new Set();
93
- // Deterministic cross-product order: thinking handling outermost, then task handling.
94
- // Variants are keep/drop-all/retain-one for each non-monotone category, minus the
95
- // keep-all/keep-all no-op; signature dedup collapses degenerate variants.
96
- for (const thinkingExchange of THINKING_EXCHANGES) {
97
- for (const taskExchange of TASK_EXCHANGES) {
98
- if (!shouldBuildExchangePlan(withCandidate, thinkingExchange, taskExchange))
99
- continue;
100
- addExchangePlan(plans, seen, withCandidate, buildExchangePlan(transcript, withCandidate, thinkingExchange, taskExchange));
11
+ function initialEvictionGroups(transcript) {
12
+ const turns = assistantTurnsForTargets(transcript, []);
13
+ const signedGroupByEntryId = new Map();
14
+ const activeSignedIds = new Set();
15
+ for (const turn of turns) {
16
+ if (turn.active) {
17
+ for (const entryId of turn.signedThinkingEntryIds)
18
+ activeSignedIds.add(entryId);
19
+ continue;
20
+ }
21
+ for (const entryId of turn.signedThinkingEntryIds) {
22
+ signedGroupByEntryId.set(entryId, turn.signedThinkingEntryIds);
101
23
  }
102
24
  }
103
- return plans;
104
- }
105
- function validatedExchange(transcript, planned, entryId, lastValidated) {
106
- let best;
107
- for (const retryTargets of exchangePlans(transcript, planned, entryId)) {
108
- try {
109
- const result = validateContextDeletionRequest(deletionRequestFromTargets(retryTargets), transcript);
110
- if (lastValidated !== undefined && result.stats.tokensAfter >= lastValidated.stats.tokensAfter)
111
- continue;
112
- if (best === undefined || result.stats.tokensAfter < best.stats.tokensAfter)
113
- best = result;
25
+ const entryById = new Map(transcript.entries.map((entry, index) => [entry.entryId, { entry, index }]));
26
+ const grouped = new Set();
27
+ const groups = [];
28
+ for (let index = 0; index < transcript.entries.length; index++) {
29
+ const entry = transcript.entries[index];
30
+ if (activeSignedIds.has(entry.entryId) || grouped.has(entry.entryId))
31
+ continue;
32
+ const entryIds = signedGroupByEntryId.get(entry.entryId) ?? [entry.entryId];
33
+ for (const entryId of entryIds)
34
+ grouped.add(entryId);
35
+ if (!entryIds.every((entryId) => canDeleteTarget(transcript, { kind: "entry", entryId })))
36
+ continue;
37
+ groups.push({
38
+ entryIds: [...entryIds],
39
+ order: index,
40
+ tokens: entryIds.reduce((sum, entryId) => sum + (entryById.get(entryId)?.entry.tokenEstimate ?? 0), 0),
41
+ boundary: entryIds.length === 1 && transcriptEntryStartsNewTurn(entry),
42
+ });
43
+ }
44
+ return groups;
45
+ }
46
+ function repairedFittingBoundaryPrefix(transcript, planned, groups, tokenBudget, currentTokens) {
47
+ const required = currentTokens - tokenBudget;
48
+ if (required <= 0)
49
+ return undefined;
50
+ let rawRemoved = 0;
51
+ let lowerBound = 0;
52
+ while (lowerBound < groups.length && rawRemoved < required) {
53
+ rawRemoved += groups[lowerBound].tokens;
54
+ lowerBound += 1;
55
+ }
56
+ if (rawRemoved < required)
57
+ return undefined;
58
+ let prospective = [...planned];
59
+ for (let index = 0; index < groups.length; index++) {
60
+ prospective = targetsWithGroup(prospective, groups[index].entryIds);
61
+ if (index + 1 < lowerBound)
62
+ continue;
63
+ const repaired = repairSignedTurnTargets(transcript, prospective);
64
+ const validated = validateTargets(transcript, repaired);
65
+ if (!validated || !hasFitBudget(validated, tokenBudget))
66
+ continue;
67
+ const deleted = getDeletedEntryIds(validated.deletedTargets);
68
+ const prefixRetained = groups
69
+ .slice(0, index + 1)
70
+ .some((group) => group.entryIds.some((entryId) => !deleted.has(entryId)));
71
+ if (!prefixRetained)
72
+ return validated;
73
+ }
74
+ return undefined;
75
+ }
76
+ function adoptSmallestFittingPrefix(transcript, planned, groups, tokenBudget) {
77
+ if (groups.length === 0)
78
+ return undefined;
79
+ const prefixTargets = (count) => groups.slice(0, count).reduce((targets, group) => targetsWithGroup(targets, group.entryIds), [...planned]);
80
+ const full = validateTargets(transcript, prefixTargets(groups.length));
81
+ if (!full)
82
+ return undefined;
83
+ if (!hasFitBudget(full, tokenBudget))
84
+ return full;
85
+ let low = 1;
86
+ let high = groups.length;
87
+ let best = full;
88
+ while (low <= high) {
89
+ const middle = Math.floor((low + high) / 2);
90
+ const result = validateTargets(transcript, prefixTargets(middle));
91
+ if (result && hasFitBudget(result, tokenBudget)) {
92
+ best = result;
93
+ high = middle - 1;
114
94
  }
115
- catch {
116
- // Try the next deterministic exchange variant.
95
+ else {
96
+ low = middle + 1;
117
97
  }
118
98
  }
119
99
  return best;
120
100
  }
101
+ /**
102
+ * Finite deterministic eviction phases:
103
+ * 1. Batch or sweep non-boundary groups in transcript order.
104
+ * 2. Try repaired boundary prefixes, then individual boundaries by token value.
105
+ * 3. Sweep newly historical signed groups exposed by those deletions.
106
+ * 4. Retry skipped boundaries by shared restoration component, then individually.
107
+ * 5. Search bounded alternate boundary states (at most 16 per boundary) and their signed groups.
108
+ * 6. Fail with the best validated stats after every finite candidate set is exhausted.
109
+ */
121
110
  export function runDeterministicContextEviction(transcript, tokenBudget) {
122
111
  const relaxed = relaxTranscriptForCriticalEviction(transcript);
123
- const latestAssistant = [...relaxed.entries].reverse().find((entry) => entry.role === "assistant");
124
- const protectedThinkingAssistant = latestAssistant && assistantEntryHasThinkingContentBlock(latestAssistant) ? latestAssistant.entryId : undefined;
125
- const candidates = relaxed.entries
126
- .filter((entry) => entry.entryId !== protectedThinkingAssistant)
127
- .filter((entry) => canDeleteTarget(relaxed, { kind: "entry", entryId: entry.entryId }))
128
- .map((entry) => entry.entryId);
129
- const planned = [];
130
- const excluded = new Set();
112
+ const groups = initialEvictionGroups(relaxed);
113
+ const nonBoundaries = groups.filter((group) => !group.boundary).sort((left, right) => left.order - right.order);
114
+ const boundaries = groups
115
+ .filter((group) => group.boundary)
116
+ .sort((left, right) => right.tokens - left.tokens || left.order - right.order);
117
+ let planned = [];
131
118
  let lastValidated;
132
- // Hard iteration cap required by the compaction-ladder design: every compaction loop must be
133
- // bounded (max 50) so no tier can spin indefinitely. Non-monotone validation rules can require
134
- // local exchange: a prior thinking-bearing or task-bearing deletion can make a newer candidate
135
- // invalid, even though replacing the prior deletion with that candidate is safe and fits better.
136
- // Exchanges are deterministic and adopted only when validation succeeds and tokensAfter strictly
137
- // decreases; exclusions grow monotonically, so no oscillation is possible, and the pass cap remains
138
- // the terminal safety belt.
139
- for (let pass = 0; pass < CONTEXT_COMPACTION_MAX_EVICTION_PASSES; pass++) {
140
- if (hasFitBudget(lastValidated, tokenBudget))
141
- return lastValidated;
142
- let changed = false;
143
- for (const entryId of candidates) {
119
+ const skippedBoundaries = [];
120
+ if (relaxed.tokensBefore > tokenBudget) {
121
+ const batch = adoptSmallestFittingPrefix(relaxed, planned, nonBoundaries, tokenBudget);
122
+ if (batch) {
123
+ planned = [...batch.deletedTargets];
124
+ lastValidated = batch;
144
125
  if (hasFitBudget(lastValidated, tokenBudget))
145
126
  return lastValidated;
146
- if (planned.some((target) => target.entryId === entryId) || excluded.has(entryId))
147
- continue;
148
- const nextPlanned = [...planned, { kind: "entry", entryId }];
149
- try {
150
- lastValidated = validateContextDeletionRequest(deletionRequestFromTargets(nextPlanned), relaxed);
151
- planned.splice(0, planned.length, ...lastValidated.deletedTargets);
152
- changed = true;
153
- }
154
- catch {
155
- const exchanged = validatedExchange(relaxed, planned, entryId, lastValidated);
156
- if (exchanged !== undefined) {
157
- lastValidated = exchanged;
158
- planned.splice(0, planned.length, ...lastValidated.deletedTargets);
159
- changed = true;
127
+ }
128
+ else {
129
+ for (const group of nonBoundaries) {
130
+ const result = tryGroup(relaxed, planned, group, false);
131
+ if (!result)
160
132
  continue;
161
- }
162
- excluded.add(entryId);
163
- changed = true;
133
+ planned = [...result.deletedTargets];
134
+ lastValidated = result;
135
+ if (hasFitBudget(lastValidated, tokenBudget))
136
+ return lastValidated;
164
137
  }
165
138
  }
166
- if (!changed) {
167
- throw terminalDeterministicEvictionError("candidate sweep exhausted", lastValidated, tokenBudget);
139
+ }
140
+ else {
141
+ for (const group of nonBoundaries) {
142
+ const result = tryGroup(relaxed, planned, group, false);
143
+ if (!result)
144
+ continue;
145
+ return result;
146
+ }
147
+ }
148
+ const boundaryBaseTargets = [...planned];
149
+ const boundaryBaseResult = lastValidated;
150
+ const boundaryBatch = repairedFittingBoundaryPrefix(relaxed, planned, boundaries, tokenBudget, lastValidated?.stats.tokensAfter ?? relaxed.tokensBefore);
151
+ if (boundaryBatch) {
152
+ const standalone = boundaries[0] ? tryGroup(relaxed, [], boundaries[0], true) : undefined;
153
+ return standalone && hasFitBudget(standalone, tokenBudget) && standalone.stats.tokensAfter > boundaryBatch.stats.tokensAfter
154
+ ? standalone
155
+ : boundaryBatch;
156
+ }
157
+ for (const group of boundaries) {
158
+ const result = tryGroup(relaxed, planned, group, true);
159
+ if (!result || (lastValidated && result.stats.tokensAfter >= lastValidated.stats.tokensAfter)) {
160
+ skippedBoundaries.push(group);
161
+ continue;
162
+ }
163
+ planned = [...result.deletedTargets];
164
+ lastValidated = result;
165
+ if (hasFitBudget(lastValidated, tokenBudget)) {
166
+ const standalone = tryGroup(relaxed, [], group, true);
167
+ return standalone && hasFitBudget(standalone, tokenBudget) && standalone.stats.tokensAfter > result.stats.tokensAfter
168
+ ? standalone
169
+ : result;
168
170
  }
169
171
  }
170
- throw terminalDeterministicEvictionError(`reached ${CONTEXT_COMPACTION_MAX_EVICTION_PASSES} eviction pass cap`, lastValidated, tokenBudget);
172
+ for (const group of currentHistoricalSignedGroups(relaxed, planned)) {
173
+ const result = tryGroup(relaxed, planned, group, false);
174
+ if (!result)
175
+ continue;
176
+ planned = [...result.deletedTargets];
177
+ lastValidated = result;
178
+ if (hasFitBudget(lastValidated, tokenBudget))
179
+ return lastValidated;
180
+ }
181
+ const groupedRetryIds = new Set();
182
+ for (const component of skippedBoundaryRestorationGroups(relaxed, planned, skippedBoundaries)) {
183
+ const entryIds = component.flatMap((group) => group.entryIds);
184
+ for (const entryId of entryIds)
185
+ groupedRetryIds.add(entryId);
186
+ const combined = {
187
+ entryIds,
188
+ order: Math.min(...component.map((group) => group.order)),
189
+ tokens: component.reduce((sum, group) => sum + group.tokens, 0),
190
+ boundary: true,
191
+ };
192
+ const result = tryGroup(relaxed, planned, combined, true);
193
+ if (!result)
194
+ continue;
195
+ const deleted = getDeletedEntryIds(result.deletedTargets);
196
+ if (!entryIds.every((entryId) => deleted.has(entryId)))
197
+ continue;
198
+ if (lastValidated && result.stats.tokensAfter >= lastValidated.stats.tokensAfter && !hasFitBudget(result, tokenBudget)) {
199
+ continue;
200
+ }
201
+ planned = [...result.deletedTargets];
202
+ lastValidated = result;
203
+ if (hasFitBudget(lastValidated, tokenBudget))
204
+ return lastValidated;
205
+ }
206
+ for (const group of skippedBoundaries) {
207
+ if (group.entryIds.some((entryId) => groupedRetryIds.has(entryId)))
208
+ continue;
209
+ const result = tryGroup(relaxed, planned, group, true);
210
+ if (!result || (lastValidated && result.stats.tokensAfter >= lastValidated.stats.tokensAfter))
211
+ continue;
212
+ planned = [...result.deletedTargets];
213
+ lastValidated = result;
214
+ if (hasFitBudget(lastValidated, tokenBudget))
215
+ return lastValidated;
216
+ }
217
+ const alternate = alternateBoundaryPlan(relaxed, boundaryBaseTargets, boundaryBaseResult, boundaries, tokenBudget);
218
+ if (alternate)
219
+ return alternate;
220
+ throw terminalDeterministicEvictionError("candidate sweep exhausted", lastValidated, tokenBudget);
171
221
  }
172
222
  //# sourceMappingURL=context-compaction-eviction.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-compaction-eviction.js","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-eviction.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextDeletionTarget } from \"../session-manager.ts\";\nimport type { CompactableTranscript, ValidatedContextDeletionResult } from \"./context-compaction-types.ts\";\nimport { validateContextDeletionRequest } from \"./context-deletion-application.ts\";\nimport { canDeleteTarget, deletionRequestFromTargets, isTaskBearingEntry } from \"./context-deletion-targets.ts\";\nimport { relaxTranscriptForCriticalEviction } from \"./context-compaction-critical.ts\";\nimport { assistantEntryHasThinkingContentBlock } from \"./context-transcript-analysis.ts\";\n\nexport const CONTEXT_COMPACTION_MAX_EVICTION_PASSES = 50;\n\nfunction terminalDeterministicEvictionError(\n\treason: string,\n\tlastValidated: ValidatedContextDeletionResult | undefined,\n\ttokenBudget: number,\n): Error {\n\tconst statsText = lastValidated\n\t\t? `achieved tokensAfter=${lastValidated.stats.tokensAfter}, reduction=${lastValidated.stats.percentReduction}%, deletionTargets=${lastValidated.deletedTargets.length}`\n\t\t: \"achieved no validated deletion targets\";\n\treturn new Error(\n\t\t`Context deterministic overflow eviction failed: ${reason}; ${statsText}; budget=${tokenBudget}; nothing more was safely deletable`,\n\t);\n}\n\n\nfunction hasFitBudget(result: ValidatedContextDeletionResult | undefined, tokenBudget: number): result is ValidatedContextDeletionResult {\n\treturn result !== undefined && result.deletedTargets.length > 0 && result.stats.tokensAfter <= tokenBudget;\n}\n\nfunction isThinkingAssistantEntryTarget(transcript: CompactableTranscript, target: ContextDeletionTarget): boolean {\n\tif (target.kind !== \"entry\") return false;\n\tconst entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);\n\treturn entry?.role === \"assistant\" && assistantEntryHasThinkingContentBlock(entry);\n}\n\nfunction isTaskBearingEntryTarget(transcript: CompactableTranscript, target: ContextDeletionTarget): boolean {\n\tif (target.kind !== \"entry\") return false;\n\tconst entry = transcript.entries.find((candidate) => candidate.entryId === target.entryId);\n\treturn entry !== undefined && isTaskBearingEntry(entry);\n}\n\nfunction targetSignature(targets: readonly ContextDeletionTarget[]): string {\n\treturn targets\n\t\t.map((target) => `${target.kind}:${target.entryId}:${target.kind === \"content_block\" ? target.blockIndex : \"\"}`)\n\t\t.join(\"|\");\n}\n\nfunction entryOrder(transcript: CompactableTranscript, entryId: string): number {\n\tconst index = transcript.entries.findIndex((entry) => entry.entryId === entryId);\n\treturn index < 0 ? Number.MAX_SAFE_INTEGER : index;\n}\n\nfunction entryTokenEstimate(transcript: CompactableTranscript, entryId: string): number {\n\treturn transcript.entries.find((entry) => entry.entryId === entryId)?.tokenEstimate ?? 0;\n}\n\nfunction smallestTaskTarget(transcript: CompactableTranscript, targets: readonly ContextDeletionTarget[]): ContextDeletionTarget | undefined {\n\treturn [...targets]\n\t\t.filter((target) => isTaskBearingEntryTarget(transcript, target))\n\t\t.sort((left: ContextDeletionTarget, right: ContextDeletionTarget) => {\n\t\t\tconst tokenDelta = entryTokenEstimate(transcript, left.entryId) - entryTokenEstimate(transcript, right.entryId);\n\t\t\tif (tokenDelta !== 0) return tokenDelta;\n\t\t\treturn entryOrder(transcript, left.entryId) - entryOrder(transcript, right.entryId);\n\t\t})[0];\n}\n\nfunction newestThinkingTarget(transcript: CompactableTranscript, targets: readonly ContextDeletionTarget[]): ContextDeletionTarget | undefined {\n\treturn [...targets]\n\t\t.filter((target) => isThinkingAssistantEntryTarget(transcript, target))\n\t\t.sort((left: ContextDeletionTarget, right: ContextDeletionTarget) => entryOrder(transcript, right.entryId) - entryOrder(transcript, left.entryId))[0];\n}\n\ntype ThinkingExchange = \"keep-all\" | \"drop-all\" | \"retain-newest\";\ntype TaskExchange = \"keep-all\" | \"drop-all\" | \"retain-smallest\";\n\nconst THINKING_EXCHANGES: readonly ThinkingExchange[] = [\"keep-all\", \"drop-all\", \"retain-newest\"];\nconst TASK_EXCHANGES: readonly TaskExchange[] = [\"keep-all\", \"drop-all\", \"retain-smallest\"];\n\nfunction shouldDeleteTarget(\n\ttranscript: CompactableTranscript,\n\ttarget: ContextDeletionTarget,\n\tthinkingExchange: ThinkingExchange,\n\ttaskExchange: TaskExchange,\n\tretainedThinking: ContextDeletionTarget | undefined,\n\tretainedTask: ContextDeletionTarget | undefined,\n): boolean {\n\tif (thinkingExchange === \"drop-all\" && isThinkingAssistantEntryTarget(transcript, target)) return false;\n\tif (thinkingExchange === \"retain-newest\" && retainedThinking !== undefined && targetSignature([target]) === targetSignature([retainedThinking])) return false;\n\tif (taskExchange === \"drop-all\" && isTaskBearingEntryTarget(transcript, target)) return false;\n\tif (taskExchange === \"retain-smallest\" && retainedTask !== undefined && targetSignature([target]) === targetSignature([retainedTask])) return false;\n\treturn true;\n}\n\nfunction buildExchangePlan(\n\ttranscript: CompactableTranscript,\n\twithCandidate: readonly ContextDeletionTarget[],\n\tthinkingExchange: ThinkingExchange,\n\ttaskExchange: TaskExchange,\n): ContextDeletionTarget[] {\n\tconst retainedThinking = thinkingExchange === \"retain-newest\" ? newestThinkingTarget(transcript, withCandidate) : undefined;\n\tconst retainedTask = taskExchange === \"retain-smallest\" ? smallestTaskTarget(transcript, withCandidate) : undefined;\n\treturn withCandidate.filter((target) =>\n\t\tshouldDeleteTarget(transcript, target, thinkingExchange, taskExchange, retainedThinking, retainedTask),\n\t);\n}\n\nfunction shouldBuildExchangePlan(\n\twithCandidate: readonly ContextDeletionTarget[],\n\tthinkingExchange: ThinkingExchange,\n\ttaskExchange: TaskExchange,\n): boolean {\n\tif (thinkingExchange === \"keep-all\" && taskExchange === \"keep-all\") return false;\n\tif (thinkingExchange === \"retain-newest\" && withCandidate.filter((target) => target.kind === \"entry\").length === 0) return false;\n\treturn true;\n}\n\nfunction addExchangePlan(\n\tplans: ContextDeletionTarget[][],\n\tseen: Set<string>,\n\toriginalTargets: readonly ContextDeletionTarget[],\n\ttargets: readonly ContextDeletionTarget[],\n): void {\n\tif (targetSignature(targets) === targetSignature(originalTargets)) return;\n\tconst signature = targetSignature(targets);\n\tif (seen.has(signature)) return;\n\tseen.add(signature);\n\tplans.push([...targets]);\n}\n\nfunction exchangePlans(\n\ttranscript: CompactableTranscript,\n\tplanned: readonly ContextDeletionTarget[],\n\tentryId: string,\n): ContextDeletionTarget[][] {\n\tconst currentTarget: ContextDeletionTarget = { kind: \"entry\", entryId };\n\tconst withCandidate = [...planned, currentTarget];\n\tconst plans: ContextDeletionTarget[][] = [];\n\tconst seen = new Set<string>();\n\t// Deterministic cross-product order: thinking handling outermost, then task handling.\n\t// Variants are keep/drop-all/retain-one for each non-monotone category, minus the\n\t// keep-all/keep-all no-op; signature dedup collapses degenerate variants.\n\tfor (const thinkingExchange of THINKING_EXCHANGES) {\n\t\tfor (const taskExchange of TASK_EXCHANGES) {\n\t\t\tif (!shouldBuildExchangePlan(withCandidate, thinkingExchange, taskExchange)) continue;\n\t\t\taddExchangePlan(plans, seen, withCandidate, buildExchangePlan(transcript, withCandidate, thinkingExchange, taskExchange));\n\t\t}\n\t}\n\treturn plans;\n}\n\nfunction validatedExchange(\n\ttranscript: CompactableTranscript,\n\tplanned: readonly ContextDeletionTarget[],\n\tentryId: string,\n\tlastValidated: ValidatedContextDeletionResult | undefined,\n): ValidatedContextDeletionResult | undefined {\n\tlet best: ValidatedContextDeletionResult | undefined;\n\tfor (const retryTargets of exchangePlans(transcript, planned, entryId)) {\n\t\ttry {\n\t\t\tconst result = validateContextDeletionRequest(deletionRequestFromTargets(retryTargets), transcript);\n\t\t\tif (lastValidated !== undefined && result.stats.tokensAfter >= lastValidated.stats.tokensAfter) continue;\n\t\t\tif (best === undefined || result.stats.tokensAfter < best.stats.tokensAfter) best = result;\n\t\t} catch {\n\t\t\t// Try the next deterministic exchange variant.\n\t\t}\n\t}\n\treturn best;\n}\n\nexport function runDeterministicContextEviction(\n\ttranscript: CompactableTranscript,\n\ttokenBudget: number,\n): ValidatedContextDeletionResult {\n\tconst relaxed = relaxTranscriptForCriticalEviction(transcript);\n\tconst latestAssistant = [...relaxed.entries].reverse().find((entry) => entry.role === \"assistant\");\n\tconst protectedThinkingAssistant = latestAssistant && assistantEntryHasThinkingContentBlock(latestAssistant) ? latestAssistant.entryId : undefined;\n\tconst candidates = relaxed.entries\n\t\t.filter((entry) => entry.entryId !== protectedThinkingAssistant)\n\t\t.filter((entry) => canDeleteTarget(relaxed, { kind: \"entry\", entryId: entry.entryId }))\n\t\t.map((entry) => entry.entryId);\n\tconst planned: ContextDeletionTarget[] = [];\n\tconst excluded = new Set<string>();\n\tlet lastValidated: ValidatedContextDeletionResult | undefined;\n\n\t// Hard iteration cap required by the compaction-ladder design: every compaction loop must be\n\t// bounded (max 50) so no tier can spin indefinitely. Non-monotone validation rules can require\n\t// local exchange: a prior thinking-bearing or task-bearing deletion can make a newer candidate\n\t// invalid, even though replacing the prior deletion with that candidate is safe and fits better.\n\t// Exchanges are deterministic and adopted only when validation succeeds and tokensAfter strictly\n\t// decreases; exclusions grow monotonically, so no oscillation is possible, and the pass cap remains\n\t// the terminal safety belt.\n\tfor (let pass = 0; pass < CONTEXT_COMPACTION_MAX_EVICTION_PASSES; pass++) {\n\t\tif (hasFitBudget(lastValidated, tokenBudget)) return lastValidated;\n\t\tlet changed = false;\n\t\tfor (const entryId of candidates) {\n\t\t\tif (hasFitBudget(lastValidated, tokenBudget)) return lastValidated;\n\t\t\tif (planned.some((target) => target.entryId === entryId) || excluded.has(entryId)) continue;\n\t\t\tconst nextPlanned: ContextDeletionTarget[] = [...planned, { kind: \"entry\", entryId }];\n\t\t\ttry {\n\t\t\t\tlastValidated = validateContextDeletionRequest(deletionRequestFromTargets(nextPlanned), relaxed);\n\t\t\t\tplanned.splice(0, planned.length, ...lastValidated.deletedTargets);\n\t\t\t\tchanged = true;\n\t\t\t} catch {\n\t\t\t\tconst exchanged = validatedExchange(relaxed, planned, entryId, lastValidated);\n\t\t\t\tif (exchanged !== undefined) {\n\t\t\t\t\tlastValidated = exchanged;\n\t\t\t\t\tplanned.splice(0, planned.length, ...lastValidated.deletedTargets);\n\t\t\t\t\tchanged = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\texcluded.add(entryId);\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t\tif (!changed) {\n\t\t\tthrow terminalDeterministicEvictionError(\"candidate sweep exhausted\", lastValidated, tokenBudget);\n\t\t}\n\t}\n\tthrow terminalDeterministicEvictionError(\n\t\t`reached ${CONTEXT_COMPACTION_MAX_EVICTION_PASSES} eviction pass cap`,\n\t\tlastValidated,\n\t\ttokenBudget,\n\t);\n}\n"]}
1
+ {"version":3,"file":"context-compaction-eviction.js","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-eviction.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextDeletionTarget } from \"../session-manager.js\";\nimport { relaxTranscriptForCriticalEviction } from \"./context-compaction-critical.js\";\nimport {\n\talternateBoundaryPlan,\n\tassistantTurnsForTargets,\n\tcurrentHistoricalSignedGroups,\n\ttype EvictionGroup,\n\thasFitBudget,\n\trepairSignedTurnTargets,\n\tskippedBoundaryRestorationGroups,\n\ttargetsWithGroup,\n\ttryGroup,\n\tvalidateTargets,\n} from \"./context-compaction-eviction-alternates.js\";\nimport type { CompactableTranscript, ValidatedContextDeletionResult } from \"./context-compaction-types.js\";\nimport { transcriptEntryStartsNewTurn } from \"./context-assistant-turns.js\";\nimport { canDeleteTarget, getDeletedEntryIds } from \"./context-deletion-targets.js\";\n\nfunction terminalDeterministicEvictionError(\n\treason: string,\n\tlastValidated: ValidatedContextDeletionResult | undefined,\n\ttokenBudget: number,\n): Error {\n\tconst statsText = lastValidated\n\t\t? `achieved tokensAfter=${lastValidated.stats.tokensAfter}, reduction=${lastValidated.stats.percentReduction}%, deletionTargets=${lastValidated.deletedTargets.length}`\n\t\t: \"achieved no validated deletion targets\";\n\treturn new Error(\n\t\t`Context deterministic overflow eviction failed: ${reason}; ${statsText}; budget=${tokenBudget}; nothing more was safely deletable`,\n\t);\n}\n\nfunction initialEvictionGroups(transcript: CompactableTranscript): EvictionGroup[] {\n\tconst turns = assistantTurnsForTargets(transcript, []);\n\tconst signedGroupByEntryId = new Map<string, string[]>();\n\tconst activeSignedIds = new Set<string>();\n\tfor (const turn of turns) {\n\t\tif (turn.active) {\n\t\t\tfor (const entryId of turn.signedThinkingEntryIds) activeSignedIds.add(entryId);\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const entryId of turn.signedThinkingEntryIds) {\n\t\t\tsignedGroupByEntryId.set(entryId, turn.signedThinkingEntryIds);\n\t\t}\n\t}\n\n\tconst entryById = new Map(transcript.entries.map((entry, index) => [entry.entryId, { entry, index }]));\n\tconst grouped = new Set<string>();\n\tconst groups: EvictionGroup[] = [];\n\tfor (let index = 0; index < transcript.entries.length; index++) {\n\t\tconst entry = transcript.entries[index]!;\n\t\tif (activeSignedIds.has(entry.entryId) || grouped.has(entry.entryId)) continue;\n\t\tconst entryIds = signedGroupByEntryId.get(entry.entryId) ?? [entry.entryId];\n\t\tfor (const entryId of entryIds) grouped.add(entryId);\n\t\tif (!entryIds.every((entryId) => canDeleteTarget(transcript, { kind: \"entry\", entryId }))) continue;\n\t\tgroups.push({\n\t\t\tentryIds: [...entryIds],\n\t\t\torder: index,\n\t\t\ttokens: entryIds.reduce((sum, entryId) => sum + (entryById.get(entryId)?.entry.tokenEstimate ?? 0), 0),\n\t\t\tboundary: entryIds.length === 1 && transcriptEntryStartsNewTurn(entry),\n\t\t});\n\t}\n\treturn groups;\n}\n\nfunction repairedFittingBoundaryPrefix(\n\ttranscript: CompactableTranscript,\n\tplanned: readonly ContextDeletionTarget[],\n\tgroups: readonly EvictionGroup[],\n\ttokenBudget: number,\n\tcurrentTokens: number,\n): ValidatedContextDeletionResult | undefined {\n\tconst required = currentTokens - tokenBudget;\n\tif (required <= 0) return undefined;\n\tlet rawRemoved = 0;\n\tlet lowerBound = 0;\n\twhile (lowerBound < groups.length && rawRemoved < required) {\n\t\trawRemoved += groups[lowerBound]!.tokens;\n\t\tlowerBound += 1;\n\t}\n\tif (rawRemoved < required) return undefined;\n\n\tlet prospective = [...planned];\n\tfor (let index = 0; index < groups.length; index++) {\n\t\tprospective = targetsWithGroup(prospective, groups[index]!.entryIds);\n\t\tif (index + 1 < lowerBound) continue;\n\t\tconst repaired = repairSignedTurnTargets(transcript, prospective);\n\t\tconst validated = validateTargets(transcript, repaired);\n\t\tif (!validated || !hasFitBudget(validated, tokenBudget)) continue;\n\t\tconst deleted = getDeletedEntryIds(validated.deletedTargets);\n\t\tconst prefixRetained = groups\n\t\t\t.slice(0, index + 1)\n\t\t\t.some((group) => group.entryIds.some((entryId) => !deleted.has(entryId)));\n\t\tif (!prefixRetained) return validated;\n\t}\n\treturn undefined;\n}\n\nfunction adoptSmallestFittingPrefix(\n\ttranscript: CompactableTranscript,\n\tplanned: readonly ContextDeletionTarget[],\n\tgroups: readonly EvictionGroup[],\n\ttokenBudget: number,\n): ValidatedContextDeletionResult | undefined {\n\tif (groups.length === 0) return undefined;\n\tconst prefixTargets = (count: number): ContextDeletionTarget[] =>\n\t\tgroups.slice(0, count).reduce((targets, group) => targetsWithGroup(targets, group.entryIds), [...planned]);\n\tconst full = validateTargets(transcript, prefixTargets(groups.length));\n\tif (!full) return undefined;\n\tif (!hasFitBudget(full, tokenBudget)) return full;\n\n\tlet low = 1;\n\tlet high = groups.length;\n\tlet best = full;\n\twhile (low <= high) {\n\t\tconst middle = Math.floor((low + high) / 2);\n\t\tconst result = validateTargets(transcript, prefixTargets(middle));\n\t\tif (result && hasFitBudget(result, tokenBudget)) {\n\t\t\tbest = result;\n\t\t\thigh = middle - 1;\n\t\t} else {\n\t\t\tlow = middle + 1;\n\t\t}\n\t}\n\treturn best;\n}\n\n/**\n * Finite deterministic eviction phases:\n * 1. Batch or sweep non-boundary groups in transcript order.\n * 2. Try repaired boundary prefixes, then individual boundaries by token value.\n * 3. Sweep newly historical signed groups exposed by those deletions.\n * 4. Retry skipped boundaries by shared restoration component, then individually.\n * 5. Search bounded alternate boundary states (at most 16 per boundary) and their signed groups.\n * 6. Fail with the best validated stats after every finite candidate set is exhausted.\n */\nexport function runDeterministicContextEviction(\n\ttranscript: CompactableTranscript,\n\ttokenBudget: number,\n): ValidatedContextDeletionResult {\n\tconst relaxed = relaxTranscriptForCriticalEviction(transcript);\n\tconst groups = initialEvictionGroups(relaxed);\n\tconst nonBoundaries = groups.filter((group) => !group.boundary).sort((left, right) => left.order - right.order);\n\tconst boundaries = groups\n\t\t.filter((group) => group.boundary)\n\t\t.sort((left, right) => right.tokens - left.tokens || left.order - right.order);\n\tlet planned: ContextDeletionTarget[] = [];\n\tlet lastValidated: ValidatedContextDeletionResult | undefined;\n\tconst skippedBoundaries: EvictionGroup[] = [];\n\n\tif (relaxed.tokensBefore > tokenBudget) {\n\t\tconst batch = adoptSmallestFittingPrefix(relaxed, planned, nonBoundaries, tokenBudget);\n\t\tif (batch) {\n\t\t\tplanned = [...batch.deletedTargets];\n\t\t\tlastValidated = batch;\n\t\t\tif (hasFitBudget(lastValidated, tokenBudget)) return lastValidated;\n\t\t} else {\n\t\t\tfor (const group of nonBoundaries) {\n\t\t\t\tconst result = tryGroup(relaxed, planned, group, false);\n\t\t\t\tif (!result) continue;\n\t\t\t\tplanned = [...result.deletedTargets];\n\t\t\t\tlastValidated = result;\n\t\t\t\tif (hasFitBudget(lastValidated, tokenBudget)) return lastValidated;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor (const group of nonBoundaries) {\n\t\t\tconst result = tryGroup(relaxed, planned, group, false);\n\t\t\tif (!result) continue;\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tconst boundaryBaseTargets = [...planned];\n\tconst boundaryBaseResult = lastValidated;\n\tconst boundaryBatch = repairedFittingBoundaryPrefix(\n\t\trelaxed,\n\t\tplanned,\n\t\tboundaries,\n\t\ttokenBudget,\n\t\tlastValidated?.stats.tokensAfter ?? relaxed.tokensBefore,\n\t);\n\tif (boundaryBatch) {\n\t\tconst standalone = boundaries[0] ? tryGroup(relaxed, [], boundaries[0], true) : undefined;\n\t\treturn standalone && hasFitBudget(standalone, tokenBudget) && standalone.stats.tokensAfter > boundaryBatch.stats.tokensAfter\n\t\t\t? standalone\n\t\t\t: boundaryBatch;\n\t}\n\n\tfor (const group of boundaries) {\n\t\tconst result = tryGroup(relaxed, planned, group, true);\n\t\tif (!result || (lastValidated && result.stats.tokensAfter >= lastValidated.stats.tokensAfter)) {\n\t\t\tskippedBoundaries.push(group);\n\t\t\tcontinue;\n\t\t}\n\t\tplanned = [...result.deletedTargets];\n\t\tlastValidated = result;\n\t\tif (hasFitBudget(lastValidated, tokenBudget)) {\n\t\t\tconst standalone = tryGroup(relaxed, [], group, true);\n\t\t\treturn standalone && hasFitBudget(standalone, tokenBudget) && standalone.stats.tokensAfter > result.stats.tokensAfter\n\t\t\t\t? standalone\n\t\t\t\t: result;\n\t\t}\n\t}\n\n\tfor (const group of currentHistoricalSignedGroups(relaxed, planned)) {\n\t\tconst result = tryGroup(relaxed, planned, group, false);\n\t\tif (!result) continue;\n\t\tplanned = [...result.deletedTargets];\n\t\tlastValidated = result;\n\t\tif (hasFitBudget(lastValidated, tokenBudget)) return lastValidated;\n\t}\n\n\tconst groupedRetryIds = new Set<string>();\n\tfor (const component of skippedBoundaryRestorationGroups(relaxed, planned, skippedBoundaries)) {\n\t\tconst entryIds = component.flatMap((group) => group.entryIds);\n\t\tfor (const entryId of entryIds) groupedRetryIds.add(entryId);\n\t\tconst combined: EvictionGroup = {\n\t\t\tentryIds,\n\t\t\torder: Math.min(...component.map((group) => group.order)),\n\t\t\ttokens: component.reduce((sum, group) => sum + group.tokens, 0),\n\t\t\tboundary: true,\n\t\t};\n\t\tconst result = tryGroup(relaxed, planned, combined, true);\n\t\tif (!result) continue;\n\t\tconst deleted = getDeletedEntryIds(result.deletedTargets);\n\t\tif (!entryIds.every((entryId) => deleted.has(entryId))) continue;\n\t\tif (lastValidated && result.stats.tokensAfter >= lastValidated.stats.tokensAfter && !hasFitBudget(result, tokenBudget)) {\n\t\t\tcontinue;\n\t\t}\n\t\tplanned = [...result.deletedTargets];\n\t\tlastValidated = result;\n\t\tif (hasFitBudget(lastValidated, tokenBudget)) return lastValidated;\n\t}\n\n\tfor (const group of skippedBoundaries) {\n\t\tif (group.entryIds.some((entryId) => groupedRetryIds.has(entryId))) continue;\n\t\tconst result = tryGroup(relaxed, planned, group, true);\n\t\tif (!result || (lastValidated && result.stats.tokensAfter >= lastValidated.stats.tokensAfter)) continue;\n\t\tplanned = [...result.deletedTargets];\n\t\tlastValidated = result;\n\t\tif (hasFitBudget(lastValidated, tokenBudget)) return lastValidated;\n\t}\n\n\tconst alternate = alternateBoundaryPlan(\n\t\trelaxed,\n\t\tboundaryBaseTargets,\n\t\tboundaryBaseResult,\n\t\tboundaries,\n\t\ttokenBudget,\n\t);\n\tif (alternate) return alternate;\n\n\tthrow terminalDeterministicEvictionError(\"candidate sweep exhausted\", lastValidated, tokenBudget);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"context-compaction-prompt.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-prompt.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,qBAAqB,EAErB,2BAA2B,EAC3B,MAAM,+BAA+B,CAAC;AAWvC,eAAO,MAAM,gCAAgC,sTAE0N,CAAC;AAsFxQ,MAAM,WAAW,+BAA+B;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,IAAI,IAAI,CAAC;CAChB;AAED,wBAAgB,oCAAoC,CAAC,UAAU,EAAE,qBAAqB,GAAG,+BAA+B,CAWvH;AA+DD,wBAAgB,4BAA4B,CAC3C,UAAU,EAAE,qBAAqB,EACjC,kBAAkB,SAAgE,EAClF,UAAU,GAAE,2BAA2E,GACrF,MAAM,CAER","sourcesContent":["import { mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type {\n\tCompactableTranscript,\n\tCompactableTranscriptEntry,\n\tContextCompactionParameters,\n} from \"./context-compaction-types.ts\";\nimport {\n\tcontextCompactionTargetLabel,\n\tcontextCompactionTargetReductionPercent,\n} from \"./context-compaction-metrics.ts\";\nimport { getTranscriptCompactionParameters } from \"./context-compaction-strategy.ts\";\nimport { isExcludedFromLlmContext } from \"./context-transcript-analysis.ts\";\n\nconst CONTEXT_MANIFEST_MAX_ENTRIES = 80;\nconst CONTEXT_MANIFEST_PREVIEW_CHARS = 240;\n\nexport const CONTEXT_COMPACTION_SYSTEM_PROMPT = `You are a context compaction assistant.\n\nYour task is to read relevant parts of a conversation between a user and an AI assistant provided via a transcript file, then run a series of tools to apply deletion-only verbatim compaction using the exact context_delete or context_grep_delete format specified.`;\n\nfunction contextCompactionFixedPrompt(parameters: ContextCompactionParameters): string {\n\tconst targetLabel = contextCompactionTargetLabel(parameters);\n\treturn `Reference the provided transcript file transcript and use your search/read tools for small inspections, then use context_delete or context_grep_delete for deletions.\n\nCompaction records deletion targets, not replacement content.\nFor context_delete, use id-only targets: stable entryId values and optional blockIndex values only.\nFor context_grep_delete, use a concise literal or regex pattern to select matching entries or blocks; do not paste full transcript entries or content-block bodies.\nDo not summarize, paraphrase, or generate replacement context; those are not accepted compaction outputs.\nDo not mutate retained transcript objects or content.\nDeletion tool calls are the compaction action.\n\nStrategy:\n- Start by calling context_compaction_budget to see how much of the context window is full and how much reduction is needed.\n- Spend a few turns exploring with search/read tools to gain high confidence of candidate blocks to remove.\n- Prefer high-confidence exploit actions after that: delete obvious low-value entries via context_grep_delete or context_delete.\n- Use grep deletion for repeated low-value patterns.\n- Use exact id deletion for inspected one-off stale entries.\n- Check context_compaction_budget after deletion batches to track progress.\n- Strict requirement: reduce current context by at least ${targetLabel} before finishing. This is a hard completion gate, not a loose goal.\n- Do not send a final plain-text completion message until context_compaction_budget reports at least ${targetLabel} currentReductionPercent.\n- If the strict ${targetLabel} reduction is not met yet, continue removing low-value message entries or content blocks with context_delete/context_grep_delete.\n- Use the focus query to preserve relevant context: ${JSON.stringify(parameters.query)}.\n\nWhat Gets Deleted:\n- Redundant tool outputs: file reads already acted on, grep/search results already processed, passing test output no longer needed.\n- Exploratory dead ends: irrelevant files read, unhelpful or empty searches.\n- Verbose boilerplate: license headers, import blocks the agent isn't modifying, configuration files read for reference.\n- Superseded information: earlier versions of files that have since been edited, old error messages from bugs already fixed.\n- Stale/superseded image context: image content blocks (shown as type \"image\" / text \"[image]\") in older tool results, custom messages, or old user-pasted attachments that the agent has already inspected and no longer needs. Image blocks are large (each costs far more tokens than its \"[image]\" text preview suggests, as reported by context_compaction_budget imageTokenPercent). When images dominate the context, prefer deleting these stale image content blocks before removing useful recent text. Use context_grep_delete with the literal pattern \"[image]\" and target \"content_block\" to find image candidates, then confirm they are stale with context_read_entry before deleting. User text blocks remain protected. Old non-recent user image blocks may be deleted only when non-image user content remains in the same entry; old image-only user entries may be deleted as whole entries only when another task-bearing entry remains.\n\nWhat Survives:\n- Active file paths and line numbers: Any reference the agent might need to navigate.\n- Current error messages: Unresolved bugs and their exact text.\n- Reasoning decisions: Why the agent chose approach A over B. An agent's chain of thought (why it chose this file, what pattern it noticed, what fix it decided on) carries more information-per-token than the raw grep output or file content that informed those decisions.\n- Recent tool calls and their results: The last 3-5 operations.\n- User instructions: The original task and any clarifications.\n- Task-relevant images: Images that are part of the active user task (for example, a screenshot the user just asked about, or the most recent image-bearing result the agent is still acting on). Recent user images and recent tool results are protected by preserve_recent, so do not delete images the agent still needs.\n\nConditionally Deleted:\n- Old Reasoning decisions: If there is nothing else to remove and the target reduction is not met, you can remove entire stale assistant entries, EXCEPT do not delete individual content blocks from any retained assistant message that contains thinking or redacted_thinking blocks. Thinking-bearing assistant messages are all-or-nothing for replay safety.\n\n<output_format>\nCall the context_delete tool one or more times with deletion targets in this shape:\n{ \"deletions\": [{ \"kind\": \"entry\", \"entryId\": \"...\" }] }\n\nFor content-block deletions, use:\n{ \"kind\": \"content_block\", \"entryId\": \"...\", \"blockIndex\": 0 }\n\nThe tool applies and validates deletion targets immediately. You can continue calling it for additional deletions if useful.\n\nFor guarded bulk deletion by text match, call context_grep_delete with a literal pattern or regex. It removes valid matching context, silently ignores candidates that validation does not allow so they are not counted as removals, enforces a per-call maxMatches safety cap and optional expectedMatchCount, and validates through the same tool-call/tool-result safety rules. maxMatches only limits one tool call; there is no cumulative cap across corrected or repeated deletion calls.\n\nThe full transcript is available as a JSONL file path in the prompt, but do NOT try to load the whole file into context. Use context_search_transcript to find candidate entry IDs and context_read_entry to read only small slices (for example maxChars 1000-4000) before deleting.\n\nWhen the strict ${targetLabel} reduction requirement is met, reply with a brief plain-text completion message. Do not include deletion target IDs outside tool calls.\n</output_format>`;\n}\n\nfunction truncateForPrompt(text: string, maxChars: number): string {\n\tif (text.length <= maxChars) return text;\n\treturn `${text.slice(0, maxChars)}\\n[... ${text.length - maxChars} more characters omitted from context compaction prompt]`;\n}\n\nfunction transcriptEntryFilePayload(entry: CompactableTranscriptEntry): unknown {\n\treturn {\n\t\tentryId: entry.entryId,\n\t\tentryType: entry.entryType,\n\t\trole: entry.role,\n\t\tprotected: entry.protected,\n\t\ttokenEstimate: entry.tokenEstimate,\n\t\ttoolCallIds: entry.toolCallIds,\n\t\ttoolResultFor: entry.toolResultFor,\n\t\ttext: entry.text,\n\t\tcontentBlocks: entry.contentBlocks.map((block) => ({\n\t\t\tblockIndex: block.blockIndex,\n\t\t\ttype: block.type,\n\t\t\tprotected: block.protected,\n\t\t\ttoolCallId: block.toolCallId,\n\t\t\ttokenEstimate: block.tokenEstimate,\n\t\t\ttext: block.text,\n\t\t})),\n\t};\n}\n\nexport interface ContextCompactionTranscriptFile {\n\tpath: string;\n\tcleanup(): void;\n}\n\nexport function writeContextCompactionTranscriptFile(transcript: CompactableTranscript): ContextCompactionTranscriptFile {\n\tconst directory = mkdtempSync(join(tmpdir(), \"atomic-context-transcript-\"));\n\tconst path = join(directory, \"transcript.jsonl\");\n\tconst lines = transcript.entries\n\t\t.filter((entry) => !isExcludedFromLlmContext(entry.message))\n\t\t.map((entry) => JSON.stringify(transcriptEntryFilePayload(entry)));\n\twriteFileSync(path, `${lines.join(\"\\n\")}\\n`, \"utf8\");\n\treturn {\n\t\tpath,\n\t\tcleanup: () => rmSync(directory, { recursive: true, force: true }),\n\t};\n}\n\nfunction contextCompactionTranscriptManifest(transcript: CompactableTranscript, transcriptFilePath: string): unknown {\n\tconst eligibleEntries = transcript.entries.filter((entry) => !isExcludedFromLlmContext(entry.message));\n\tconst selectedEntryIds = new Set<string>();\n\tconst selectedEntries: CompactableTranscriptEntry[] = [];\n\tconst addEntry = (entry: CompactableTranscriptEntry): void => {\n\t\tif (selectedEntryIds.has(entry.entryId) || selectedEntries.length >= CONTEXT_MANIFEST_MAX_ENTRIES) return;\n\t\tselectedEntryIds.add(entry.entryId);\n\t\tselectedEntries.push(entry);\n\t};\n\n\tfor (const entry of eligibleEntries.filter((entry) => entry.protected)) {\n\t\taddEntry(entry);\n\t}\n\tfor (const entry of [...eligibleEntries]\n\t\t.filter((entry) => !entry.protected)\n\t\t.sort((left, right) => right.tokenEstimate - left.tokenEstimate)) {\n\t\taddEntry(entry);\n\t}\n\tselectedEntries.sort((left, right) => eligibleEntries.indexOf(left) - eligibleEntries.indexOf(right));\n\n\treturn {\n\t\ttranscriptFilePath,\n\t\ttranscriptFileFormat: \"jsonl: one compactable transcript entry per line with full text and contentBlocks text\",\n\t\ttotalEntries: eligibleEntries.length,\n\t\tmanifestEntries: selectedEntries.length,\n\t\tomittedEntries: Math.max(0, eligibleEntries.length - selectedEntries.length),\n\t\ttokensBefore: transcript.tokensBefore,\n\t\tprotectedEntryIds: transcript.protectedEntryIds,\n\t\tentries: selectedEntries.map((entry) => ({\n\t\t\tentryId: entry.entryId,\n\t\t\trole: entry.role,\n\t\t\tprotected: entry.protected,\n\t\t\ttokenEstimate: entry.tokenEstimate,\n\t\t\ttoolCallIds: entry.toolCallIds,\n\t\t\ttoolResultFor: entry.toolResultFor,\n\t\t\tcontentBlockCount: entry.contentBlocks.length,\n\t\t\tcontentBlocks: entry.contentBlocks.map((block) => ({\n\t\t\t\tblockIndex: block.blockIndex,\n\t\t\t\ttype: block.type,\n\t\t\t\tprotected: block.protected,\n\t\t\t\ttoolCallId: block.toolCallId,\n\t\t\t\ttokenEstimate: block.tokenEstimate,\n\t\t\t})),\n\t\t\tpreview: truncateForPrompt(entry.text, CONTEXT_MANIFEST_PREVIEW_CHARS),\n\t\t})),\n\t};\n}\n\nfunction contextCompactionParametersPrompt(parameters: ContextCompactionParameters): string {\n\treturn `\\n<compaction-parameters>\\n${JSON.stringify(\n\t\t{\n\t\t\tcompression_ratio: parameters.compression_ratio,\n\t\t\tpreserve_recent: parameters.preserve_recent,\n\t\t\tquery: parameters.query,\n\t\t\ttarget_reduction_percent: contextCompactionTargetReductionPercent(parameters),\n\t\t},\n\t\tnull,\n\t\t2,\n\t)}\\n</compaction-parameters>`;\n}\n\nexport function buildContextCompactionPrompt(\n\ttranscript: CompactableTranscript,\n\ttranscriptFilePath = \"<transcript file will be written during context compaction>\",\n\tparameters: ContextCompactionParameters = getTranscriptCompactionParameters(transcript),\n): string {\n\treturn `${contextCompactionFixedPrompt(parameters)}${contextCompactionParametersPrompt(parameters)}\\n\\n<transcript-file>\\n${transcriptFilePath}\\n</transcript-file>\\n\\n<context-manifest>\\n${JSON.stringify(contextCompactionTranscriptManifest(transcript, transcriptFilePath), null, 2)}\\n</context-manifest>`;\n}\n"]}
1
+ {"version":3,"file":"context-compaction-prompt.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-prompt.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,qBAAqB,EAErB,2BAA2B,EAC3B,MAAM,+BAA+B,CAAC;AAWvC,eAAO,MAAM,gCAAgC,sTAE0N,CAAC;AAsFxQ,MAAM,WAAW,+BAA+B;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,IAAI,IAAI,CAAC;CAChB;AAED,wBAAgB,oCAAoC,CAAC,UAAU,EAAE,qBAAqB,GAAG,+BAA+B,CAWvH;AA+DD,wBAAgB,4BAA4B,CAC3C,UAAU,EAAE,qBAAqB,EACjC,kBAAkB,SAAgE,EAClF,UAAU,GAAE,2BAA2E,GACrF,MAAM,CAER","sourcesContent":["import { mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type {\n\tCompactableTranscript,\n\tCompactableTranscriptEntry,\n\tContextCompactionParameters,\n} from \"./context-compaction-types.ts\";\nimport {\n\tcontextCompactionTargetLabel,\n\tcontextCompactionTargetReductionPercent,\n} from \"./context-compaction-metrics.ts\";\nimport { getTranscriptCompactionParameters } from \"./context-compaction-strategy.ts\";\nimport { isExcludedFromLlmContext } from \"./context-transcript-analysis.ts\";\n\nconst CONTEXT_MANIFEST_MAX_ENTRIES = 80;\nconst CONTEXT_MANIFEST_PREVIEW_CHARS = 240;\n\nexport const CONTEXT_COMPACTION_SYSTEM_PROMPT = `You are a context compaction assistant.\n\nYour task is to read relevant parts of a conversation between a user and an AI assistant provided via a transcript file, then run a series of tools to apply deletion-only verbatim compaction using the exact context_delete or context_grep_delete format specified.`;\n\nfunction contextCompactionFixedPrompt(parameters: ContextCompactionParameters): string {\n\tconst targetLabel = contextCompactionTargetLabel(parameters);\n\treturn `Reference the provided transcript file transcript and use your search/read tools for small inspections, then use context_delete or context_grep_delete for deletions.\n\nCompaction records deletion targets, not replacement content.\nFor context_delete, use id-only targets: stable entryId values and optional blockIndex values only.\nFor context_grep_delete, use a concise literal or regex pattern to select matching entries or blocks; do not paste full transcript entries or content-block bodies.\nDo not summarize, paraphrase, or generate replacement context; those are not accepted compaction outputs.\nDo not mutate retained transcript objects or content.\nDeletion tool calls are the compaction action.\n\nStrategy:\n- Start by calling context_compaction_budget to see how much of the context window is full and how much reduction is needed.\n- Spend a few turns exploring with search/read tools to gain high confidence of candidate blocks to remove.\n- Prefer high-confidence exploit actions after that: delete obvious low-value entries via context_grep_delete or context_delete.\n- Use grep deletion for repeated low-value patterns.\n- Use exact id deletion for inspected one-off stale entries.\n- Check context_compaction_budget after deletion batches to track progress.\n- Strict requirement: reduce current context by at least ${targetLabel} before finishing. This is a hard completion gate, not a loose goal.\n- Do not send a final plain-text completion message until context_compaction_budget reports at least ${targetLabel} currentReductionPercent.\n- If the strict ${targetLabel} reduction is not met yet, continue removing low-value message entries or content blocks with context_delete/context_grep_delete.\n- Use the focus query to preserve relevant context: ${JSON.stringify(parameters.query)}.\n\nWhat Gets Deleted:\n- Redundant tool outputs: file reads already acted on, grep/search results already processed, passing test output no longer needed.\n- Exploratory dead ends: irrelevant files read, unhelpful or empty searches.\n- Verbose boilerplate: license headers, import blocks the agent isn't modifying, configuration files read for reference.\n- Superseded information: earlier versions of files that have since been edited, old error messages from bugs already fixed.\n- Stale/superseded image context: image content blocks (shown as type \"image\" / text \"[image]\") in older tool results, custom messages, or old user-pasted attachments that the agent has already inspected and no longer needs. Image blocks are large (each costs far more tokens than its \"[image]\" text preview suggests, as reported by context_compaction_budget imageTokenPercent). When images dominate the context, prefer deleting these stale image content blocks before removing useful recent text. Use context_grep_delete with the literal pattern \"[image]\" and target \"content_block\" to find image candidates, then confirm they are stale with context_read_entry before deleting. User text blocks remain protected. Old non-recent user image blocks may be deleted only when non-image user content remains in the same entry; old image-only user entries may be deleted as whole entries only when another task-bearing entry remains.\n\nWhat Survives:\n- Active file paths and line numbers: Any reference the agent might need to navigate.\n- Current error messages: Unresolved bugs and their exact text.\n- Reasoning decisions: Why the agent chose approach A over B. An agent's chain of thought (why it chose this file, what pattern it noticed, what fix it decided on) carries more information-per-token than the raw grep output or file content that informed those decisions.\n- Recent tool calls and their results: The last 3-5 operations.\n- User instructions: The original task and any clarifications.\n- Task-relevant images: Images that are part of the active user task (for example, a screenshot the user just asked about, or the most recent image-bearing result the agent is still acting on). Recent user images and recent tool results are protected by preserve_recent, so do not delete images the agent still needs.\n\nConditionally Deleted:\n- Old reasoning decisions: If there is nothing else to remove and the target reduction is not met, you may omit signed reasoning only as a complete logical assistant tool-use turn sequence. Each provider-visible user-like input starts a turn: a non-empty user/custom input (non-whitespace text or an image), a context-eligible bash execution, or a non-empty branch summary. Empty/whitespace-only user or custom inputs and empty branch summaries do not establish a boundary; whitespace-only branch summaries do because their wrapper is visible. Assistant messages and intervening tool results remain in that turn until the next visible user-like input. Never delete any thinking/redacted_thinking-bearing assistant entry from the current final logical turn; a trailing visible input without an assistant response makes the preceding assistant turn historical. In a completed historical turn, retain all thinking/redacted_thinking-bearing assistant entries or delete all of them as whole entries; never retain a proper subset. Never delete individual content blocks from a retained thinking-bearing assistant message.\n\n<output_format>\nCall the context_delete tool one or more times with deletion targets in this shape:\n{ \"deletions\": [{ \"kind\": \"entry\", \"entryId\": \"...\" }] }\n\nFor content-block deletions, use:\n{ \"kind\": \"content_block\", \"entryId\": \"...\", \"blockIndex\": 0 }\n\nThe tool applies and validates deletion targets immediately. You can continue calling it for additional deletions if useful.\n\nFor guarded bulk deletion by text match, call context_grep_delete with a literal pattern or regex. It removes valid matching context, silently ignores candidates that validation does not allow so they are not counted as removals, enforces a per-call maxMatches safety cap and optional expectedMatchCount, and validates through the same tool-call/tool-result safety rules. maxMatches only limits one tool call; there is no cumulative cap across corrected or repeated deletion calls.\n\nThe full transcript is available as a JSONL file path in the prompt, but do NOT try to load the whole file into context. Use context_search_transcript to find candidate entry IDs and context_read_entry to read only small slices (for example maxChars 1000-4000) before deleting.\n\nWhen the strict ${targetLabel} reduction requirement is met, reply with a brief plain-text completion message. Do not include deletion target IDs outside tool calls.\n</output_format>`;\n}\n\nfunction truncateForPrompt(text: string, maxChars: number): string {\n\tif (text.length <= maxChars) return text;\n\treturn `${text.slice(0, maxChars)}\\n[... ${text.length - maxChars} more characters omitted from context compaction prompt]`;\n}\n\nfunction transcriptEntryFilePayload(entry: CompactableTranscriptEntry): unknown {\n\treturn {\n\t\tentryId: entry.entryId,\n\t\tentryType: entry.entryType,\n\t\trole: entry.role,\n\t\tprotected: entry.protected,\n\t\ttokenEstimate: entry.tokenEstimate,\n\t\ttoolCallIds: entry.toolCallIds,\n\t\ttoolResultFor: entry.toolResultFor,\n\t\ttext: entry.text,\n\t\tcontentBlocks: entry.contentBlocks.map((block) => ({\n\t\t\tblockIndex: block.blockIndex,\n\t\t\ttype: block.type,\n\t\t\tprotected: block.protected,\n\t\t\ttoolCallId: block.toolCallId,\n\t\t\ttokenEstimate: block.tokenEstimate,\n\t\t\ttext: block.text,\n\t\t})),\n\t};\n}\n\nexport interface ContextCompactionTranscriptFile {\n\tpath: string;\n\tcleanup(): void;\n}\n\nexport function writeContextCompactionTranscriptFile(transcript: CompactableTranscript): ContextCompactionTranscriptFile {\n\tconst directory = mkdtempSync(join(tmpdir(), \"atomic-context-transcript-\"));\n\tconst path = join(directory, \"transcript.jsonl\");\n\tconst lines = transcript.entries\n\t\t.filter((entry) => !isExcludedFromLlmContext(entry.message))\n\t\t.map((entry) => JSON.stringify(transcriptEntryFilePayload(entry)));\n\twriteFileSync(path, `${lines.join(\"\\n\")}\\n`, \"utf8\");\n\treturn {\n\t\tpath,\n\t\tcleanup: () => rmSync(directory, { recursive: true, force: true }),\n\t};\n}\n\nfunction contextCompactionTranscriptManifest(transcript: CompactableTranscript, transcriptFilePath: string): unknown {\n\tconst eligibleEntries = transcript.entries.filter((entry) => !isExcludedFromLlmContext(entry.message));\n\tconst selectedEntryIds = new Set<string>();\n\tconst selectedEntries: CompactableTranscriptEntry[] = [];\n\tconst addEntry = (entry: CompactableTranscriptEntry): void => {\n\t\tif (selectedEntryIds.has(entry.entryId) || selectedEntries.length >= CONTEXT_MANIFEST_MAX_ENTRIES) return;\n\t\tselectedEntryIds.add(entry.entryId);\n\t\tselectedEntries.push(entry);\n\t};\n\n\tfor (const entry of eligibleEntries.filter((entry) => entry.protected)) {\n\t\taddEntry(entry);\n\t}\n\tfor (const entry of [...eligibleEntries]\n\t\t.filter((entry) => !entry.protected)\n\t\t.sort((left, right) => right.tokenEstimate - left.tokenEstimate)) {\n\t\taddEntry(entry);\n\t}\n\tselectedEntries.sort((left, right) => eligibleEntries.indexOf(left) - eligibleEntries.indexOf(right));\n\n\treturn {\n\t\ttranscriptFilePath,\n\t\ttranscriptFileFormat: \"jsonl: one compactable transcript entry per line with full text and contentBlocks text\",\n\t\ttotalEntries: eligibleEntries.length,\n\t\tmanifestEntries: selectedEntries.length,\n\t\tomittedEntries: Math.max(0, eligibleEntries.length - selectedEntries.length),\n\t\ttokensBefore: transcript.tokensBefore,\n\t\tprotectedEntryIds: transcript.protectedEntryIds,\n\t\tentries: selectedEntries.map((entry) => ({\n\t\t\tentryId: entry.entryId,\n\t\t\trole: entry.role,\n\t\t\tprotected: entry.protected,\n\t\t\ttokenEstimate: entry.tokenEstimate,\n\t\t\ttoolCallIds: entry.toolCallIds,\n\t\t\ttoolResultFor: entry.toolResultFor,\n\t\t\tcontentBlockCount: entry.contentBlocks.length,\n\t\t\tcontentBlocks: entry.contentBlocks.map((block) => ({\n\t\t\t\tblockIndex: block.blockIndex,\n\t\t\t\ttype: block.type,\n\t\t\t\tprotected: block.protected,\n\t\t\t\ttoolCallId: block.toolCallId,\n\t\t\t\ttokenEstimate: block.tokenEstimate,\n\t\t\t})),\n\t\t\tpreview: truncateForPrompt(entry.text, CONTEXT_MANIFEST_PREVIEW_CHARS),\n\t\t})),\n\t};\n}\n\nfunction contextCompactionParametersPrompt(parameters: ContextCompactionParameters): string {\n\treturn `\\n<compaction-parameters>\\n${JSON.stringify(\n\t\t{\n\t\t\tcompression_ratio: parameters.compression_ratio,\n\t\t\tpreserve_recent: parameters.preserve_recent,\n\t\t\tquery: parameters.query,\n\t\t\ttarget_reduction_percent: contextCompactionTargetReductionPercent(parameters),\n\t\t},\n\t\tnull,\n\t\t2,\n\t)}\\n</compaction-parameters>`;\n}\n\nexport function buildContextCompactionPrompt(\n\ttranscript: CompactableTranscript,\n\ttranscriptFilePath = \"<transcript file will be written during context compaction>\",\n\tparameters: ContextCompactionParameters = getTranscriptCompactionParameters(transcript),\n): string {\n\treturn `${contextCompactionFixedPrompt(parameters)}${contextCompactionParametersPrompt(parameters)}\\n\\n<transcript-file>\\n${transcriptFilePath}\\n</transcript-file>\\n\\n<context-manifest>\\n${JSON.stringify(contextCompactionTranscriptManifest(transcript, transcriptFilePath), null, 2)}\\n</context-manifest>`;\n}\n"]}
@@ -48,7 +48,7 @@ What Survives:
48
48
  - Task-relevant images: Images that are part of the active user task (for example, a screenshot the user just asked about, or the most recent image-bearing result the agent is still acting on). Recent user images and recent tool results are protected by preserve_recent, so do not delete images the agent still needs.
49
49
 
50
50
  Conditionally Deleted:
51
- - Old Reasoning decisions: If there is nothing else to remove and the target reduction is not met, you can remove entire stale assistant entries, EXCEPT do not delete individual content blocks from any retained assistant message that contains thinking or redacted_thinking blocks. Thinking-bearing assistant messages are all-or-nothing for replay safety.
51
+ - Old reasoning decisions: If there is nothing else to remove and the target reduction is not met, you may omit signed reasoning only as a complete logical assistant tool-use turn sequence. Each provider-visible user-like input starts a turn: a non-empty user/custom input (non-whitespace text or an image), a context-eligible bash execution, or a non-empty branch summary. Empty/whitespace-only user or custom inputs and empty branch summaries do not establish a boundary; whitespace-only branch summaries do because their wrapper is visible. Assistant messages and intervening tool results remain in that turn until the next visible user-like input. Never delete any thinking/redacted_thinking-bearing assistant entry from the current final logical turn; a trailing visible input without an assistant response makes the preceding assistant turn historical. In a completed historical turn, retain all thinking/redacted_thinking-bearing assistant entries or delete all of them as whole entries; never retain a proper subset. Never delete individual content blocks from a retained thinking-bearing assistant message.
52
52
 
53
53
  <output_format>
54
54
  Call the context_delete tool one or more times with deletion targets in this shape:
@@ -1 +1 @@
1
- {"version":3,"file":"context-compaction-prompt.js","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAMjC,OAAO,EACN,4BAA4B,EAC5B,uCAAuC,GACvC,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,MAAM,4BAA4B,GAAG,EAAE,CAAC;AACxC,MAAM,8BAA8B,GAAG,GAAG,CAAC;AAE3C,MAAM,CAAC,MAAM,gCAAgC,GAAG;;uQAEuN,CAAC;AAExQ,SAAS,4BAA4B,CAAC,UAAuC;IAC5E,MAAM,WAAW,GAAG,4BAA4B,CAAC,UAAU,CAAC,CAAC;IAC7D,OAAO;;;;;;;;;;;;;;;;2DAgBmD,WAAW;uGACiC,WAAW;kBAChG,WAAW;sDACyB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAiCpE,WAAW;iBACZ,CAAC;AAClB,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY,EAAE,QAAgB;IACxD,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,IAAI,CAAC,MAAM,GAAG,QAAQ,0DAA0D,CAAC;AAC7H,CAAC;AAED,SAAS,0BAA0B,CAAC,KAAiC;IACpE,OAAO;QACN,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAClD,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,IAAI,EAAE,KAAK,CAAC,IAAI;SAChB,CAAC,CAAC;KACH,CAAC;AACH,CAAC;AAOD,MAAM,UAAU,oCAAoC,CAAC,UAAiC;IACrF,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,4BAA4B,CAAC,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO;SAC9B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,wBAAwB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;SAC3D,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,0BAA0B,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpE,aAAa,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrD,OAAO;QACN,IAAI;QACJ,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;KAClE,CAAC;AACH,CAAC;AAED,SAAS,mCAAmC,CAAC,UAAiC,EAAE,kBAA0B;IACzG,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,wBAAwB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IACvG,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC3C,MAAM,eAAe,GAAiC,EAAE,CAAC;IACzD,MAAM,QAAQ,GAAG,CAAC,KAAiC,EAAQ,EAAE;QAC5D,IAAI,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,eAAe,CAAC,MAAM,IAAI,4BAA4B;YAAE,OAAO;QAC1G,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QACxE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,eAAe,CAAC;SACtC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;SACnC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QACnE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC;IACD,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAEtG,OAAO;QACN,kBAAkB;QAClB,oBAAoB,EAAE,wFAAwF;QAC9G,YAAY,EAAE,eAAe,CAAC,MAAM;QACpC,eAAe,EAAE,eAAe,CAAC,MAAM;QACvC,cAAc,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC;QAC5E,YAAY,EAAE,UAAU,CAAC,YAAY;QACrC,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;QAC/C,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACxC,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,iBAAiB,EAAE,KAAK,CAAC,aAAa,CAAC,MAAM;YAC7C,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBAClD,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,aAAa,EAAE,KAAK,CAAC,aAAa;aAClC,CAAC,CAAC;YACH,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,IAAI,EAAE,8BAA8B,CAAC;SACtE,CAAC,CAAC;KACH,CAAC;AACH,CAAC;AAED,SAAS,iCAAiC,CAAC,UAAuC;IACjF,OAAO,8BAA8B,IAAI,CAAC,SAAS,CAClD;QACC,iBAAiB,EAAE,UAAU,CAAC,iBAAiB;QAC/C,eAAe,EAAE,UAAU,CAAC,eAAe;QAC3C,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,wBAAwB,EAAE,uCAAuC,CAAC,UAAU,CAAC;KAC7E,EACD,IAAI,EACJ,CAAC,CACD,4BAA4B,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC3C,UAAiC,EACjC,kBAAkB,GAAG,6DAA6D,EAClF,UAAU,GAAgC,iCAAiC,CAAC,UAAU,CAAC;IAEvF,OAAO,GAAG,4BAA4B,CAAC,UAAU,CAAC,GAAG,iCAAiC,CAAC,UAAU,CAAC,0BAA0B,kBAAkB,+CAA+C,IAAI,CAAC,SAAS,CAAC,mCAAmC,CAAC,UAAU,EAAE,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,uBAAuB,CAAC;AAClT,CAAC","sourcesContent":["import { mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type {\n\tCompactableTranscript,\n\tCompactableTranscriptEntry,\n\tContextCompactionParameters,\n} from \"./context-compaction-types.ts\";\nimport {\n\tcontextCompactionTargetLabel,\n\tcontextCompactionTargetReductionPercent,\n} from \"./context-compaction-metrics.ts\";\nimport { getTranscriptCompactionParameters } from \"./context-compaction-strategy.ts\";\nimport { isExcludedFromLlmContext } from \"./context-transcript-analysis.ts\";\n\nconst CONTEXT_MANIFEST_MAX_ENTRIES = 80;\nconst CONTEXT_MANIFEST_PREVIEW_CHARS = 240;\n\nexport const CONTEXT_COMPACTION_SYSTEM_PROMPT = `You are a context compaction assistant.\n\nYour task is to read relevant parts of a conversation between a user and an AI assistant provided via a transcript file, then run a series of tools to apply deletion-only verbatim compaction using the exact context_delete or context_grep_delete format specified.`;\n\nfunction contextCompactionFixedPrompt(parameters: ContextCompactionParameters): string {\n\tconst targetLabel = contextCompactionTargetLabel(parameters);\n\treturn `Reference the provided transcript file transcript and use your search/read tools for small inspections, then use context_delete or context_grep_delete for deletions.\n\nCompaction records deletion targets, not replacement content.\nFor context_delete, use id-only targets: stable entryId values and optional blockIndex values only.\nFor context_grep_delete, use a concise literal or regex pattern to select matching entries or blocks; do not paste full transcript entries or content-block bodies.\nDo not summarize, paraphrase, or generate replacement context; those are not accepted compaction outputs.\nDo not mutate retained transcript objects or content.\nDeletion tool calls are the compaction action.\n\nStrategy:\n- Start by calling context_compaction_budget to see how much of the context window is full and how much reduction is needed.\n- Spend a few turns exploring with search/read tools to gain high confidence of candidate blocks to remove.\n- Prefer high-confidence exploit actions after that: delete obvious low-value entries via context_grep_delete or context_delete.\n- Use grep deletion for repeated low-value patterns.\n- Use exact id deletion for inspected one-off stale entries.\n- Check context_compaction_budget after deletion batches to track progress.\n- Strict requirement: reduce current context by at least ${targetLabel} before finishing. This is a hard completion gate, not a loose goal.\n- Do not send a final plain-text completion message until context_compaction_budget reports at least ${targetLabel} currentReductionPercent.\n- If the strict ${targetLabel} reduction is not met yet, continue removing low-value message entries or content blocks with context_delete/context_grep_delete.\n- Use the focus query to preserve relevant context: ${JSON.stringify(parameters.query)}.\n\nWhat Gets Deleted:\n- Redundant tool outputs: file reads already acted on, grep/search results already processed, passing test output no longer needed.\n- Exploratory dead ends: irrelevant files read, unhelpful or empty searches.\n- Verbose boilerplate: license headers, import blocks the agent isn't modifying, configuration files read for reference.\n- Superseded information: earlier versions of files that have since been edited, old error messages from bugs already fixed.\n- Stale/superseded image context: image content blocks (shown as type \"image\" / text \"[image]\") in older tool results, custom messages, or old user-pasted attachments that the agent has already inspected and no longer needs. Image blocks are large (each costs far more tokens than its \"[image]\" text preview suggests, as reported by context_compaction_budget imageTokenPercent). When images dominate the context, prefer deleting these stale image content blocks before removing useful recent text. Use context_grep_delete with the literal pattern \"[image]\" and target \"content_block\" to find image candidates, then confirm they are stale with context_read_entry before deleting. User text blocks remain protected. Old non-recent user image blocks may be deleted only when non-image user content remains in the same entry; old image-only user entries may be deleted as whole entries only when another task-bearing entry remains.\n\nWhat Survives:\n- Active file paths and line numbers: Any reference the agent might need to navigate.\n- Current error messages: Unresolved bugs and their exact text.\n- Reasoning decisions: Why the agent chose approach A over B. An agent's chain of thought (why it chose this file, what pattern it noticed, what fix it decided on) carries more information-per-token than the raw grep output or file content that informed those decisions.\n- Recent tool calls and their results: The last 3-5 operations.\n- User instructions: The original task and any clarifications.\n- Task-relevant images: Images that are part of the active user task (for example, a screenshot the user just asked about, or the most recent image-bearing result the agent is still acting on). Recent user images and recent tool results are protected by preserve_recent, so do not delete images the agent still needs.\n\nConditionally Deleted:\n- Old Reasoning decisions: If there is nothing else to remove and the target reduction is not met, you can remove entire stale assistant entries, EXCEPT do not delete individual content blocks from any retained assistant message that contains thinking or redacted_thinking blocks. Thinking-bearing assistant messages are all-or-nothing for replay safety.\n\n<output_format>\nCall the context_delete tool one or more times with deletion targets in this shape:\n{ \"deletions\": [{ \"kind\": \"entry\", \"entryId\": \"...\" }] }\n\nFor content-block deletions, use:\n{ \"kind\": \"content_block\", \"entryId\": \"...\", \"blockIndex\": 0 }\n\nThe tool applies and validates deletion targets immediately. You can continue calling it for additional deletions if useful.\n\nFor guarded bulk deletion by text match, call context_grep_delete with a literal pattern or regex. It removes valid matching context, silently ignores candidates that validation does not allow so they are not counted as removals, enforces a per-call maxMatches safety cap and optional expectedMatchCount, and validates through the same tool-call/tool-result safety rules. maxMatches only limits one tool call; there is no cumulative cap across corrected or repeated deletion calls.\n\nThe full transcript is available as a JSONL file path in the prompt, but do NOT try to load the whole file into context. Use context_search_transcript to find candidate entry IDs and context_read_entry to read only small slices (for example maxChars 1000-4000) before deleting.\n\nWhen the strict ${targetLabel} reduction requirement is met, reply with a brief plain-text completion message. Do not include deletion target IDs outside tool calls.\n</output_format>`;\n}\n\nfunction truncateForPrompt(text: string, maxChars: number): string {\n\tif (text.length <= maxChars) return text;\n\treturn `${text.slice(0, maxChars)}\\n[... ${text.length - maxChars} more characters omitted from context compaction prompt]`;\n}\n\nfunction transcriptEntryFilePayload(entry: CompactableTranscriptEntry): unknown {\n\treturn {\n\t\tentryId: entry.entryId,\n\t\tentryType: entry.entryType,\n\t\trole: entry.role,\n\t\tprotected: entry.protected,\n\t\ttokenEstimate: entry.tokenEstimate,\n\t\ttoolCallIds: entry.toolCallIds,\n\t\ttoolResultFor: entry.toolResultFor,\n\t\ttext: entry.text,\n\t\tcontentBlocks: entry.contentBlocks.map((block) => ({\n\t\t\tblockIndex: block.blockIndex,\n\t\t\ttype: block.type,\n\t\t\tprotected: block.protected,\n\t\t\ttoolCallId: block.toolCallId,\n\t\t\ttokenEstimate: block.tokenEstimate,\n\t\t\ttext: block.text,\n\t\t})),\n\t};\n}\n\nexport interface ContextCompactionTranscriptFile {\n\tpath: string;\n\tcleanup(): void;\n}\n\nexport function writeContextCompactionTranscriptFile(transcript: CompactableTranscript): ContextCompactionTranscriptFile {\n\tconst directory = mkdtempSync(join(tmpdir(), \"atomic-context-transcript-\"));\n\tconst path = join(directory, \"transcript.jsonl\");\n\tconst lines = transcript.entries\n\t\t.filter((entry) => !isExcludedFromLlmContext(entry.message))\n\t\t.map((entry) => JSON.stringify(transcriptEntryFilePayload(entry)));\n\twriteFileSync(path, `${lines.join(\"\\n\")}\\n`, \"utf8\");\n\treturn {\n\t\tpath,\n\t\tcleanup: () => rmSync(directory, { recursive: true, force: true }),\n\t};\n}\n\nfunction contextCompactionTranscriptManifest(transcript: CompactableTranscript, transcriptFilePath: string): unknown {\n\tconst eligibleEntries = transcript.entries.filter((entry) => !isExcludedFromLlmContext(entry.message));\n\tconst selectedEntryIds = new Set<string>();\n\tconst selectedEntries: CompactableTranscriptEntry[] = [];\n\tconst addEntry = (entry: CompactableTranscriptEntry): void => {\n\t\tif (selectedEntryIds.has(entry.entryId) || selectedEntries.length >= CONTEXT_MANIFEST_MAX_ENTRIES) return;\n\t\tselectedEntryIds.add(entry.entryId);\n\t\tselectedEntries.push(entry);\n\t};\n\n\tfor (const entry of eligibleEntries.filter((entry) => entry.protected)) {\n\t\taddEntry(entry);\n\t}\n\tfor (const entry of [...eligibleEntries]\n\t\t.filter((entry) => !entry.protected)\n\t\t.sort((left, right) => right.tokenEstimate - left.tokenEstimate)) {\n\t\taddEntry(entry);\n\t}\n\tselectedEntries.sort((left, right) => eligibleEntries.indexOf(left) - eligibleEntries.indexOf(right));\n\n\treturn {\n\t\ttranscriptFilePath,\n\t\ttranscriptFileFormat: \"jsonl: one compactable transcript entry per line with full text and contentBlocks text\",\n\t\ttotalEntries: eligibleEntries.length,\n\t\tmanifestEntries: selectedEntries.length,\n\t\tomittedEntries: Math.max(0, eligibleEntries.length - selectedEntries.length),\n\t\ttokensBefore: transcript.tokensBefore,\n\t\tprotectedEntryIds: transcript.protectedEntryIds,\n\t\tentries: selectedEntries.map((entry) => ({\n\t\t\tentryId: entry.entryId,\n\t\t\trole: entry.role,\n\t\t\tprotected: entry.protected,\n\t\t\ttokenEstimate: entry.tokenEstimate,\n\t\t\ttoolCallIds: entry.toolCallIds,\n\t\t\ttoolResultFor: entry.toolResultFor,\n\t\t\tcontentBlockCount: entry.contentBlocks.length,\n\t\t\tcontentBlocks: entry.contentBlocks.map((block) => ({\n\t\t\t\tblockIndex: block.blockIndex,\n\t\t\t\ttype: block.type,\n\t\t\t\tprotected: block.protected,\n\t\t\t\ttoolCallId: block.toolCallId,\n\t\t\t\ttokenEstimate: block.tokenEstimate,\n\t\t\t})),\n\t\t\tpreview: truncateForPrompt(entry.text, CONTEXT_MANIFEST_PREVIEW_CHARS),\n\t\t})),\n\t};\n}\n\nfunction contextCompactionParametersPrompt(parameters: ContextCompactionParameters): string {\n\treturn `\\n<compaction-parameters>\\n${JSON.stringify(\n\t\t{\n\t\t\tcompression_ratio: parameters.compression_ratio,\n\t\t\tpreserve_recent: parameters.preserve_recent,\n\t\t\tquery: parameters.query,\n\t\t\ttarget_reduction_percent: contextCompactionTargetReductionPercent(parameters),\n\t\t},\n\t\tnull,\n\t\t2,\n\t)}\\n</compaction-parameters>`;\n}\n\nexport function buildContextCompactionPrompt(\n\ttranscript: CompactableTranscript,\n\ttranscriptFilePath = \"<transcript file will be written during context compaction>\",\n\tparameters: ContextCompactionParameters = getTranscriptCompactionParameters(transcript),\n): string {\n\treturn `${contextCompactionFixedPrompt(parameters)}${contextCompactionParametersPrompt(parameters)}\\n\\n<transcript-file>\\n${transcriptFilePath}\\n</transcript-file>\\n\\n<context-manifest>\\n${JSON.stringify(contextCompactionTranscriptManifest(transcript, transcriptFilePath), null, 2)}\\n</context-manifest>`;\n}\n"]}
1
+ {"version":3,"file":"context-compaction-prompt.js","sourceRoot":"","sources":["../../../src/core/compaction/context-compaction-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type {\n\tCompactableTranscript,\n\tCompactableTranscriptEntry,\n\tContextCompactionParameters,\n} from \"./context-compaction-types.ts\";\nimport {\n\tcontextCompactionTargetLabel,\n\tcontextCompactionTargetReductionPercent,\n} from \"./context-compaction-metrics.ts\";\nimport { getTranscriptCompactionParameters } from \"./context-compaction-strategy.ts\";\nimport { isExcludedFromLlmContext } from \"./context-transcript-analysis.ts\";\n\nconst CONTEXT_MANIFEST_MAX_ENTRIES = 80;\nconst CONTEXT_MANIFEST_PREVIEW_CHARS = 240;\n\nexport const CONTEXT_COMPACTION_SYSTEM_PROMPT = `You are a context compaction assistant.\n\nYour task is to read relevant parts of a conversation between a user and an AI assistant provided via a transcript file, then run a series of tools to apply deletion-only verbatim compaction using the exact context_delete or context_grep_delete format specified.`;\n\nfunction contextCompactionFixedPrompt(parameters: ContextCompactionParameters): string {\n\tconst targetLabel = contextCompactionTargetLabel(parameters);\n\treturn `Reference the provided transcript file transcript and use your search/read tools for small inspections, then use context_delete or context_grep_delete for deletions.\n\nCompaction records deletion targets, not replacement content.\nFor context_delete, use id-only targets: stable entryId values and optional blockIndex values only.\nFor context_grep_delete, use a concise literal or regex pattern to select matching entries or blocks; do not paste full transcript entries or content-block bodies.\nDo not summarize, paraphrase, or generate replacement context; those are not accepted compaction outputs.\nDo not mutate retained transcript objects or content.\nDeletion tool calls are the compaction action.\n\nStrategy:\n- Start by calling context_compaction_budget to see how much of the context window is full and how much reduction is needed.\n- Spend a few turns exploring with search/read tools to gain high confidence of candidate blocks to remove.\n- Prefer high-confidence exploit actions after that: delete obvious low-value entries via context_grep_delete or context_delete.\n- Use grep deletion for repeated low-value patterns.\n- Use exact id deletion for inspected one-off stale entries.\n- Check context_compaction_budget after deletion batches to track progress.\n- Strict requirement: reduce current context by at least ${targetLabel} before finishing. This is a hard completion gate, not a loose goal.\n- Do not send a final plain-text completion message until context_compaction_budget reports at least ${targetLabel} currentReductionPercent.\n- If the strict ${targetLabel} reduction is not met yet, continue removing low-value message entries or content blocks with context_delete/context_grep_delete.\n- Use the focus query to preserve relevant context: ${JSON.stringify(parameters.query)}.\n\nWhat Gets Deleted:\n- Redundant tool outputs: file reads already acted on, grep/search results already processed, passing test output no longer needed.\n- Exploratory dead ends: irrelevant files read, unhelpful or empty searches.\n- Verbose boilerplate: license headers, import blocks the agent isn't modifying, configuration files read for reference.\n- Superseded information: earlier versions of files that have since been edited, old error messages from bugs already fixed.\n- Stale/superseded image context: image content blocks (shown as type \"image\" / text \"[image]\") in older tool results, custom messages, or old user-pasted attachments that the agent has already inspected and no longer needs. Image blocks are large (each costs far more tokens than its \"[image]\" text preview suggests, as reported by context_compaction_budget imageTokenPercent). When images dominate the context, prefer deleting these stale image content blocks before removing useful recent text. Use context_grep_delete with the literal pattern \"[image]\" and target \"content_block\" to find image candidates, then confirm they are stale with context_read_entry before deleting. User text blocks remain protected. Old non-recent user image blocks may be deleted only when non-image user content remains in the same entry; old image-only user entries may be deleted as whole entries only when another task-bearing entry remains.\n\nWhat Survives:\n- Active file paths and line numbers: Any reference the agent might need to navigate.\n- Current error messages: Unresolved bugs and their exact text.\n- Reasoning decisions: Why the agent chose approach A over B. An agent's chain of thought (why it chose this file, what pattern it noticed, what fix it decided on) carries more information-per-token than the raw grep output or file content that informed those decisions.\n- Recent tool calls and their results: The last 3-5 operations.\n- User instructions: The original task and any clarifications.\n- Task-relevant images: Images that are part of the active user task (for example, a screenshot the user just asked about, or the most recent image-bearing result the agent is still acting on). Recent user images and recent tool results are protected by preserve_recent, so do not delete images the agent still needs.\n\nConditionally Deleted:\n- Old reasoning decisions: If there is nothing else to remove and the target reduction is not met, you may omit signed reasoning only as a complete logical assistant tool-use turn sequence. Each provider-visible user-like input starts a turn: a non-empty user/custom input (non-whitespace text or an image), a context-eligible bash execution, or a non-empty branch summary. Empty/whitespace-only user or custom inputs and empty branch summaries do not establish a boundary; whitespace-only branch summaries do because their wrapper is visible. Assistant messages and intervening tool results remain in that turn until the next visible user-like input. Never delete any thinking/redacted_thinking-bearing assistant entry from the current final logical turn; a trailing visible input without an assistant response makes the preceding assistant turn historical. In a completed historical turn, retain all thinking/redacted_thinking-bearing assistant entries or delete all of them as whole entries; never retain a proper subset. Never delete individual content blocks from a retained thinking-bearing assistant message.\n\n<output_format>\nCall the context_delete tool one or more times with deletion targets in this shape:\n{ \"deletions\": [{ \"kind\": \"entry\", \"entryId\": \"...\" }] }\n\nFor content-block deletions, use:\n{ \"kind\": \"content_block\", \"entryId\": \"...\", \"blockIndex\": 0 }\n\nThe tool applies and validates deletion targets immediately. You can continue calling it for additional deletions if useful.\n\nFor guarded bulk deletion by text match, call context_grep_delete with a literal pattern or regex. It removes valid matching context, silently ignores candidates that validation does not allow so they are not counted as removals, enforces a per-call maxMatches safety cap and optional expectedMatchCount, and validates through the same tool-call/tool-result safety rules. maxMatches only limits one tool call; there is no cumulative cap across corrected or repeated deletion calls.\n\nThe full transcript is available as a JSONL file path in the prompt, but do NOT try to load the whole file into context. Use context_search_transcript to find candidate entry IDs and context_read_entry to read only small slices (for example maxChars 1000-4000) before deleting.\n\nWhen the strict ${targetLabel} reduction requirement is met, reply with a brief plain-text completion message. Do not include deletion target IDs outside tool calls.\n</output_format>`;\n}\n\nfunction truncateForPrompt(text: string, maxChars: number): string {\n\tif (text.length <= maxChars) return text;\n\treturn `${text.slice(0, maxChars)}\\n[... ${text.length - maxChars} more characters omitted from context compaction prompt]`;\n}\n\nfunction transcriptEntryFilePayload(entry: CompactableTranscriptEntry): unknown {\n\treturn {\n\t\tentryId: entry.entryId,\n\t\tentryType: entry.entryType,\n\t\trole: entry.role,\n\t\tprotected: entry.protected,\n\t\ttokenEstimate: entry.tokenEstimate,\n\t\ttoolCallIds: entry.toolCallIds,\n\t\ttoolResultFor: entry.toolResultFor,\n\t\ttext: entry.text,\n\t\tcontentBlocks: entry.contentBlocks.map((block) => ({\n\t\t\tblockIndex: block.blockIndex,\n\t\t\ttype: block.type,\n\t\t\tprotected: block.protected,\n\t\t\ttoolCallId: block.toolCallId,\n\t\t\ttokenEstimate: block.tokenEstimate,\n\t\t\ttext: block.text,\n\t\t})),\n\t};\n}\n\nexport interface ContextCompactionTranscriptFile {\n\tpath: string;\n\tcleanup(): void;\n}\n\nexport function writeContextCompactionTranscriptFile(transcript: CompactableTranscript): ContextCompactionTranscriptFile {\n\tconst directory = mkdtempSync(join(tmpdir(), \"atomic-context-transcript-\"));\n\tconst path = join(directory, \"transcript.jsonl\");\n\tconst lines = transcript.entries\n\t\t.filter((entry) => !isExcludedFromLlmContext(entry.message))\n\t\t.map((entry) => JSON.stringify(transcriptEntryFilePayload(entry)));\n\twriteFileSync(path, `${lines.join(\"\\n\")}\\n`, \"utf8\");\n\treturn {\n\t\tpath,\n\t\tcleanup: () => rmSync(directory, { recursive: true, force: true }),\n\t};\n}\n\nfunction contextCompactionTranscriptManifest(transcript: CompactableTranscript, transcriptFilePath: string): unknown {\n\tconst eligibleEntries = transcript.entries.filter((entry) => !isExcludedFromLlmContext(entry.message));\n\tconst selectedEntryIds = new Set<string>();\n\tconst selectedEntries: CompactableTranscriptEntry[] = [];\n\tconst addEntry = (entry: CompactableTranscriptEntry): void => {\n\t\tif (selectedEntryIds.has(entry.entryId) || selectedEntries.length >= CONTEXT_MANIFEST_MAX_ENTRIES) return;\n\t\tselectedEntryIds.add(entry.entryId);\n\t\tselectedEntries.push(entry);\n\t};\n\n\tfor (const entry of eligibleEntries.filter((entry) => entry.protected)) {\n\t\taddEntry(entry);\n\t}\n\tfor (const entry of [...eligibleEntries]\n\t\t.filter((entry) => !entry.protected)\n\t\t.sort((left, right) => right.tokenEstimate - left.tokenEstimate)) {\n\t\taddEntry(entry);\n\t}\n\tselectedEntries.sort((left, right) => eligibleEntries.indexOf(left) - eligibleEntries.indexOf(right));\n\n\treturn {\n\t\ttranscriptFilePath,\n\t\ttranscriptFileFormat: \"jsonl: one compactable transcript entry per line with full text and contentBlocks text\",\n\t\ttotalEntries: eligibleEntries.length,\n\t\tmanifestEntries: selectedEntries.length,\n\t\tomittedEntries: Math.max(0, eligibleEntries.length - selectedEntries.length),\n\t\ttokensBefore: transcript.tokensBefore,\n\t\tprotectedEntryIds: transcript.protectedEntryIds,\n\t\tentries: selectedEntries.map((entry) => ({\n\t\t\tentryId: entry.entryId,\n\t\t\trole: entry.role,\n\t\t\tprotected: entry.protected,\n\t\t\ttokenEstimate: entry.tokenEstimate,\n\t\t\ttoolCallIds: entry.toolCallIds,\n\t\t\ttoolResultFor: entry.toolResultFor,\n\t\t\tcontentBlockCount: entry.contentBlocks.length,\n\t\t\tcontentBlocks: entry.contentBlocks.map((block) => ({\n\t\t\t\tblockIndex: block.blockIndex,\n\t\t\t\ttype: block.type,\n\t\t\t\tprotected: block.protected,\n\t\t\t\ttoolCallId: block.toolCallId,\n\t\t\t\ttokenEstimate: block.tokenEstimate,\n\t\t\t})),\n\t\t\tpreview: truncateForPrompt(entry.text, CONTEXT_MANIFEST_PREVIEW_CHARS),\n\t\t})),\n\t};\n}\n\nfunction contextCompactionParametersPrompt(parameters: ContextCompactionParameters): string {\n\treturn `\\n<compaction-parameters>\\n${JSON.stringify(\n\t\t{\n\t\t\tcompression_ratio: parameters.compression_ratio,\n\t\t\tpreserve_recent: parameters.preserve_recent,\n\t\t\tquery: parameters.query,\n\t\t\ttarget_reduction_percent: contextCompactionTargetReductionPercent(parameters),\n\t\t},\n\t\tnull,\n\t\t2,\n\t)}\\n</compaction-parameters>`;\n}\n\nexport function buildContextCompactionPrompt(\n\ttranscript: CompactableTranscript,\n\ttranscriptFilePath = \"<transcript file will be written during context compaction>\",\n\tparameters: ContextCompactionParameters = getTranscriptCompactionParameters(transcript),\n): string {\n\treturn `${contextCompactionFixedPrompt(parameters)}${contextCompactionParametersPrompt(parameters)}\\n\\n<transcript-file>\\n${transcriptFilePath}\\n</transcript-file>\\n\\n<context-manifest>\\n${JSON.stringify(contextCompactionTranscriptManifest(transcript, transcriptFilePath), null, 2)}\\n</context-manifest>`;\n}\n"]}