@martian-engineering/lossless-claw 0.9.2 → 0.9.4

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.
@@ -53,11 +53,20 @@ Most installations only need to override a handful of keys. If you want a comple
53
53
  "circuitBreakerCooldownMs": 1800000,
54
54
  "fallbackProviders": [],
55
55
  "proactiveThresholdCompactionMode": "deferred",
56
+ "autoRotateSessionFiles": {
57
+ "enabled": true,
58
+ "sizeBytes": 2097152,
59
+ "startup": "rotate",
60
+ "runtime": "rotate"
61
+ },
56
62
  "cacheAwareCompaction": {
57
63
  "enabled": true,
64
+ "cacheTTLSeconds": 300,
58
65
  "maxColdCacheCatchupPasses": 2,
59
66
  "hotCachePressureFactor": 4,
60
- "hotCacheBudgetHeadroomRatio": 0.2
67
+ "hotCacheBudgetHeadroomRatio": 0.2,
68
+ "coldCacheObservationThreshold": 3,
69
+ "criticalBudgetPressureRatio": 0.70
61
70
  },
62
71
  "dynamicLeafChunkTokens": {
63
72
  "enabled": true,
@@ -114,9 +123,17 @@ openclaw plugins install --link /path/to/lossless-claw
114
123
  | `pruneHeartbeatOk` | `boolean` | `false` | `LCM_PRUNE_HEARTBEAT_OK` | Retroactively removes `HEARTBEAT_OK` turn cycles from persisted storage. |
115
124
  | `transcriptGcEnabled` | `boolean` | `false` | `LCM_TRANSCRIPT_GC_ENABLED` | Enables transcript rewrite GC during `maintain()`; disabled by default so transcript rewrites stay opt-in. |
116
125
  | `proactiveThresholdCompactionMode` | `"deferred" \| "inline"` | `"deferred"` | `LCM_PROACTIVE_THRESHOLD_COMPACTION_MODE` | Controls whether proactive threshold compaction is deferred into maintenance debt by default or run inline for legacy behavior. |
126
+ | `autoRotateSessionFiles.enabled` | `boolean` | `true` | `LCM_AUTO_ROTATE_SESSION_FILES_ENABLED` | Enables automatic rotation for oversized LCM-managed session JSONL files. |
127
+ | `autoRotateSessionFiles.sizeBytes` | `integer` | `2097152` | `LCM_AUTO_ROTATE_SESSION_FILES_SIZE_BYTES` | Byte threshold that triggers automatic session-file rotation. |
128
+ | `autoRotateSessionFiles.startup` | `"rotate" \| "warn" \| "off"` | `"rotate"` | `LCM_AUTO_ROTATE_SESSION_FILES_STARTUP` | Startup behavior for oversized indexed OpenClaw session transcripts that also have active LCM bootstrap state. |
129
+ | `autoRotateSessionFiles.runtime` | `"rotate" \| "warn" \| "off"` | `"rotate"` | `LCM_AUTO_ROTATE_SESSION_FILES_RUNTIME` | Runtime behavior after `afterTurn()` and `maintain()` check the current transcript size. |
117
130
 
118
131
  > **Multi-profile note:** `OPENCLAW_STATE_DIR` (set by the host OpenClaw gateway) controls where state is stored. When two gateways run on the same host (e.g. separate bot personas), each gateway sets its own `OPENCLAW_STATE_DIR` and lossless-claw automatically uses that directory for the database, large-file payloads, auth-profile lookups, and legacy secrets — no per-profile plugin config is needed.
119
132
 
133
+ Automatic session-file rotation uses the same safe path as `/lcm rotate`: runtime rotation replaces the rolling `rotate-latest` SQLite backup, rewrites only the live session transcript, keeps the active LCM conversation and durable history intact, and refreshes the bootstrap checkpoint. Startup rotation first scans OpenClaw's current indexed session stores for configured agents, then intersects those candidates with active LCM conversations and matching bootstrap file mappings. If multiple startup candidates need rotation, one pre-rotation LCM database backup is created for the batch before any transcript is rewritten. Rotation never runs for ignored sessions, stateless sessions, or sessions without active LCM state. The preserved JSONL tail follows the existing rotate behavior, which is controlled by `freshTailCount`.
134
+
135
+ Every automatic decision emits grep-able log lines prefixed with `[lcm] auto-rotate:`. Startup emits one compact summary line with `phase=startup`, `action=summary`, `scanned`, `eligible`, `rotated`, `warned`, `skipped`, `durationMs`, `bytesRemoved`, and backup fields when a batch backup was created; quiet skips such as missing files, missing bootstrap mappings, and below-threshold files are counted there instead of producing one line per candidate. Rotation detail lines include `phase`, `action`, `sessionId`, `sessionKey`, `sessionFile`, `sizeBytes`, `thresholdBytes`, `durationMs`, `backupPath`, `bytesRemoved`, `preservedTailMessageCount`, and `checkpointSize`; real warning lines include the same available context plus `reason` or `error`.
136
+
120
137
  ### Compaction thresholds and summary sizing
121
138
 
122
139
  | Key | Type | Default | Env override | Purpose |
@@ -173,6 +190,7 @@ openclaw plugins install --link /path/to/lossless-claw
173
190
  | `cacheAwareCompaction.hotCachePressureFactor` | `number` | `4` | `LCM_HOT_CACHE_PRESSURE_FACTOR` | Multiplier applied to the hot-cache leaf trigger before raw-history pressure overrides cache preservation. |
174
191
  | `cacheAwareCompaction.hotCacheBudgetHeadroomRatio` | `number` | `0.2` | `LCM_HOT_CACHE_BUDGET_HEADROOM_RATIO` | Minimum fraction of the real token budget that must remain free before hot-cache incremental compaction is skipped entirely. |
175
192
  | `cacheAwareCompaction.coldCacheObservationThreshold` | `integer` | `3` | `LCM_COLD_CACHE_OBSERVATION_THRESHOLD` | Consecutive cold observations required before non-explicit cache misses are treated as truly cold. This dampens one-off routing noise and provider failover blips. |
193
+ | `cacheAwareCompaction.criticalBudgetPressureRatio` | `number` | `0.70` | `LCM_CRITICAL_BUDGET_PRESSURE_RATIO` | Fraction of the token budget at which deferred compaction bypasses hot-cache delay so prompt-mutating debt can run before overflow. Set to `1` to disable this bypass. |
176
194
 
177
195
  #### `dynamicLeafChunkTokens`
178
196
 
@@ -189,6 +207,7 @@ When cache-aware compaction is enabled:
189
207
  - hot cache skips incremental maintenance entirely when the assembled context is still comfortably below the real token budget
190
208
  - hot cache also gets a short hysteresis window so one ambiguous turn does not immediately discard a recently healthy cache signal
191
209
  - cold cache still allows bounded catch-up passes via `cacheAwareCompaction.maxColdCacheCatchupPasses`
210
+ - once `currentTokenCount >= criticalBudgetPressureRatio * tokenBudget`, deferred compaction bypasses hot-cache delay so prompt-mutating debt can run before emergency overflow handling
192
211
 
193
212
  When incremental leaf compaction still runs on a hot cache, follow-on condensed passes are suppressed so the maintenance cycle only pays for the leaf pass that was explicitly justified.
194
213
 
package/docs/tui.md CHANGED
@@ -245,8 +245,8 @@ Scans for genuinely truncated summaries and can rewrite them in place. This is n
245
245
  # Preview repairs for one conversation
246
246
  lcm-tui doctor 44 --show-diff
247
247
 
248
- # Apply repairs with an OpenAI-compatible backend
249
- lcm-tui doctor 44 --apply --provider openai --model gpt-5.3-codex --base-url https://proxy.example.com/openai
248
+ # Apply repairs through Codex CLI OAuth after `codex login`
249
+ lcm-tui doctor 44 --apply --provider openai-codex --model gpt-5.3-codex
250
250
 
251
251
  # Scan only across every conversation
252
252
  lcm-tui doctor --all
@@ -263,6 +263,8 @@ lcm-tui doctor --all
263
263
  | `--show-diff` | Show unified diff for each fix |
264
264
  | `--timestamps` | Inject timestamps into rewrite source text |
265
265
 
266
+ Use `--provider openai-codex` when you want ChatGPT Plus/Pro OAuth from the Codex CLI. Keep `--provider openai` for direct OpenAI-compatible HTTP calls with a raw `OPENAI_API_KEY`, including custom `--base-url` proxies.
267
+
266
268
  ### `lcm-tui repair`
267
269
 
268
270
  Finds and fixes corrupted summaries (those containing the `[LCM fallback summary]` marker from failed summarization attempts).
@@ -280,7 +282,10 @@ lcm-tui repair 44 --apply
280
282
  # Repair a specific summary
281
283
  lcm-tui repair 44 --summary-id sum_abc123 --apply
282
284
 
283
- # Repair through an OpenAI-compatible backend
285
+ # Repair through Codex CLI OAuth after `codex login`
286
+ lcm-tui repair 44 --apply --provider openai-codex --model gpt-5.3-codex
287
+
288
+ # Repair through a custom OpenAI-compatible proxy with a raw API key
284
289
  lcm-tui repair 44 --apply --provider openai --model gpt-5.3-codex --base-url https://proxy.example.com/openai
285
290
  ```
286
291
 
@@ -316,10 +321,10 @@ lcm-tui rewrite 44 --depth 0 --apply
316
321
  # Rewrite everything bottom-up
317
322
  lcm-tui rewrite 44 --all --apply --diff
318
323
 
319
- # Rewrite with OpenAI Responses API
320
- lcm-tui rewrite 44 --summary sum_abc123 --provider openai --model gpt-5.3-codex --apply
324
+ # Rewrite with Codex CLI OAuth after `codex login`
325
+ lcm-tui rewrite 44 --summary sum_abc123 --provider openai-codex --model gpt-5.3-codex --apply
321
326
 
322
- # Rewrite through a custom OpenAI-compatible proxy
327
+ # Rewrite through a custom OpenAI-compatible proxy with a raw API key
323
328
  lcm-tui rewrite 44 --summary sum_abc123 --provider openai --model gpt-5.3-codex --base-url https://proxy.example.com/openai --apply
324
329
 
325
330
  # Use custom prompt templates
@@ -412,10 +417,10 @@ lcm-tui backfill my-agent session_abc123 --apply --recompact --single-root
412
417
  # Import + compact + transplant into an active conversation
413
418
  lcm-tui backfill my-agent session_abc123 --apply --transplant-to 653
414
419
 
415
- # Backfill using OpenAI
416
- lcm-tui backfill my-agent session_abc123 --apply --provider openai --model gpt-5.3-codex
420
+ # Backfill using Codex CLI OAuth after `codex login`
421
+ lcm-tui backfill my-agent session_abc123 --apply --provider openai-codex --model gpt-5.3-codex
417
422
 
418
- # Backfill through a custom OpenAI-compatible proxy
423
+ # Backfill through a custom OpenAI-compatible proxy with a raw API key
419
424
  lcm-tui backfill my-agent session_abc123 --apply --provider openai --model gpt-5.3-codex --base-url https://proxy.example.com/openai
420
425
  ```
421
426
 
@@ -1,9 +1,20 @@
1
1
  {
2
2
  "id": "lossless-claw",
3
3
  "kind": "context-engine",
4
+ "activation": {
5
+ "onStartup": true
6
+ },
4
7
  "skills": [
5
8
  "skills/lossless-claw"
6
9
  ],
10
+ "contracts": {
11
+ "tools": [
12
+ "lcm_grep",
13
+ "lcm_describe",
14
+ "lcm_expand",
15
+ "lcm_expand_query"
16
+ ]
17
+ },
7
18
  "uiHints": {
8
19
  "enabled": {
9
20
  "label": "Enabled",
@@ -177,6 +188,10 @@
177
188
  "label": "Cold Cache Observation Threshold",
178
189
  "help": "Consecutive cold observations required before non-explicit cache misses are treated as truly cold"
179
190
  },
191
+ "cacheAwareCompaction.criticalBudgetPressureRatio": {
192
+ "label": "Critical Budget Pressure Ratio",
193
+ "help": "Fraction of token budget at which deferred compaction fires regardless of prompt-cache state. Defaults to 0.70 — set to 1 to disable the override and let cache-aware throttling fully control deferral."
194
+ },
180
195
  "dynamicLeafChunkTokens.enabled": {
181
196
  "label": "Dynamic Leaf Chunk Tokens",
182
197
  "help": "When enabled, incremental compaction uses a larger working leaf chunk in busy sessions and keeps the static floor in quieter sessions"
@@ -201,6 +216,22 @@
201
216
  "label": "Proactive Threshold Compaction Mode",
202
217
  "help": "Choose deferred compaction debt by default or keep legacy inline proactive compaction"
203
218
  },
219
+ "autoRotateSessionFiles.enabled": {
220
+ "label": "Auto-Rotate Session Files",
221
+ "help": "Automatically rotate oversized LCM-managed session JSONL files after startup and runtime checks"
222
+ },
223
+ "autoRotateSessionFiles.sizeBytes": {
224
+ "label": "Auto-Rotate Size Bytes",
225
+ "help": "Session JSONL byte threshold for automatic rotation (default: 2097152)"
226
+ },
227
+ "autoRotateSessionFiles.startup": {
228
+ "label": "Startup Auto-Rotate",
229
+ "help": "Startup behavior for oversized indexed OpenClaw session files with active LCM state: rotate, warn, or off"
230
+ },
231
+ "autoRotateSessionFiles.runtime": {
232
+ "label": "Runtime Auto-Rotate",
233
+ "help": "Runtime behavior for oversized current LCM session files: rotate, warn, or off"
234
+ },
204
235
  "fallbackProviders": {
205
236
  "label": "Fallback Providers",
206
237
  "help": "Explicit fallback provider/model pairs for compaction summarization (e.g., [{\"provider\": \"anthropic\", \"model\": \"claude-haiku-4-5\"}])"
@@ -370,6 +401,11 @@
370
401
  "coldCacheObservationThreshold": {
371
402
  "type": "integer",
372
403
  "minimum": 1
404
+ },
405
+ "criticalBudgetPressureRatio": {
406
+ "type": "number",
407
+ "minimum": 0,
408
+ "maximum": 1
373
409
  }
374
410
  }
375
411
  },
@@ -402,6 +438,35 @@
402
438
  "inline"
403
439
  ]
404
440
  },
