@bastani/atomic 0.8.29 → 0.8.30-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/builtin/cursor/CHANGELOG.md +4 -0
  3. package/dist/builtin/cursor/package.json +2 -2
  4. package/dist/builtin/intercom/CHANGELOG.md +4 -0
  5. package/dist/builtin/intercom/package.json +2 -2
  6. package/dist/builtin/mcp/CHANGELOG.md +4 -0
  7. package/dist/builtin/mcp/package.json +3 -3
  8. package/dist/builtin/subagents/CHANGELOG.md +9 -0
  9. package/dist/builtin/subagents/README.md +10 -30
  10. package/dist/builtin/subagents/package.json +4 -4
  11. package/dist/builtin/subagents/skills/subagent/SKILL.md +5 -11
  12. package/dist/builtin/subagents/src/agents/agent-management.ts +0 -5
  13. package/dist/builtin/subagents/src/agents/agent-serializer.ts +7 -3
  14. package/dist/builtin/subagents/src/agents/agents.ts +4 -29
  15. package/dist/builtin/subagents/src/agents/chain-serializer.ts +27 -25
  16. package/dist/builtin/subagents/src/extension/schemas.ts +0 -75
  17. package/dist/builtin/subagents/src/runs/background/async-execution.ts +0 -29
  18. package/dist/builtin/subagents/src/runs/background/run-status.ts +1 -2
  19. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +134 -239
  20. package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +1 -52
  21. package/dist/builtin/subagents/src/runs/foreground/execution.ts +103 -94
  22. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +0 -10
  23. package/dist/builtin/subagents/src/runs/shared/dynamic-fanout.ts +16 -8
  24. package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +0 -1
  25. package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +0 -3
  26. package/dist/builtin/subagents/src/runs/shared/structured-output.ts +67 -2
  27. package/dist/builtin/subagents/src/runs/shared/subagent-control.ts +6 -20
  28. package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +1 -1
  29. package/dist/builtin/subagents/src/runs/shared/workflow-graph.ts +2 -6
  30. package/dist/builtin/subagents/src/shared/settings.ts +1 -4
  31. package/dist/builtin/subagents/src/shared/types.ts +1 -156
  32. package/dist/builtin/subagents/src/tui/render.ts +0 -1
  33. package/dist/builtin/web-access/CHANGELOG.md +4 -0
  34. package/dist/builtin/web-access/package.json +2 -2
  35. package/dist/builtin/workflows/CHANGELOG.md +11 -0
  36. package/dist/builtin/workflows/README.md +2 -2
  37. package/dist/builtin/workflows/package.json +2 -2
  38. package/dist/builtin/workflows/src/extension/index.ts +8 -1
  39. package/dist/builtin/workflows/src/extension/wiring.ts +66 -10
  40. package/dist/builtin/workflows/src/runs/foreground/executor.ts +70 -19
  41. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +98 -14
  42. package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +0 -1
  43. package/dist/builtin/workflows/src/shared/persistence-restore.ts +4 -0
  44. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
  45. package/dist/builtin/workflows/src/shared/store.ts +2 -0
  46. package/dist/config.d.ts.map +1 -1
  47. package/dist/config.js +18 -4
  48. package/dist/config.js.map +1 -1
  49. package/dist/core/agent-session.d.ts +2 -2
  50. package/dist/core/agent-session.d.ts.map +1 -1
  51. package/dist/core/agent-session.js +21 -9
  52. package/dist/core/agent-session.js.map +1 -1
  53. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  54. package/dist/core/compaction/branch-summarization.js +2 -2
  55. package/dist/core/compaction/branch-summarization.js.map +1 -1
  56. package/dist/core/compaction/compaction.d.ts +6 -0
  57. package/dist/core/compaction/compaction.d.ts.map +1 -1
  58. package/dist/core/compaction/compaction.js +2 -0
  59. package/dist/core/compaction/compaction.js.map +1 -1
  60. package/dist/core/compaction/context-compaction.d.ts +43 -16
  61. package/dist/core/compaction/context-compaction.d.ts.map +1 -1
  62. package/dist/core/compaction/context-compaction.js +518 -189
  63. package/dist/core/compaction/context-compaction.js.map +1 -1
  64. package/dist/core/extensions/loader.d.ts +4 -2
  65. package/dist/core/extensions/loader.d.ts.map +1 -1
  66. package/dist/core/extensions/loader.js +11 -7
  67. package/dist/core/extensions/loader.js.map +1 -1
  68. package/dist/core/extensions/types.d.ts +14 -3
  69. package/dist/core/extensions/types.d.ts.map +1 -1
  70. package/dist/core/extensions/types.js.map +1 -1
  71. package/dist/core/model-registry.d.ts.map +1 -1
  72. package/dist/core/model-registry.js +2 -1
  73. package/dist/core/model-registry.js.map +1 -1
  74. package/dist/core/package-manager.d.ts +1 -1
  75. package/dist/core/package-manager.d.ts.map +1 -1
  76. package/dist/core/package-manager.js +52 -18
  77. package/dist/core/package-manager.js.map +1 -1
  78. package/dist/core/resource-loader.d.ts +20 -0
  79. package/dist/core/resource-loader.d.ts.map +1 -1
  80. package/dist/core/resource-loader.js +89 -24
  81. package/dist/core/resource-loader.js.map +1 -1
  82. package/dist/core/session-manager.d.ts +14 -1
  83. package/dist/core/session-manager.d.ts.map +1 -1
  84. package/dist/core/session-manager.js +145 -3
  85. package/dist/core/session-manager.js.map +1 -1
  86. package/dist/core/settings-manager.d.ts +9 -0
  87. package/dist/core/settings-manager.d.ts.map +1 -1
  88. package/dist/core/settings-manager.js +16 -0
  89. package/dist/core/settings-manager.js.map +1 -1
  90. package/dist/core/thinking-blocks.d.ts +7 -0
  91. package/dist/core/thinking-blocks.d.ts.map +1 -0
  92. package/dist/core/thinking-blocks.js +16 -0
  93. package/dist/core/thinking-blocks.js.map +1 -0
  94. package/dist/core/tools/bash.d.ts.map +1 -1
  95. package/dist/core/tools/bash.js +4 -0
  96. package/dist/core/tools/bash.js.map +1 -1
  97. package/dist/index.d.ts +2 -2
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +1 -1
  100. package/dist/index.js.map +1 -1
  101. package/dist/main.d.ts.map +1 -1
  102. package/dist/main.js +30 -0
  103. package/dist/main.js.map +1 -1
  104. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  105. package/dist/modes/interactive/components/tree-selector.js +87 -12
  106. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  107. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  108. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  109. package/dist/modes/interactive/interactive-mode.js +37 -18
  110. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  111. package/dist/modes/interactive/theme/theme.d.ts +24 -1
  112. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  113. package/dist/modes/interactive/theme/theme.js +58 -13
  114. package/dist/modes/interactive/theme/theme.js.map +1 -1
  115. package/dist/utils/child-process.d.ts +9 -4
  116. package/dist/utils/child-process.d.ts.map +1 -1
  117. package/dist/utils/child-process.js +42 -10
  118. package/dist/utils/child-process.js.map +1 -1
  119. package/dist/utils/version-check.d.ts.map +1 -1
  120. package/dist/utils/version-check.js +4 -27
  121. package/dist/utils/version-check.js.map +1 -1
  122. package/docs/compaction.md +469 -51
  123. package/docs/containerization.md +37 -37
  124. package/docs/extensions.md +23 -14
  125. package/docs/models.md +6 -4
  126. package/docs/packages.md +2 -0
  127. package/docs/providers.md +1 -1
  128. package/docs/subagents.md +11 -4
  129. package/docs/workflows.md +4 -2
  130. package/examples/extensions/README.md +2 -2
  131. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  132. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  133. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  134. package/examples/extensions/gondolin/package-lock.json +2 -2
  135. package/examples/extensions/gondolin/package.json +1 -1
  136. package/examples/extensions/question.ts +39 -18
  137. package/examples/extensions/questionnaire.ts +49 -28
  138. package/examples/extensions/sandbox/package-lock.json +2 -2
  139. package/examples/extensions/sandbox/package.json +1 -1
  140. package/examples/extensions/with-deps/package-lock.json +2 -2
  141. package/examples/extensions/with-deps/package.json +1 -1
  142. package/package.json +7 -5
  143. package/dist/builtin/subagents/src/runs/shared/acceptance.ts +0 -612
  144. package/dist/builtin/subagents/src/runs/shared/completion-guard.ts +0 -147
