@martian-engineering/lossless-claw 0.6.2 → 0.7.0

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.
@@ -4,6 +4,10 @@
4
4
  "skills/lossless-claw"
5
5
  ],
6
6
  "uiHints": {
7
+ "enabled": {
8
+ "label": "Enabled",
9
+ "help": "Enable or disable lossless-claw without uninstalling it"
10
+ },
7
11
  "contextThreshold": {
8
12
  "label": "Context Threshold",
9
13
  "help": "Fraction of context window that triggers compaction (0.0–1.0)"
@@ -40,10 +44,26 @@
40
44
  "label": "Max Expand Tokens",
41
45
  "help": "Token cap for lcm_expand_query expansion calls"
42
46
  },
47
+ "leafMinFanout": {
48
+ "label": "Leaf Min Fanout",
49
+ "help": "Minimum number of raw messages required before a leaf compaction pass runs"
50
+ },
51
+ "condensedMinFanout": {
52
+ "label": "Condensed Min Fanout",
53
+ "help": "Number of same-depth summaries required before condensation is attempted"
54
+ },
55
+ "condensedMinFanoutHard": {
56
+ "label": "Condensed Min Fanout Hard",
57
+ "help": "Hard floor for condensation grouping during maintenance and repair flows"
58
+ },
43
59
  "dbPath": {
44
60
  "label": "Database Path",
45
61
  "help": "Path to LCM SQLite database (default: ~/.openclaw/lcm.db)"
46
62
  },
63
+ "databasePath": {
64
+ "label": "Database Path",
65
+ "help": "Path to LCM SQLite database (preferred key; alias of dbPath)"
66
+ },
47
67
  "ignoreSessionPatterns": {
48
68
  "label": "Ignored Sessions",
49
69
  "help": "Glob patterns for session keys to exclude from LCM storage"
@@ -56,6 +76,14 @@
56
76
  "label": "Skip Stateless Sessions",
57
77
  "help": "When enabled, matching stateless session keys skip LCM persistence and grant writes"
58
78
  },
79
+ "largeFileThresholdTokens": {
80
+ "label": "Large File Threshold Tokens",
81
+ "help": "Token threshold that routes text attachments into large-file summarization"
82
+ },
83
+ "largeFileTokenThreshold": {
84
+ "label": "Large File Threshold Tokens",
85
+ "help": "Legacy alias of largeFileThresholdTokens"
86
+ },
59
87
  "summaryModel": {
60
88
  "label": "Summary Model",
61
89
  "help": "Model override for LCM summarization (e.g., 'gpt-5.4' to reuse the session provider, or 'openai-resp/gpt-5.4' for a full cross-provider ref)"
@@ -100,6 +128,38 @@
100
128
  "label": "Custom Instructions",
101
129
  "help": "Natural language instructions injected into all summarization prompts (e.g., formatting rules, tone control)"
102
130
  },
131
+ "circuitBreakerThreshold": {
132
+ "label": "Circuit Breaker Threshold",
133
+ "help": "Consecutive auth failures before the summarization circuit breaker trips"
134
+ },
135
+ "circuitBreakerCooldownMs": {
136
+ "label": "Circuit Breaker Cooldown (ms)",
137
+ "help": "Cooldown before the summarization circuit breaker auto-resets"
138
+ },
139
+ "cacheAwareCompaction.enabled": {
140
+ "label": "Cache-Aware Compaction",
141
+ "help": "When enabled, hot prompt cache defers incremental compaction while cold cache allows bounded catch-up passes"
142
+ },
143
+ "cacheAwareCompaction.maxColdCacheCatchupPasses": {
144
+ "label": "Cold Cache Catch-Up Passes",
145
+ "help": "Maximum incremental leaf passes allowed in one maintenance cycle when prompt cache is cold"
146
+ },
147
+ "cacheAwareCompaction.hotCachePressureFactor": {
148
+ "label": "Hot Cache Pressure Factor",
149
+ "help": "Multiplier applied to the hot-cache leaf trigger before raw-history pressure overrides cache preservation"
150
+ },
151
+ "cacheAwareCompaction.hotCacheBudgetHeadroomRatio": {
152
+ "label": "Hot Cache Budget Headroom",
153
+ "help": "Fraction of the real token budget that must remain free before hot-cache incremental compaction is skipped entirely"
154
+ },
155
+ "dynamicLeafChunkTokens.enabled": {
156
+ "label": "Dynamic Leaf Chunk Tokens",
157
+ "help": "When enabled, incremental compaction uses a larger working leaf chunk in busy sessions and keeps the static floor in quieter sessions"
158
+ },
159
+ "dynamicLeafChunkTokens.max": {
160
+ "label": "Dynamic Leaf Chunk Max",
161
+ "help": "Maximum working leaf chunk target for dynamic incremental compaction. The static leafChunkTokens value remains the floor."
162
+ },
103
163
  "timezone": {
104
164
  "label": "Timezone",
105
165
  "help": "IANA timezone used for summary timestamps"
@@ -107,6 +167,10 @@
107
167
  "pruneHeartbeatOk": {
108
168
  "label": "Prune HEARTBEAT_OK",
109
169
  "help": "Retroactively delete HEARTBEAT_OK turn cycles from LCM storage"
170
+ },
171
+ "fallbackProviders": {
172
+ "label": "Fallback Providers",
173
+ "help": "Explicit fallback provider/model pairs for compaction summarization (e.g., [{\"provider\": \"anthropic\", \"model\": \"claude-haiku-4-5\"}])"
110
174
  }
111
175
  },
112
176
  "configSchema": {
@@ -187,6 +251,10 @@
187
251
  "type": "integer",
188
252
  "minimum": 1000
189
253
  },
254
+ "largeFileTokenThreshold": {
255
+ "type": "integer",
256
+ "minimum": 1000
257
+ },
190
258
  "summaryModel": {
191
259
  "type": "string"
192
260
  },
@@ -224,6 +292,49 @@
224
292
  "customInstructions": {
225
293
  "type": "string"
226
294
  },
295
+ "circuitBreakerThreshold": {
296
+ "type": "integer",
297
+ "minimum": 1
298
+ },
299
+ "circuitBreakerCooldownMs": {
300
+ "type": "integer",
301
+ "minimum": 1
302
+ },
303
+ "cacheAwareCompaction": {
304
+ "type": "object",
305
+ "additionalProperties": false,
306
+ "properties": {
307
+ "enabled": {
308
+ "type": "boolean"
309
+ },
310
+ "maxColdCacheCatchupPasses": {
311
+ "type": "integer",
312
+ "minimum": 1
313
+ },
314
+ "hotCachePressureFactor": {
315
+ "type": "number",
316
+ "minimum": 1
317
+ },
318
+ "hotCacheBudgetHeadroomRatio": {
319
+ "type": "number",
320
+ "minimum": 0,
321
+ "maximum": 0.95
322
+ }
323
+ }
324
+ },
325
+ "dynamicLeafChunkTokens": {
326
+ "type": "object",
327
+ "additionalProperties": false,
328
+ "properties": {
329
+ "enabled": {
330
+ "type": "boolean"
331
+ },
332
+ "max": {
333
+ "type": "integer",
334
+ "minimum": 1
335
+ }
336
+ }
337
+ },
227
338
  "timezone": {
228
339
  "type": "string"
229
340
  },
@@ -233,6 +344,18 @@
233
344
  "databasePath": {
234
345
  "description": "Path to LCM SQLite database (alias for dbPath)",
235
346
  "type": "string"
347
+ },
348
+ "fallbackProviders": {
349
+ "type": "array",
350
+ "items": {
351
+ "type": "object",
352
+ "properties": {
353
+ "provider": { "type": "string" },
354
+ "model": { "type": "string" }
355
+ },
356
+ "required": ["provider", "model"],
357
+ "additionalProperties": false
358
+ }
236
359
  }
237
360
  }