441
+ "autoRotateSessionFiles": {
442
+ "type": "object",
443
+ "additionalProperties": false,
444
+ "properties": {
445
+ "enabled": {
446
+ "type": "boolean"
447
+ },
448
+ "sizeBytes": {
449
+ "type": "integer",
450
+ "minimum": 1
451
+ },
452
+ "startup": {
453
+ "type": "string",
454
+ "enum": [
455
+ "rotate",
456
+ "warn",
457
+ "off"
458
+ ]
459
+ },
460
+ "runtime": {
461
+ "type": "string",
462
+ "enum": [
463
+ "rotate",
464
+ "warn",
465
+ "off"
466
+ ]
467
+ }
468
+ }
469
+ },
405
470
  "databasePath": {
406
471
  "description": "Path to LCM SQLite database (preferred key; alias of dbPath, default: <OPENCLAW_STATE_DIR>/lcm.db)",
407
472
  "type": "string"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@martian-engineering/lossless-claw",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "Lossless Context Management plugin for OpenClaw — DAG-based conversation summarization with incremental compaction",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -31,20 +31,34 @@
31
31
  "LICENSE"
32
32
  ],
33
33
  "dependencies": {
34
- "@mariozechner/pi-agent-core": "0.66.1",
35
- "@mariozechner/pi-ai": "0.66.1",
36
- "@mariozechner/pi-coding-agent": "0.66.1",
37
34
  "@sinclair/typebox": "0.34.48"
38
35
  },