@@ -25,7 +25,7 @@ Atomic has one context compaction behavior and one separate branch-summarization
25
25
 
26
26
  Summary compaction — the earlier behavior that generated replacement prose — has been removed as an active runtime path. Historical JSONL lines with `type:"compaction"` remain readable on disk but are not injected into active LLM context. See [Legacy Summary Compaction (Retired)](#legacy-summary-compaction-retired) for a comparison and historical reference.
27
27
 
28
- `/compact` has no user-facing arguments. It uses a fixed internal prompt, transcript-bound inspection/deletion tools, local validation, and a `context_compaction` session entry. Auto-compaction uses the same deletion-only path.
28
+ `/compact` has no user-facing arguments. It uses the effective `compaction` settings (`compression_ratio`, `preserve_recent`, and optional `query`), a fixed internal prompt, transcript-bound inspection/deletion tools, local validation, and a `context_compaction` session entry. Auto-compaction uses the same deletion-only path.
29
29
 
30
30
  ## Verbatim vs. Summary Compaction
31
31
 
@@ -45,7 +45,7 @@ Atomic uses Verbatim Compaction as its sole compaction strategy. The following c
45
45
  Coding agents depend on exact file paths (`src/foo.ts:42`), exact commands (`npm run build`), exact error strings, and exact line numbers. A generated summary that says "an error occurred in the auth module" instead of recording the actual stack trace loses irreplaceable information. Deletion is honest: what remains is unchanged, and what was deleted is listed in an inspectable `context_compaction` entry.
46
46
 
47
47
  Deletion can still lose needed context. Atomic mitigates this with:
48
- - **Local validation**: Protected entries (user tasks, recent context, unresolved errors, failed commands) cannot be deleted in standard mode.
48
+ - **Local validation**: Disallowed deletion targets return explicit non-terminating tool errors; grep/regex deletion ignores rejected matches and continues with accepted matches.
49
49
  - **Pre-compaction backups**: A `.compact.bak` snapshot is written before each compaction for persisted sessions.
50
50
  - **Auditable targets**: The `context_compaction` entry records every deleted entry/content-block ID.
51
51
 
@@ -62,6 +62,28 @@ Atomic records those targets in an append-only `context_compaction` entry. When
62
62
 
63
63
  The raw session JSONL remains append-only. Deleted objects stay available in the stored session file and backup snapshot; they are only omitted from future active LLM context on that branch.
64
64
 
65
+ ### Compaction Parameters
66
+
67
+ Atomic uses three effective parameters for each context-compaction run. They are available to extension hooks as `event.parameters`, copied into `event.preparation.parameters`, and returned on `event.result.parameters` after a successful compaction.
68
+
69
+ | Parameter | Type | Default | Meaning |
70
+ |-----------|------|---------|---------|
71
+ | `compression_ratio` | `float` | `0.5` | Fraction of compactable context to keep. `0.3` is aggressive (keep 30%, delete 70%); `0.7` is light (keep 70%, delete 30%). |
72
+ | `preserve_recent` | `int` | `2` | Number of most recent context-eligible messages kept uncompressed / undeletable. |
73
+ | `query` | `string` | auto-detected | Focus query for relevance-based pruning. If provided in settings or `ctx.compact()`, Atomic uses that value; otherwise it derives the query from the latest context-eligible user message. |
74
+
75
+ Settings use the same snake_case names under `compaction`, for example:
76
+
77
+ ```json
78
+ {
79
+ "compaction": {
80
+ "compression_ratio": 0.5,
81
+ "preserve_recent": 2,
82
+ "query": "preserve details relevant to the current refactor"
83
+ }
84
+ }
85
+ ```
86
+
65
87
  ### When It Triggers
66
88
 
67
89
  Auto-compaction triggers when:
@@ -76,72 +98,461 @@ You can also trigger compaction manually with `/compact`. Custom summary instruc
76
98
 
77
99
  ### How It Works
78
100
 
79
- ```mermaid
80
- %%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#f8f9fa','primaryTextColor':'#2c3e50','primaryBorderColor':'#4a5568','lineColor':'#4a90e2','secondaryColor':'#ffffff','tertiaryColor':'#e9ecef'}}}%%
81
- flowchart TD
82
- A["🗣 /compact · auto-threshold · auto-overflow"]
83
- B["collect active branch context\napply prior context_compaction deletions"]
84
- C["build compactable transcript\n(entry IDs · roles · token estimates · text)"]
85
- D["mark protected context\n(user tasks · recent 5 entries · errors · failed commands)"]
86
- E["write temporary transcript file\nsend manifest to planner"]
87
- F["internal deletion planner\nfixed prompt · lowest thinking level"]
88
- G["transcript-bound tools\ncontext_search · context_read · context_delete · context_grep_delete"]
89
- H["validateContextDeletionRequest()\nlocal airlock: unknown · protected · orphaning · empty checks"]
90
- I["write pre-compaction backup snapshot"]
91
- J["appendContextCompaction()\ndeletedTargets · protectedEntryIds · stats · backupPath"]
92
- K["buildSessionContext()\nfilter deleted targets · reuse survivors verbatim"]
93
- L["emit session_compact event\nContextCompactionResult · contextCompactionEntry"]
94
-
95
- A --> B --> C --> D --> E --> F
96
- F <--> G
97
- G --> H
98
- H -->|validated| I --> J --> K --> L
99
- H -->|rejected| F
101
+ The diagram below is intentionally a block diagram, not a flowchart DSL. Read it left to right first, then use the lower diagrams to inspect the tool loop, validation airlock, dependency repair, and persistence path.
102
+
103
+ #### Context compaction at a glance
104
+
105
+ ```text
106
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
107
+ GOAL │
108
+ Delete low-signal transcript objects while leaving every surviving object byte-for-byte │
109
+ equivalent in active model context. No summaries. No paraphrases. No replacement messages. │
110
+ └──────────────────────────────────────────────────────────────────────────────────────────────┘
111
+
112
+ ┌──────────────┐ ┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────┐
113
+ │ 1 Trigger │───▶│ 2 Prepare transcript │───▶│ 3 Planner workspace │───▶│ 4 Tool loop │
114
+ └──────────────┘ └──────────────────────┘ └──────────────────────┘ └──────────────────┘
115
+ │ │ │ │
116
+ │ │ │ ▼
117
+ │ │ │ ┌──────────────────────────┐
118
+ │ │ │ │ 5 Validation airlock │
119
+ │ │ │ └──────────────────────────┘
120
+ │ │ │ │
121
+ │ │ │ ┌─────────────┴─────────────┐
122
+ │ │ │ ▼ ▼
123
+ │ │ │ ┌──────────────────┐ ┌─────────────────────┐
124
+ │ │ │ │ ✗ Correction │ │ ✓ Validated state │
125
+ │ │ │ │ tool result │ │ replaces tool store │
126
+ │ │ │ └──────────────────┘ └─────────────────────┘
127
+ │ │ │ │ │
128
+ │ │ │ └──────────────┬────────────┘
129
+ │ │ │ ▼
130
+ │ │ │ ┌──────────────────────────┐
131
+ │ │ └─────────────▶│ 6 Planner stops or adds │
132
+ │ │ │ more deletion targets │
133
+ │ │ └──────────────────────────┘
134
+ │ │ │
135
+ │ │ ▼
136
+ │ │ ┌──────────────────────────┐
137
+ └───────────────────────┴─────────────────────────────────────────▶│ 7 Persist compaction │
138
+ └──────────────────────────┘
139
+
140
+
141
+ ┌──────────────────────────┐
142
+ │ 8 Rebuild active context │
143
+ └──────────────────────────┘
144
+ ```
145
+
146
+ | Block | Main code path | Input | Output |
147
+ |-------|----------------|-------|--------|
148
+ | 1 Trigger | `/compact`, threshold check, overflow retry, `ctx.compact()` | Current session branch | Compaction request with reason and parameters |
149
+ | 2 Prepare transcript | `prepareContextCompaction` | Branch `SessionEntry[]` plus prior `context_compaction` filters | `ContextCompactionPreparation` |
150
+ | 3 Planner workspace | `runContextDeletionAssistant` | `CompactableTranscript` | Temp JSONL transcript file plus bounded manifest prompt, inheriting the session's current model thinking level |
151
+ | 4 Tool loop | `createContextDeletionTool` tools | Planner tool calls | In-run deletion store updates or correction errors |
152
+ | 5 Validation airlock | `validateContextDeletionRequest` | Candidate cumulative deletion request | Reconciled `deletedTargets` or thrown error |
153
+ | 6 Planner stops or adds more | Agent loop until target is met or no progress remains | Tool results and current context | Final validated deletion state |
154
+ | 7 Persist compaction | session manager append path | `ContextCompactionResult` | New append-only `context_compaction` entry |
155
+ | 8 Rebuild active context | `buildSessionContext` | Branch plus all logical deletion filters | Model messages with deleted objects omitted verbatim |
156
+
157
+ #### Block 1: trigger sources
158
+
159
+ ```text
160
+ ┌───────────────────────────────────────────────┐
161
+ │ Trigger source │
162
+ ├───────────────────────────────────────────────┤
163
+ │ /compact │
164
+ │ fixed deletion-only prompt │
165
+ │ │
166
+ │ Auto threshold / provider overflow │
167
+ │ if contextTokens > contextWindow - reserve │
168
+ │ │
169
+ │ Extension ctx.compact() │
170
+ │ optional compression parameters │
171
+ └───────────────────────────────────────────────┘
100
172
  ```
101
173
 
174
+ All triggers produce the same `ContextDeletionTarget[]` shape and append the same `context_compaction` entry type.
175
+
176
+ #### Block 2: transcript preparation
177
+
178
+ ```text
179
+ append-only SessionEntry branch
180
+
181
+ │ Example branch path:
182
+
183
+ │ entry-0 system/header context
184
+ │ entry-1 user task
185
+ │ entry-2 assistant with toolCall(call-a)
186
+ │ entry-3 toolResult(call-a)
187
+ │ entry-4 assistant note
188
+ │ entry-5 context_compaction ← old logical deletion filters
189
+ │ entry-6 user clarification
190
+ │ entry-7 recent assistant
191
+
192
+
193
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
194
+ │ A. Accumulate prior deletion filters │
195
+ │ │
196
+ │ Prior context_compaction entries are interpreted as filters: │
197
+ │ deletedEntries = Set<entryId> │
198
+ │ deletedContentBlocks = Map<entryId, Set<blockIndex>> │
199
+ │ │
200
+ │ Disk is append-only. Old entries remain in JSONL. They are only hidden from active context. │
201
+ └──────────────────────────────────────────────────────────────────────────────────────────────┘
202
+
203
+
204
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
205
+ │ B. Build filtered path │
206
+ │ │
207
+ │ entry deletion → remove that SessionEntry from the compactable path │
208
+ │ content_block → keep the SessionEntry, but omit selected content blocks │
209
+ │ context_compaction → do not include as a model message │
210
+ │ excludeFromContext → omit from compactable transcript │
211
+ └──────────────────────────────────────────────────────────────────────────────────────────────┘
212
+
213
+
214
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
215
+ │ C. Mark entries that validation will not delete │
216
+ │ │
217
+ │ protected = true when any of these are true: │
218
+ │ • entry is inside the configured preserve_recent context window │
219
+ │ • role is user │
220
+ │ • role is custom │
221
+ │ • role is branchSummary, or entryType is branch_summary │
222
+ │ • assistant stopReason is error │
223
+ │ • toolResult isError is true │
224
+ │ • bashExecution has non-zero exitCode │
225
+ └──────────────────────────────────────────────────────────────────────────────────────────────┘
226
+
227
+
228
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
229
+ │ D. Emit CompactableTranscript │
230
+ │ │
231
+ │ transcript.entries[] contains one CompactableTranscriptEntry per compactable message: │
232
+ │ │
233
+ │ entryId stable id used in deletion targets │
234
+ │ entryType message | custom_message | branch_summary | ... │
235
+ │ role user | assistant | toolResult | bashExecution | custom | branchSummary │
236
+ │ text searchable/readable text │
237
+ │ tokenEstimate stats and manifest prioritization │
238
+ │ protected validation guard bit │
239
+ │ contentBlocks per-block delete targets with original blockIndex │
240
+ │ message original AgentMessage for invariant checks │
241
+ │ toolCallIds ids from assistant toolCall content blocks │
242
+ │ toolResultFor call id answered by a toolResult entry │
243
+ │ │
244
+ │ transcript.protectedEntryIds records the protected ids for the persisted result. │
245
+ └──────────────────────────────────────────────────────────────────────────────────────────────┘
246
+ ```
247
+
248
+ #### Block 3: planner workspace
249
+
250
+ ```text
251
+ CompactableTranscript
252
+
253
+ ├─ writeContextCompactionTranscriptFile(transcript)
254
+
255
+ │ Temporary file layout:
256
+
257
+ │ /tmp/atomic-context-transcript-*/transcript.jsonl
258
+
259
+ │ line 1: { entryId, role, protected, tokenEstimate, text, contentBlocks, ... }
260
+ │ line 2: { entryId, role, protected, tokenEstimate, text, contentBlocks, ... }
261
+ │ ...
262
+
263
+ │ The full transcript text lives here, not in the prompt.
264
+
265
+ └─ buildContextCompactionPrompt(transcript, transcriptFilePath)
266
+
267
+ Prompt body
268
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
269
+ │ Planner guardrails │
270
+ │ • context_delete is id-only: kind, entryId, and optional blockIndex. │
271
+ │ • context_grep_delete may use a concise content pattern, never full block bodies. │
272
+ │ • No-summary/no-paraphrase wording prevents legacy replacement-context behavior. │
273
+ │ • Atomic ignores final prose as a deletion plan; validated tool state is the result. │
274
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
275
+ │ Strategy │
276
+ │ • Aggressively compact/remove blocks. │
277
+ │ • Start with context_compaction_budget to inspect window fullness and reduction target. │
278
+ │ • Spend a few turns exploring with search/read tools to gain high confidence of candidate │
279
+ │ blocks to remove. │
280
+ │ • Prefer high-confidence exploit actions after that: delete obvious low-value entries via │
281
+ │ context_grep_delete or context_delete. │
282
+ │ • Check context_compaction_budget after deletion batches. │
283
+ │ • Treat compression_ratio as strict: default 0.5 means keep 50% / delete 50%. │
284
+ │ • If the target is not met, continue deleting low-value entries/content blocks. │
285
+ │ • Converge quickly; do not keep reading once safe deletion targets are clear. │
286
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
287
+ │ Transcript file path │
288
+ │ The planner can search/read slices through tools instead of loading the whole JSONL file. │
289
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
290
+ │ Manifest │
291
+ │ • max 80 entries │
292
+ │ • entries selected by largest tokenEstimate │
293
+ │ • sorted back into transcript order │
294
+ │ • previews truncated to 240 chars │
295
+ └──────────────────────────────────────────────────────────────────────────────────────────────┘
296
+ ```
297
+
298
+ #### Block 4: transcript-bound tool loop
299
+
300
+ ```text
301
+ ┌────────────────────────────────────┐
302
+ │ ContextDeletionMemoryStore │
303
+ ├────────────────────────────────────┤
304
+ │ deletionTargets: [] │
305
+ │ callCount: 0 │
306
+ │ lastError: undefined │
307
+ │ immutable entry rows │
308
+ │ immutable content-block rows │
309
+ └────────────────────────────────────┘
310
+
311
+ │ serialized transaction
312
+
313
+ ┌──────────────────────────────┐ ┌──────────────┴──────────────┐ ┌──────────────────────────────┐
314
+ │ Inspection tools │ │ Mutation tools │ │ Planner continuation │
315
+ ├──────────────────────────────┤ ├─────────────────────────────┤ ├──────────────────────────────┤
316
+ │ context_search_transcript │ │ context_delete │ │ Every tool result has │
317
+ │ search entry/block text │ │ exact targets │ │ terminate: false. │
318
+ │ no mutation │ │ │ │ │
319
+ │ context_read_entry │ │ context_grep_delete │ │ The planner can respond with │
320
+ │ read bounded text slice │ │ guarded bulk targets │ │ more tool calls, or stop. │
321
+ │ no mutation │ │ │ │ │
322
+ │ context_compaction_budget │ │ Both route through │ │ Final assistant prose is │
323
+ │ window fullness + target │ │ validateContextDeletionRequest│ │ ignored for deletion targets. │
324
+ └──────────────────────────────┘ └─────────────────────────────┘ └──────────────────────────────┘
325
+ ```
326
+
327
+ Mutation tool transaction shape:
328
+
329
+ ```text
330
+ ┌─────────────────────────────────────────────────────────────────────┐
331
+ │ context_delete / context_grep_delete │
332
+ └─────────────────────────────────────────────────────────────────────┘
333
+
334
+ ├─ snapshot current store
335
+ ├─ increment callCount
336
+ ├─ build candidate ContextDeletionTarget[]
337
+ │ context_delete payload is id-only: { kind, entryId, blockIndex? }
338
+ │ context_grep_delete payload uses a concise pattern selector
339
+ ├─ validate incoming targets
340
+ ├─ merge with existing store.deletionTargets
341
+ ├─ validate merged cumulative plan
342
+
343
+ ├─ ✓ success
344
+ │ ├─ replace store.deletionTargets with reconciled targets
345
+ │ ├─ clear lastError
346
+ │ └─ return { content: success text, details: stats, terminate: false }
347
+
348
+ └─ ✗ failure
349
+ ├─ restore snapshot
350
+ ├─ set lastError to exact validation message
351
+ └─ return { content: correction text, details.error, terminate: false }
352
+ ```
353
+
354
+ #### Block 5: validation airlock
355
+
356
+ ```text
357
+ Candidate cumulative deletion request
358
+
359
+
360
+ ┌─────────────────────────────────────────────────────────────────────┐
361
+ │ Gate 0: request shape │
362
+ │ object with deletions[], id-only keys, valid kind, known entryId │
363
+ └─────────────────────────────────────────────────────────────────────┘
364
+
365
+
366
+ ┌─────────────────────────────────────────────────────────────────────┐
367
+ │ Gate 1: recent-context guard │
368
+ │ preserve_recent context entries are rejected with correction text │
369
+ └─────────────────────────────────────────────────────────────────────┘
370
+
371
+
372
+ ┌─────────────────────────────────────────────────────────────────────┐
373
+ │ Gate 2: thinking-content guard │
374
+ │ assistant entries containing thinking/redacted_thinking cannot be │
375
+ │ deleted or partially block-deleted │
376
+ └─────────────────────────────────────────────────────────────────────┘
377
+
378
+
379
+ ┌─────────────────────────────────────────────────────────────────────┐
380
+ │ Gate 3: protected target guard │
381
+ │ disallowed entries/blocks are rejected with correction text │
382
+ └─────────────────────────────────────────────────────────────────────┘
383
+
384
+
385
+ ┌─────────────────────────────────────────────────────────────────────┐
386
+ │ Gate 4: content-block details │
387
+ │ valid integer blockIndex, block exists, not the only block │
388
+ └─────────────────────────────────────────────────────────────────────┘
389
+
390
+
391
+ ┌─────────────────────────────────────────────────────────────────────┐
392
+ │ Gate 5: duplicate targets │
393
+ │ duplicate entry/block targets are rejected │
394
+ └─────────────────────────────────────────────────────────────────────┘
395
+
396
+
397
+ ┌─────────────────────────────────────────────────────────────────────┐
398
+ ┌─────────────────────────────────────────────────────────────────────┐
399
+ │ Gate 6: tool-call/tool-result reconciliation │
400
+ │ repairs paired call/result deletion dependencies when safe │
401
+ │ throws explicit recent-context errors when repair crosses the │
402
+ │ preserve_recent boundary │
403
+ └─────────────────────────────────────────────────────────────────────┘
404
+
405
+
406
+ ┌─────────────────────────────────────────────────────────────────────┐
407
+ │ Gate 7: post-reconcile guards │
408
+ │ no recent targets, no thinking-bearing assistant targets │
409
+ └─────────────────────────────────────────────────────────────────────┘
410
+
411
+
412
+ ┌─────────────────────────────────────────────────────────────────────┐
413
+ │ Gate 8: structural integrity │
414
+ │ no entry/content-block overlap, no all-block deletion by blocks, │
415
+ │ no orphaned tool result, no dangling tool call │
416
+ └─────────────────────────────────────────────────────────────────────┘
417
+
418
+
419
+ ┌─────────────────────────────────────────────────────────────────────┐
420
+ │ Gate 10: context survival │
421
+ │ at least one entry remains, and at least one task-bearing entry │
422
+ │ remains (user, custom, branchSummary, or branch_summary) │
423
+ └─────────────────────────────────────────────────────────────────────┘
424
+
425
+
426
+ ┌─────────────────────────────────────────────────────────────────────┐
427
+ │ Gate 11: stats │
428
+ │ compute objectsBefore, objectsDeleted, tokensBefore, tokensAfter, │
429
+ │ percentReduction │
430
+ └─────────────────────────────────────────────────────────────────────┘
431
+
432
+
433
+ ValidatedContextDeletionResult
434
+ ```
435
+
436
+ #### Block 6: dependency repair as a block diagram
437
+
438
+ ```text
439
+ Normal model-visible pairing
440
+
441
+ ┌─────────────────────────────────────────┐ toolCallId ┌────────────────────────────┐
442
+ │ assistant entry │────────────────────────▶│ toolResult entry │
443
+ │ content block: { type: toolCall, id } │ │ toolResultFor = id │
444
+ └─────────────────────────────────────────┘ └────────────────────────────┘
445
+
446
+ If the assistant tool-call block is deleted:
447
+
448
+ ┌─────────────────────────────────────────┐ ┌────────────────────────────┐
449
+ │ assistant tool-call block deleted │──────── requires ──────▶│ paired result deleted │
450
+ └─────────────────────────────────────────┘ └────────────────────────────┘
451
+ │ │
452
+ └─ if paired result is not deletable │
453
+ validation removes/rejects the unsafe call deletion │
454
+
455
+ If the tool result is deleted:
456
+
457
+ ┌─────────────────────────────────────────┐ ┌────────────────────────────┐
458
+ │ paired call deleted │◀────── requires ───────│ toolResult entry deleted │
459
+ └─────────────────────────────────────────┘ └────────────────────────────┘
460
+ │ │
461
+ └─ if paired call is not deletable │
462
+ validation removes/rejects the unsafe result deletion │
463
+
464
+ Standard recent boundary case:
465
+
466
+ ┌──────────────────────────────┐ repair would delete ┌──────────────────────────────┐
467
+ │ old side of pair requested │────────────────────────────────▶│ last-5 side of pair │
468
+ └──────────────────────────────┘ └──────────────────────────────┘
469
+
470
+
471
+ explicit correction error
472
+ "Cannot delete recent context entry ..."
473
+ ```
474
+
475
+ #### Block 7: persistence and rebuild
476
+
477
+ ```text
478
+ ValidatedContextDeletionResult
479
+
480
+ ├─ deletedTargets
481
+ │ [{ kind: "entry", entryId }, { kind: "content_block", entryId, blockIndex }]
482
+
483
+ ├─ protectedEntryIds
484
+ │ snapshot of ids protected during preparation
485
+
486
+ └─ stats
487
+ object and token reduction estimate
488
+
489
+
490
+ ┌─────────────────────────────────────────────────────────────────────┐
491
+ │ Persist │
492
+ │ 1. write .compact.bak for persisted sessions when available │
493
+ │ 2. append one context_compaction SessionEntry │
494
+ │ 3. emit session_compact event │
495
+ └─────────────────────────────────────────────────────────────────────┘
496
+
497
+
498
+ ┌─────────────────────────────────────────────────────────────────────┐
499
+ │ Future buildSessionContext │
500
+ │ 1. walk branch path │
501
+ │ 2. accumulate all context_compaction filters │
502
+ │ 3. omit deleted entries │
503
+ │ 4. clone messages with deleted content blocks removed │
504
+ │ 5. preserve surviving message objects and content blocks verbatim │
505
+ │ 6. skip unsafe historical filters against latest thinking arrays │
506
+ │ 7. retain paired tool results for restored tool-call blocks │
507
+ └─────────────────────────────────────────────────────────────────────┘
508
+ ```
509
+
510
+ #### Failure paths
511
+
512
+ | Failure path | State mutation | What the planner or caller sees |
513
+ |--------------|----------------|----------------------------------|
514
+ | `context_delete` validation error | Store rolls back to previous deletion targets | Non-terminating correction tool result with exact error |
515
+ | `context_grep_delete` regex/pattern error | Store rolls back to previous deletion targets | Non-terminating correction tool result with exact error |
516
+ | `context_grep_delete` protected/recent match | Matching protected target is ignored and not counted as a deletion | Non-protected matches still apply when validation succeeds |
517
+ | Planner stops without any valid deletion | Nothing persisted | Compaction fails, including last deletion-tool error when available |
518
+ | Provider overflow after some valid deletions | Valid in-run deletions are used | Compaction can proceed with recorded targets |
519
+ | Provider non-overflow error | Nothing persisted | Error propagates |
520
+ | Extension-provided deletion request invalid | Nothing persisted | Extension/caller sees validation failure |
521
+
522
+
523
+
102
524
  1. **Collect active branch context.** Atomic walks the current session branch and applies any earlier `context_compaction` logical deletions.
103
525
  2. **Build a compactable transcript.** Each compactable entry includes a stable `entryId`, role, token estimate, full text, content-block indexes, tool-call IDs, and tool-result links.
104
- 3. **Mark protected context.** Standard compaction protects user instructions, custom messages, branch/summary messages, the last five context-eligible entries, unresolved assistant/tool errors, and failed bash executions.
526
+ 3. **Mark validation guards.** Atomic marks user instructions, custom messages, branch/summary messages, the configured `preserve_recent` context-eligible entries, unresolved assistant/tool errors, and failed bash executions as not directly deletable. If a planner targets one, the deletion tool returns an explicit correction error.
105
527
  4. **Write a temporary transcript file.** The compaction assistant receives a compact manifest plus the path to a JSONL transcript file. It should inspect with tools instead of loading the whole transcript into prompt context.
106
- 5. **Run the deletion planner.** The selected model runs with Atomic's fixed Verbatim Compaction prompt and the lowest supported thinking level for that model. It can search/read transcript slices and then call deletion tools.
528
+ 5. **Run the deletion planner.** The user's currently selected model runs Atomic's fixed Verbatim Compaction prompt using the session's current model thinking level. It can search/read transcript slices and then call deletion tools. The prompt substitutes the effective compaction parameters: `compression_ratio` (fraction to keep, default `0.5`), `preserve_recent` (default `2`), and `query` (explicit or auto-detected). The target reduction is `1 - compression_ratio` and is treated as a strict completion requirement.
107
529
  6. **Validate fail-closed.** Atomic validates every cumulative deletion plan locally. Unknown IDs, protected targets, duplicate/overlapping targets, empty-context plans, missing task-bearing context, and tool-call/tool-result orphaning are rejected.
108
- 7. **Save and rebuild.** Atomic writes a backup snapshot for persisted sessions, appends a `context_compaction` entry with validated targets and stats, then rebuilds the active LLM context from the filtered branch.
530
+ 7. **Continue until target.** Atomic exits the internal planner loop when validated deletion stats meet the configured reduction target. If the model tries to finish early, Atomic injects a follow-up nudge with the current validated reduction and tells the planner to continue removing message entries/content blocks.
531
+ 8. **Save and rebuild.** Atomic writes a backup snapshot for persisted sessions, appends a `context_compaction` entry with validated targets and stats, then rebuilds the active LLM context from the filtered branch.
109
532
 
110
533
  ### Transcript-Bound Tools
111
534
 
112
- The compaction assistant can only compact by using these internal tools:
535
+ The compaction assistant can only compact by using these internal tools. Exact deletion is intentionally id-only: the planner identifies entries or content blocks, then calls `context_delete` with `kind`, `entryId`, and optional `blockIndex`. Content-based deletion goes through `context_grep_delete`, where the planner sends a concise literal or regex pattern and Atomic resolves the matching ids locally. Neither mutation path accepts full block text, replacement bodies, summaries, or rationale fields as deletion payload content.
113
536
 
114
537
  | Tool | Purpose |
115
538
  |------|---------|
116
539
  | `context_search_transcript` | Search entry or content-block text and return small snippets. |
117
540
  | `context_read_entry` | Read a bounded slice of one entry or content block. |
541
+ | `context_compaction_budget` | Report context-window fullness, selected-deletion progress, `compression_ratio`, and remaining work to reach the strict reduction target. |
118
542
  | `context_delete` | Record exact entry/content-block deletion targets. |
119
543
  | `context_grep_delete` | Bulk-delete matching entries or content blocks with guardrails. |
120
544
 
121
- `context_grep_delete` supports literal or regex matching, skips protected/already-deleted context, has match-count caps, can require `expectedMatchCount`, and routes matches through the same validation pipeline as exact deletions.
122
-
123
- Tool calls are cumulative during one compaction run. The assistant can apply several small deletion batches, inspect the updated state, and stop when enough safe context has been removed. Atomic uses the validated tool state as the compaction result; deletion JSON written in ordinary assistant text is not used for the final action.
124
-
125
- ### Protection and Validation Rules
126
-
127
- In standard mode, Atomic protects:
128
-
129
- - User messages and user-provided task context.
130
- - Custom messages, branch summaries, and branch-summary context.
131
- - The last five context-eligible entries on the active branch.
132
- - Assistant messages whose stop reason is an error.
133
- - Tool results marked as errors.
134
- - Failed bash executions.
545
+ The planner is prompted to call `context_compaction_budget` before deleting and after deletion batches. The tool reports the current transcript token estimate as a percentage of the selected model's context window, the configured `compression_ratio`, the projected percentage after selected deletions, current reduction percentage, and how many more estimated tokens must be removed to reach the strict target. With the default `compression_ratio: 0.5`, the strict target is a 50% token reduction.
135
546
 
136
- Validation also preserves tool-call/tool-result consistency. If deleting a tool call would leave a tool result behind, Atomic either deletes the paired result too or rejects the plan when that would violate protection. If deleting a tool result would leave a visible dangling tool call, Atomic either deletes the paired call too or rejects the plan.
547
+ `context_grep_delete` supports literal or regex matching, skips already-deleted or disallowed context, enforces a per-call `maxMatches` safety cap, can require `expectedMatchCount` when the planner wants an exact-match safety check, and routes every accepted match through the same validation pipeline as exact deletions. Disallowed matches are ignored before `matches`, `expectedMatchCount`, deletion stats, and selected targets are calculated, so a broad regex can still remove safe blocks without counting rejected candidates as removed. `maxMatches` limits only one tool call; there is no cumulative deletion cap across repeated `context_delete` or `context_grep_delete` calls. Exact deletion attempts that target disallowed entries/blocks return an explicit non-terminating tool error with correction guidance. Exact deletion payloads that include unsupported fields such as transcript `text`, block `content`, summaries, or replacement data are rejected as non-id-only requests.
137
548
 
138
- Atomic also refuses plans that would delete all context or leave no task-bearing context. These checks are local; the model cannot bypass them.
549
+ Tool calls are cumulative during one compaction run. The assistant can apply several small deletion batches, inspect the updated state, and stop only after the validated stats meet the strict reduction target. Atomic uses the validated tool state as the compaction result; ordinary assistant text is ignored for deletion targets.
139
550
 
140
- ### Standard vs. Critical Overflow Mode
551
+ ### Validation Rules
141
552
 
142
- Manual `/compact` and threshold auto-compaction run in **standard** mode: protected entries and protected content blocks cannot be deleted.
553
+ Validation preserves tool-call/tool-result consistency. If deleting a tool call would leave a tool result behind, Atomic either deletes the paired result too or rejects the plan when that would violate a validation guard. If deleting a tool result would leave a visible dangling tool call, Atomic either deletes the paired call too or rejects the plan.
143
554
 
144
- When a provider returns a context-overflow error, Atomic runs one **critical overflow** recovery pass before retrying. Critical overflow mode first tries stale unprotected context. If that is not enough, it may delete older protected user/custom/summary context, but it still preserves the last five context-eligible entries, unresolved errors, failed commands, and enough task-bearing context for continuation. Atomic retries once after a successful overflow compaction.
555
+ Atomic also refuses plans that would delete all context or leave no task-bearing context. These checks are local; the model cannot bypass them. Provider context-overflow recovery uses the same validation rules as manual and threshold compaction.
145
556
 
146
557
  ### ContextCompactionEntry Structure
147
558
 
@@ -227,14 +638,17 @@ Fired before the internal deletion planner runs. Extensions can cancel compactio
227
638
 
228
639
  ```typescript
229
640
  pi.on("session_before_compact", async (event, ctx) => {
230
- const { preparation, branchEntries, reason, mode, signal } = event;
641
+ const { preparation, parameters, branchEntries, reason, signal } = event;
231
642
 
643
+ // parameters.compression_ratio - fraction of compactable context to keep
644
+ // parameters.preserve_recent - recent context-eligible messages kept uncompressed
645
+ // parameters.query - focus query used by the planner
646
+ // preparation.parameters - same effective parameters on the frozen preparation snapshot
232
647
  // preparation.transcript.entries - entries eligible for deletion
233
- // preparation.transcript.protectedEntryIds - entries that cannot be deleted in standard mode
648
+ // preparation.transcript.protectedEntryIds - entry ids validation will reject if directly deleted
234
649
  // preparation.transcript.tokensBefore - context token estimate before compaction
235
650
  // branchEntries - all entries on current branch
236
651
  // reason - "manual" | "threshold" | "overflow"
237
- // mode - "standard" | "critical_overflow"
238
652
 
239
653
  // Cancel compaction:
240
654
  return { cancel: true };
@@ -259,7 +673,8 @@ Fired after compaction succeeds and the `context_compaction` entry is persisted.
259
673
 
260
674
  ```typescript
261
675
  pi.on("session_compact", async (event, ctx) => {
262
- // event.result - ContextCompactionResult
676
+ // event.parameters - effective compression_ratio, preserve_recent, and query
677
+ // event.result - ContextCompactionResult, including result.parameters
263
678
  // event.contextCompactionEntry - the saved ContextCompactionEntry
264
679
  // event.reason - "manual" | "threshold" | "overflow"
265
680
  // event.fromExtension - true if extension provided the deletionRequest
@@ -279,6 +694,9 @@ Trigger Verbatim Compaction without awaiting completion. See [Extensions](/exten
279
694
 
280
695
  ```typescript
281
696
  ctx.compact({
697
+ compression_ratio: 0.3,
698
+ preserve_recent: 2,
699
+ query: "keep context relevant to the active bug fix",
282
700
  onComplete: (result) => {
283
701
  ctx.ui.notify(`Compacted: deleted ${result.stats.objectsDeleted} objects`, "info");
284
702
  },
@@ -288,7 +706,7 @@ ctx.compact({
288
706
  });
289
707
  ```
290
708
 
291
- `ctx.compact()` does not accept custom instructions. Verbatim Compaction uses a fixed internal prompt; no custom summary text can be injected.
709
+ `ctx.compact()` accepts the same compaction parameters as hooks/settings (`compression_ratio`, `preserve_recent`, and `query`) but does not accept arbitrary custom summary instructions. Verbatim Compaction uses a fixed internal prompt; no custom summary text can be injected.
292
710
 
293
711
  See [examples/extensions/trigger-compact.ts](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/examples/extensions/trigger-compact.ts) for a full example.
294
712