238
361
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@martian-engineering/lossless-claw",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "Lossless Context Management plugin for OpenClaw — DAG-based conversation summarization with incremental compaction",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -1,6 +1,6 @@
1
1
  # Configuration
2
2
 
3
- This reference covers the current `lossless-claw` config surface on `main`, based on `openclaw.plugin.json`.
3
+ This reference covers the current `lossless-claw` config surface on `main`, based on `openclaw.plugin.json`, [`docs/configuration.md`](../../../docs/configuration.md), and the runtime defaults in [`src/db/config.ts`](../../../src/db/config.ts).
4
4
 
5
5
  `lossless-claw` is most effective when the operator understands which settings change compaction behavior and why.
6
6
 
@@ -57,6 +57,49 @@ Use this when:
57
57
  - Your summarizer is rate-limited or expensive.
58
58
  - You want fewer but broader leaf summaries.
59
59
 
60
+ ### `cacheAwareCompaction`
61
+
62
+ Controls how strongly lossless-claw preserves a healthy prompt cache during incremental maintenance.
63
+
64
+ Why it matters:
65
+
66
+ - Hot cache now prefers to keep the cache intact instead of eagerly compacting old raw history.
67
+ - Cold cache still allows bounded catch-up passes so stale sessions can converge.
68
+ - The new defaults are intentionally more aggressive about preserving cache than earlier builds.
69
+
70
+ Good defaults:
71
+
72
+ - `enabled: true`
73
+ - `maxColdCacheCatchupPasses: 2`
74
+ - `hotCachePressureFactor: 4`
75
+ - `hotCacheBudgetHeadroomRatio: 0.2`
76
+
77
+ Operationally:
78
+
79
+ - hot cache stretches the incremental leaf trigger to `dynamicLeafChunkTokens.max`
80
+ - hot cache skips incremental maintenance entirely when the assembled context is comfortably below the real token budget
81
+ - hot cache gets a short hysteresis window so a recent cache hit stays "hot" briefly unless telemetry shows a break
82
+ - if hot-cache maintenance still runs, it stays leaf-only and suppresses follow-on condensed passes
83
+
84
+ ### `dynamicLeafChunkTokens`
85
+
86
+ Controls the working leaf-trigger size used by incremental compaction.
87
+
88
+ Why it matters:
89
+
90
+ - dynamic sizing is now enabled by default
91
+ - busier sessions can use a larger working chunk without changing the static floor
92
+ - hot cache uses the dynamic max as the working leaf trigger
93
+
94
+ Good defaults:
95
+
96
+ - `enabled: true`
97
+ - `max: 2 * leafChunkTokens`
98
+
99
+ With the default `leafChunkTokens=20000`, that means:
100
+
101
+ - `dynamicLeafChunkTokens.max = 40000`
102
+
60
103
  ### `incrementalMaxDepth`