39
36
  "devDependencies": {
40
37
  "@changesets/changelog-github": "^0.6.0",
41
38
  "@changesets/cli": "^2.30.0",
39
+ "@mariozechner/pi-agent-core": "0.66.1",
40
+ "@mariozechner/pi-ai": "0.66.1",
41
+ "@mariozechner/pi-coding-agent": "0.66.1",
42
42
  "esbuild": "^0.28.0",
43
43
  "typescript": "^5.7.0",
44
44
  "vitest": "^3.0.0"
45
45
  },
46
46
  "peerDependencies": {
47
- "openclaw": "*"
47
+ "@mariozechner/pi-agent-core": ">=0.66 <1",
48
+ "@mariozechner/pi-ai": ">=0.66 <1",
49
+ "@mariozechner/pi-coding-agent": ">=0.66 <1",
50
+ "openclaw": ">=2026.2.17 <2026.6.0"
51
+ },
52
+ "peerDependenciesMeta": {
53
+ "@mariozechner/pi-agent-core": {
54
+ "optional": true
55
+ },
56
+ "@mariozechner/pi-ai": {
57
+ "optional": true
58
+ },
59
+ "@mariozechner/pi-coding-agent": {
60
+ "optional": true
61
+ }
48
62
  },
49
63
  "publishConfig": {
50
64
  "access": "public"
@@ -52,7 +66,17 @@
52
66
  "openclaw": {
53
67
  "extensions": [
54
68
  "./dist/index.js"
55
- ]
69
+ ],
70
+ "compat": {
71
+ "pluginApi": ">=2026.2.17 <2026.6.0",
72
+ "minGatewayVersion": "2026.2.17",
73
+ "tested": [
74
+ "2026.5.2"
75
+ ]
76
+ },
77
+ "build": {
78
+ "openclawVersion": "2026.2.17"
79
+ }
56
80
  },
57
81
  "repository": {
58
82
  "type": "git",
@@ -103,12 +103,14 @@ Good defaults:
103
103
  - `hotCachePressureFactor: 4`
104
104
  - `hotCacheBudgetHeadroomRatio: 0.2`
105
105
  - `coldCacheObservationThreshold: 3`
106
+ - `criticalBudgetPressureRatio: 0.70`
106
107
 
107
108
  Operationally:
108
109
 
109
110
  - hot cache stretches the incremental leaf trigger to `dynamicLeafChunkTokens.max`
110
111
  - hot cache skips incremental maintenance entirely when the assembled context is comfortably below the real token budget
111
112
  - hot cache gets a short hysteresis window so a recent cache hit stays "hot" briefly unless telemetry shows a break
113
+ - critical token-budget pressure bypasses hot-cache delay once the live prompt reaches `criticalBudgetPressureRatio * tokenBudget`
112
114
  - if hot-cache maintenance still runs, it stays leaf-only and suppresses follow-on condensed passes
113
115
 
114
116
  ### `dynamicLeafChunkTokens`
@@ -233,6 +235,32 @@ Why it matters:
233
235
  - `/lossless status` and `/lcm status` surface pending/running/last-failure maintenance state so operators can see when compaction is queued
234
236
  - background `maintain()` can still do non-prompt-mutating work, but prompt-mutating debt is consumed pre-assembly once cache is cold or the next turn is already approaching overflow
235
237
 
238
+ ### `autoRotateSessionFiles`
239
+
240
+ Automatically rotates oversized LCM-managed session JSONL files.
241
+
242
+ Defaults:
243
+
244
+ - `enabled: true`
245
+ - `sizeBytes: 2097152`
246
+ - `startup: "rotate"`
247
+ - `runtime: "rotate"`
248
+
249
+ Why it matters:
250
+
251
+ - prevents very large OpenClaw session JSONL files from choking fallback/gateway startup while LCM owns the durable context
252
+ - runtime rotation uses the same backup-backed safe path as `/lossless rotate` / `/lcm rotate`
253
+ - startup scans OpenClaw's current indexed session stores for configured agents, intersects those candidates with active LCM bootstrap state, and creates one pre-rotation DB backup for the startup batch
254
+ - only runs for active, writable LCM conversations; ignored sessions, stateless sessions, sessions outside the indexed startup candidate set, and sessions without active LCM state are skipped
255
+ - the preserved transcript tail follows the normal rotate behavior controlled by `freshTailCount`
256
+
257
+ Operational logging:
258
+
259
+ - every decision is logged with the prefix `[lcm] auto-rotate:`
260
+ - startup emits one compact `action=summary` line with `scanned`, `eligible`, `rotated`, `warned`, `skipped`, `durationMs`, and `bytesRemoved`
261
+ - rotate logs include `phase`, `action`, `sessionId`, `sessionKey`, `sessionFile`, `sizeBytes`, `thresholdBytes`, `durationMs`, `backupPath`, `bytesRemoved`, `preservedTailMessageCount`, and `checkpointSize`
262
+ - real warning logs include the same available context plus `reason` or `error`; quiet startup skips such as missing files, missing bootstrap mappings, and below-threshold files are counted in the summary instead of logged per candidate
263
+
236
264
  ## Compaction timing and shape
237
265
 
238
266
  ### `contextThreshold`
@@ -428,6 +456,24 @@ Default:
428
456
 
429
457
  - `3`
430
458
 
459
+ #### `cacheAwareCompaction.criticalBudgetPressureRatio`
460
+
461
+ Fraction of the token budget at which deferred compaction bypasses hot-cache delay.
462
+
463
+ Why it matters:
464
+
465
+ - lets prompt-mutating deferred compaction run before the runtime falls back to emergency overflow handling
466
+ - preserves cache-aware throttling below the pressure threshold
467
+ - can be set to `1` to disable this pressure bypass
468
+
469
+ Default:
470
+
471
+ - `0.70`
472
+
473
+ Env override:
474
+
475
+ - `LCM_CRITICAL_BUDGET_PRESSURE_RATIO`
476
+
431
477
  ### `dynamicLeafChunkTokens`
432
478
 
433
479
  #### `dynamicLeafChunkTokens.enabled`