61
104
 
62
105
  Controls how far automatic condensation cascades after leaf compaction.
@@ -112,6 +155,15 @@ Why it matters:
112
155
  - useful for custom deployments, testing, or isolating environments
113
156
  - wrong path selection is a common reason operators think LCM is empty or not growing
114
157
 
158
+ ### `databasePath`
159
+
160
+ Preferred alias of `dbPath`.
161
+
162
+ Why it matters:
163
+
164
+ - this is the documented key new config should use
165
+ - `dbPath` is still accepted for compatibility
166
+
115
167
  ### `largeFileThresholdTokens`
116
168
 
117
169
  Threshold for externalizing oversized tool/file payloads out of the main transcript into large-file storage.
@@ -166,6 +218,16 @@ Why it matters:
166
218
 
167
219
  See high-impact settings above.
168
220
 
221
+ ### `bootstrapMaxTokens`
222
+
223
+ Maximum raw parent-history tokens imported when a brand-new LCM conversation bootstraps.
224
+
225
+ Why it matters:
226
+
227
+ - keeps first-time bootstrap from flooding the conversation with too much old transcript material
228
+ - defaults to `max(6000, floor(leafChunkTokens * 0.3))`
229
+ - only affects the first import path, not ordinary steady-state turns
230
+
169
231
  ## Session-selection controls
170
232
 
171
233
  ### `ignoreSessionPatterns`
@@ -223,6 +285,62 @@ Why it matters:
223
285
  - useful when the runtime model window is smaller than the surrounding system assumes
224
286
  - can prevent oversized assembly on smaller-context models
225
287
 
288
+ ## Nested objects
289
+
290
+ ### `cacheAwareCompaction`
291
+
292
+ #### `cacheAwareCompaction.enabled`
293
+
294
+ Defers incremental leaf compaction more aggressively when prompt-cache telemetry indicates a hot cache.
295
+
296
+ #### `cacheAwareCompaction.maxColdCacheCatchupPasses`
297
+
298
+ Maximum bounded catch-up passes allowed in one maintenance cycle when cache telemetry is cold.
299
+
300
+ #### `cacheAwareCompaction.hotCachePressureFactor`
301
+
302
+ Multiplier applied to the hot-cache leaf trigger before raw-history pressure overrides cache preservation.
303
+
304
+ Why it matters:
305
+
306
+ - higher values preserve hot cache longer
307
+ - lower values revert toward more eager incremental compaction
308
+
309
+ Default:
310
+
311
+ - `4`
312
+
313
+ #### `cacheAwareCompaction.hotCacheBudgetHeadroomRatio`
314
+
315
+ Minimum fraction of the real token budget that must remain free before hot-cache incremental compaction is skipped entirely.
316
+
317
+ Why it matters:
318
+
319
+ - higher values make hot-cache skip behavior stricter
320
+ - lower values allow more hot-cache maintenance before real budget pressure exists
321
+
322
+ Default:
323
+
324
+ - `0.2`
325
+
326
+ ### `dynamicLeafChunkTokens`
327
+
328
+ #### `dynamicLeafChunkTokens.enabled`
329
+
330
+ Enables dynamic working leaf chunk sizes for busier sessions.
331
+
332
+ Default:
333
+
334
+ - `true`
335
+
336
+ #### `dynamicLeafChunkTokens.max`
337
+
338
+ Upper bound for the dynamic working chunk size. The static `leafChunkTokens` value remains the floor.
339
+
340
+ Default:
341
+
342
+ - `max(leafChunkTokens, floor(leafChunkTokens * 2))`
343
+
226
344
  ## Summary quality and prompt controls
227
345
 
228
346
  ### `summaryMaxOverageFactor`
@@ -249,8 +367,12 @@ Why it matters:
249
367
  2. Set the context-engine slot to `lossless-claw`.
250
368
  3. Start with conservative defaults.
251
369
  4. Run `/lossless` after startup to confirm path, size, and summary health.
252
- 5. If recall feels weak, revisit `freshTailCount`, `leafChunkTokens`, and summarizer model quality before changing anything else.
253
- 6. Touch advanced knobs like fanout, large-file thresholds, custom instructions, and assembly caps only after a concrete symptom appears.
370
+ 5. If hot-cache turns still compact too often, inspect the decision logs before changing anything else:
371
+ - `reason=hot-cache-budget-headroom` means the new skip path is working.
372
+ - `reason=hot-cache-defer` means raw-history pressure is below the configured hot-cache factor.
373
+ - `allowCondensedPasses=false` on hot-cache turns is expected.
374
+ 6. If recall feels weak, revisit `freshTailCount`, `leafChunkTokens`, and summarizer model quality before changing anything else.
375
+ 7. Touch advanced knobs like fanout, large-file thresholds, custom instructions, and assembly caps only after a concrete symptom appears.
254
376
 
255
377
  ## Reading the status output
256
378
 
@@ -261,3 +383,13 @@ Useful interpretation notes:
261
383
  - `tokens in context` is the current LCM frontier token count in the live LCM state.
262
384
  - `compression ratio` is shown as a rounded `1:N`, which is easier to read than a tiny percentage for heavily compacted conversations.
263
385
  - `/status` may still show a different context number because it reflects the runtime prompt that was actually assembled and sent on the last turn.
386
+
387
+ ## Keep this reference aligned
388
+
389
+ This file should stay consistent with:
390
+
391
+ - [`docs/configuration.md`](../../../docs/configuration.md)
392
+ - [`openclaw.plugin.json`](../../../openclaw.plugin.json)
393
+ - [`src/db/config.ts`](../../../src/db/config.ts)
394
+
395
+ When config keys, aliases, defaults, or precedence rules change, update all of them together.
package/src/assembler.ts CHANGED
@@ -93,7 +93,11 @@ function buildSystemPromptAddition(summarySignals: SummaryPromptSignal[]): strin
93
93
  "Default recall flow for precision work:",
94
94
  "1) `lcm_grep` to locate relevant summary/message IDs",
95
95
  "2) `lcm_expand_query` with a focused prompt",
96
- "3) Answer with citations to summary IDs used",
96
+ "3) Answer directly from the retrieved evidence",
97
+ "",
98
+ "Keep raw summary IDs in tool context for follow-up; do not include them in the user-facing answer unless the user asks for sources or IDs.",
99
+ "",
100
+ "`lcm_grep` tips: prefer `mode: \"full_text\"` for keyword/topic lookup, quote exact multi-word phrases, use `sort: \"relevance\"` for older-topic retrieval, and use `sort: \"hybrid\"` when recency should still influence ranking.",
97
101
  "",
98
102
  "**Uncertainty checklist (run before answering):**",
99
103
  "- Am I making an exact factual claim from a compressed or condensed summary?",