@martian-engineering/lossless-claw 0.8.0 → 0.8.2

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 (52) hide show
  1. package/README.md +8 -0
  2. package/dist/index.js +971 -0
  3. package/docs/configuration.md +15 -5
  4. package/openclaw.plugin.json +27 -3
  5. package/package.json +7 -6
  6. package/skills/lossless-claw/references/config.md +37 -0
  7. package/index.ts +0 -2
  8. package/src/assembler.ts +0 -1196
  9. package/src/compaction.ts +0 -1753
  10. package/src/db/config.ts +0 -345
  11. package/src/db/connection.ts +0 -151
  12. package/src/db/features.ts +0 -61
  13. package/src/db/migration.ts +0 -868
  14. package/src/engine.ts +0 -4486
  15. package/src/estimate-tokens.ts +0 -80
  16. package/src/expansion-auth.ts +0 -365
  17. package/src/expansion-policy.ts +0 -303
  18. package/src/expansion.ts +0 -383
  19. package/src/integrity.ts +0 -600
  20. package/src/large-files.ts +0 -546
  21. package/src/lcm-log.ts +0 -37
  22. package/src/openclaw-bridge.ts +0 -22
  23. package/src/plugin/index.ts +0 -2037
  24. package/src/plugin/lcm-command.ts +0 -1040
  25. package/src/plugin/lcm-doctor-apply.ts +0 -540
  26. package/src/plugin/lcm-doctor-cleaners.ts +0 -655
  27. package/src/plugin/lcm-doctor-shared.ts +0 -210
  28. package/src/plugin/shared-init.ts +0 -59
  29. package/src/prune.ts +0 -391
  30. package/src/retrieval.ts +0 -360
  31. package/src/session-patterns.ts +0 -23
  32. package/src/startup-banner-log.ts +0 -49
  33. package/src/store/compaction-telemetry-store.ts +0 -156
  34. package/src/store/conversation-store.ts +0 -929
  35. package/src/store/fts5-sanitize.ts +0 -50
  36. package/src/store/full-text-fallback.ts +0 -83
  37. package/src/store/full-text-sort.ts +0 -21
  38. package/src/store/index.ts +0 -39
  39. package/src/store/parse-utc-timestamp.ts +0 -25
  40. package/src/store/summary-store.ts +0 -1519
  41. package/src/summarize.ts +0 -1508
  42. package/src/tools/common.ts +0 -53
  43. package/src/tools/lcm-conversation-scope.ts +0 -127
  44. package/src/tools/lcm-describe-tool.ts +0 -245
  45. package/src/tools/lcm-expand-query-tool.ts +0 -1235
  46. package/src/tools/lcm-expand-tool.delegation.ts +0 -580
  47. package/src/tools/lcm-expand-tool.ts +0 -453
  48. package/src/tools/lcm-expansion-recursion-guard.ts +0 -373
  49. package/src/tools/lcm-grep-tool.ts +0 -228
  50. package/src/transaction-mutex.ts +0 -136
  51. package/src/transcript-repair.ts +0 -301
  52. package/src/types.ts +0 -165
@@ -16,11 +16,13 @@ Most installations only need to override a handful of keys. If you want a comple
16
16
  {
17
17
  "enabled": true,
18
18
  "databasePath": "/Users/alice/.openclaw/lcm.db",
19
+ "largeFilesDir": "/Users/alice/.openclaw/lcm-files",
19
20
  "ignoreSessionPatterns": [],
20
21
  "statelessSessionPatterns": [],
21
22
  "skipStatelessSessions": true,
22
23
  "contextThreshold": 0.75,
23
24
  "freshTailCount": 64,
25
+ "freshTailMaxTokens": 24000,
24
26
  "newSessionRetainDepth": 2,
25
27
  "leafMinFanout": 8,
26
28
  "condensedMinFanout": 4,
@@ -42,6 +44,7 @@ Most installations only need to override a handful of keys. If you want a comple
42
44
  "summaryTimeoutMs": 60000,
43
45
  "timezone": "America/Los_Angeles",
44
46
  "pruneHeartbeatOk": false,
47
+ "transcriptGcEnabled": false,
45
48
  "maxAssemblyTokenBudget": 30000,
46
49
  "summaryMaxOverageFactor": 3,
47
50
  "customInstructions": "",
@@ -65,6 +68,7 @@ Notes on the example:
65
68
 
66
69
  - Values shown are the runtime defaults when a fixed default exists.
67
70
  - `databasePath` shows the expanded default path shape. Use an absolute path in config rather than `~`.
71
+ - `largeFilesDir` shows the expanded default path shape. Both `databasePath` and `largeFilesDir` default to paths under `OPENCLAW_STATE_DIR` (which in turn falls back to `~/.openclaw`).
68
72
  - `timezone` has no fixed hardcoded default; at runtime it resolves from `TZ` first, then the system timezone. The example uses `America/Los_Angeles`.
69
73
  - `maxAssemblyTokenBudget` has no default. The example uses `30000` as a realistic cap for a 32k-class model.
70
74
  - `databasePath` is the preferred key. `dbPath` is an accepted alias.
@@ -97,14 +101,18 @@ openclaw plugins install --link /path/to/lossless-claw
97
101
  | Key | Type | Default | Env override | Purpose |
98
102
  | --- | --- | --- | --- | --- |
99
103
  | `enabled` | `boolean` | `true` | `LCM_ENABLED` | Enables or disables lossless-claw without uninstalling it. |
100
- | `databasePath` | `string` | `${HOME}/.openclaw/lcm.db` | `LCM_DATABASE_PATH` | Preferred path for the SQLite database. |
104
+ | `databasePath` | `string` | `${OPENCLAW_STATE_DIR}/lcm.db` | `LCM_DATABASE_PATH` | Preferred path for the SQLite database. |
101
105
  | `dbPath` | `string` | alias of `databasePath` | `LCM_DATABASE_PATH` | Legacy alias for `databasePath`. Prefer `databasePath` in new config. |
106
+ | `largeFilesDir` | `string` | `${OPENCLAW_STATE_DIR}/lcm-files` | `LCM_LARGE_FILES_DIR` | Directory where large-file text payloads are persisted. Automatically follows the active state directory. |
102
107
  | `ignoreSessionPatterns` | `string[]` | `[]` | `LCM_IGNORE_SESSION_PATTERNS` | Session-key glob patterns that skip LCM entirely. |
103
108
  | `statelessSessionPatterns` | `string[]` | `[]` | `LCM_STATELESS_SESSION_PATTERNS` | Session-key glob patterns that may read from LCM but never write to it. |
104
109
  | `skipStatelessSessions` | `boolean` | `true` | `LCM_SKIP_STATELESS_SESSIONS` | Enforces `statelessSessionPatterns` when enabled. |
105
110
  | `newSessionRetainDepth` | `integer` | `2` | `LCM_NEW_SESSION_RETAIN_DEPTH` | Controls what survives `/new`. `-1` keeps all context, `0` keeps summaries only, higher values keep only deeper summaries. |
106
111
  | `timezone` | `string` | `TZ` or system timezone | `TZ` | IANA timezone used for timestamp rendering in summaries. |
107
112
  | `pruneHeartbeatOk` | `boolean` | `false` | `LCM_PRUNE_HEARTBEAT_OK` | Retroactively removes `HEARTBEAT_OK` turn cycles from persisted storage. |
113
+ | `transcriptGcEnabled` | `boolean` | `false` | `LCM_TRANSCRIPT_GC_ENABLED` | Enables transcript rewrite GC during `maintain()`; disabled by default so transcript rewrites stay opt-in. |
114
+
115
+ > **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.
108
116
 
109
117
  ### Compaction thresholds and summary sizing
110
118
 
@@ -112,6 +120,7 @@ openclaw plugins install --link /path/to/lossless-claw
112
120
  | --- | --- | --- | --- | --- |
113
121
  | `contextThreshold` | `number` | `0.75` | `LCM_CONTEXT_THRESHOLD` | Fraction of the active model context window that triggers compaction. |
114
122
  | `freshTailCount` | `integer` | `64` | `LCM_FRESH_TAIL_COUNT` | Number of newest messages always kept raw. |
123
+ | `freshTailMaxTokens` | `integer` | unset | `LCM_FRESH_TAIL_MAX_TOKENS` | Optional token cap for the protected fresh tail. The newest message is always preserved even if it exceeds the cap. |
115
124
  | `leafMinFanout` | `integer` | `8` | `LCM_LEAF_MIN_FANOUT` | Minimum number of raw messages required before a leaf pass runs. |
116
125
  | `condensedMinFanout` | `integer` | `4` | `LCM_CONDENSED_MIN_FANOUT` | Number of same-depth summaries needed before condensation is attempted. |
117
126
  | `condensedMinFanoutHard` | `integer` | `2` | `LCM_CONDENSED_MIN_FANOUT_HARD` | Hard floor for condensation grouping during maintenance and repair flows. |
@@ -237,16 +246,17 @@ These settings are not part of `plugins.entries.lossless-claw.config`, but they
237
246
 
238
247
  | Env var | Default | Purpose |
239
248
  | --- | --- | --- |
249
+ | `OPENCLAW_STATE_DIR` | `~/.openclaw` | Active state directory for the OpenClaw gateway. When set, all path defaults (database, large files, auth profiles, secrets) resolve relative to this directory instead of `~/.openclaw`. Set automatically by OpenClaw for non-default profiles. |
240
250
  | `LCM_TUI_CONVERSATION_WINDOW_SIZE` | `200` | Number of messages `lcm-tui` loads per keyset-paged conversation window. |
241
251
 
242
252
  ## Database operations
243
253
 
244
- The SQLite database lives at `databasePath` or `LCM_DATABASE_PATH`. The default path is `${HOME}/.openclaw/lcm.db`.
254
+ The SQLite database lives at `databasePath` or `LCM_DATABASE_PATH`. The default path is `${OPENCLAW_STATE_DIR}/lcm.db` (resolves to `~/.openclaw/lcm.db` when `OPENCLAW_STATE_DIR` is not set).
245
255
 
246
256
  Inspect it with:
247
257
 
248
258
  ```bash
249
- sqlite3 ~/.openclaw/lcm.db
259
+ sqlite3 "${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/lcm.db"
250
260
 
251
261
  SELECT COUNT(*) FROM conversations;
252
262
  SELECT * FROM context_items WHERE conversation_id = 1 ORDER BY ordinal;
@@ -257,8 +267,8 @@ SELECT summary_id, depth, token_count FROM summaries ORDER BY token_count DESC L
257
267
  Back it up with:
258
268
 
259
269
  ```bash
260
- cp ~/.openclaw/lcm.db ~/.openclaw/lcm.db.backup
261
- sqlite3 ~/.openclaw/lcm.db ".backup ~/.openclaw/lcm.db.backup"
270
+ cp "${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/lcm.db" "${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/lcm.db.backup"
271
+ sqlite3 "${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/lcm.db" ".backup ${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/lcm.db.backup"
262
272
  ```
263
273
 
264
274
  ## Disabling lossless-claw
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "id": "lossless-claw",
3
+ "kind": "context-engine",
3
4
  "skills": [
4
5
  "skills/lossless-claw"
5
6
  ],
@@ -20,6 +21,10 @@
20
21
  "label": "Fresh Tail Count",
21
22
  "help": "Number of recent messages protected from compaction"
22
23
  },
24
+ "freshTailMaxTokens": {
25
+ "label": "Fresh Tail Max Tokens",
26
+ "help": "Optional token cap for the protected fresh tail; the newest message is always preserved"
27
+ },
23
28
  "leafChunkTokens": {
24
29
  "label": "Leaf Chunk Tokens",
25
30
  "help": "Maximum source tokens per leaf compaction chunk before summarization"
@@ -58,11 +63,15 @@
58
63
  },
59
64
  "dbPath": {
60
65
  "label": "Database Path",
61
- "help": "Path to LCM SQLite database (default: ~/.openclaw/lcm.db)"
66
+ "help": "Path to LCM SQLite database (default: <OPENCLAW_STATE_DIR>/lcm.db; falls back to ~/.openclaw/lcm.db)"
62
67
  },
63
68
  "databasePath": {
64
69
  "label": "Database Path",
65
- "help": "Path to LCM SQLite database (preferred key; alias of dbPath)"
70
+ "help": "Path to LCM SQLite database (preferred key; alias of dbPath, default: <OPENCLAW_STATE_DIR>/lcm.db)"
71
+ },
72
+ "largeFilesDir": {
73
+ "label": "Large Files Directory",
74
+ "help": "Directory for persisting large-file text payloads (default: <stateDir>/lcm-files). Uses OPENCLAW_STATE_DIR when set."
66
75
  },
67
76
  "ignoreSessionPatterns": {
68
77
  "label": "Ignored Sessions",
@@ -168,6 +177,10 @@
168
177
  "label": "Prune HEARTBEAT_OK",
169
178
  "help": "Retroactively delete HEARTBEAT_OK turn cycles from LCM storage"
170
179
  },
180
+ "transcriptGcEnabled": {
181
+ "label": "Transcript GC",
182
+ "help": "Enable transcript rewrite GC during maintain(); disabled by default"
183
+ },
171
184
  "fallbackProviders": {
172
185
  "label": "Fallback Providers",
173
186
  "help": "Explicit fallback provider/model pairs for compaction summarization (e.g., [{\"provider\": \"anthropic\", \"model\": \"claude-haiku-4-5\"}])"
@@ -193,6 +206,10 @@
193
206
  "type": "integer",
194
207
  "minimum": 1
195
208
  },
209
+ "freshTailMaxTokens": {
210
+ "type": "integer",
211
+ "minimum": 0
212
+ },
196
213
  "leafChunkTokens": {
197
214
  "type": "integer",
198
215
  "minimum": 1
@@ -341,8 +358,15 @@
341
358
  "pruneHeartbeatOk": {
342
359
  "type": "boolean"
343
360
  },
361
+ "transcriptGcEnabled": {
362
+ "type": "boolean"
363
+ },
344
364
  "databasePath": {
345
- "description": "Path to LCM SQLite database (alias for dbPath)",
365
+ "description": "Path to LCM SQLite database (preferred key; alias of dbPath, default: <OPENCLAW_STATE_DIR>/lcm.db)",
366
+ "type": "string"
367
+ },
368
+ "largeFilesDir": {
369
+ "description": "Directory for persisting large-file text payloads (default: <OPENCLAW_STATE_DIR>/lcm-files)",
346
370
  "type": "string"
347
371
  },
348
372
  "fallbackProviders": {
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@martian-engineering/lossless-claw",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Lossless Context Management plugin for OpenClaw — DAG-based conversation summarization with incremental compaction",
5
5
  "type": "module",
6
- "main": "index.ts",
6
+ "main": "dist/index.js",
7
7
  "license": "MIT",
8
8
  "author": "Josh Lehman <josh@martian.engineering>",
9
9
  "keywords": [
@@ -16,14 +16,14 @@
16
16
  "dag"
17
17
  ],
18
18
  "scripts": {
19
+ "build": "esbuild index.ts --bundle --platform=node --target=node22 --format=esm --outfile=dist/index.js --external:openclaw --external:\"@mariozechner/*\" --minify-whitespace",
19
20
  "changeset": "changeset",
20
- "release:verify": "npm test && npm pack --dry-run",
21
+ "release:verify": "npm run build && npm test && npm pack --dry-run",
21
22
  "test": "vitest run --dir test",
22
23
  "version-packages": "changeset version"
23
24
  },
24
25
  "files": [
25
- "index.ts",
26
- "src/**/*.ts",
26
+ "dist/",
27
27
  "skills/",
28
28
  "openclaw.plugin.json",
29
29
  "docs/",
@@ -38,6 +38,7 @@
38
38
  "devDependencies": {
39
39
  "@changesets/changelog-github": "^0.6.0",
40
40
  "@changesets/cli": "^2.30.0",
41
+ "esbuild": "^0.28.0",
41
42
  "typescript": "^5.7.0",
42
43
  "vitest": "^3.0.0"
43
44
  },
@@ -49,7 +50,7 @@
49
50
  },
50
51
  "openclaw": {
51
52
  "extensions": [
52
- "./index.ts"
53
+ "./dist/index.js"
53
54
  ]
54
55
  },
55
56
  "repository": {
@@ -43,6 +43,20 @@ Good starting range:
43
43
 
44
44
  - `32` to `64`
45
45
 
46
+ ### `freshTailMaxTokens`
47
+
48
+ Optional token cap for the protected fresh tail.
49
+
50
+ Why it matters:
51
+
52
+ - Prevents a few huge tool results from making the "fresh" suffix effectively uncompactable.
53
+ - Still preserves the newest message even if that single message exceeds the cap.
54
+
55
+ Good starting range:
56
+
57
+ - Leave unset unless large tool outputs are forcing avoidable cost or overflow.
58
+ - Start around `12000` to `32000` when you want a softer, size-aware fresh tail.
59
+
46
60
  ### `leafChunkTokens`
47
61
 
48
62
  Caps how much raw material gets summarized into one leaf summary.
@@ -154,6 +168,7 @@ Why it matters:
154
168
 
155
169
  - useful for custom deployments, testing, or isolating environments
156
170
  - wrong path selection is a common reason operators think LCM is empty or not growing
171
+ - the default resolves to `${OPENCLAW_STATE_DIR}/lcm.db` (falls back to `~/.openclaw/lcm.db`)
157
172
 
158
173
  ### `databasePath`
159
174
 
@@ -164,6 +179,15 @@ Why it matters:
164
179
  - this is the documented key new config should use
165
180
  - `dbPath` is still accepted for compatibility
166
181
 
182
+ ### `largeFilesDir`
183
+
184
+ Directory for persisting large-file text payloads externalised from the transcript.
185
+
186
+ Why it matters:
187
+
188
+ - defaults to `${OPENCLAW_STATE_DIR}/lcm-files`; on multi-profile hosts each profile stores files in its own state directory automatically
189
+ - override with `LCM_LARGE_FILES_DIR` or set `largeFilesDir` in plugin config when you want an explicit path
190
+
167
191
  ### `largeFileThresholdTokens`
168
192
 
169
193
  Threshold for externalizing oversized tool/file payloads out of the main transcript into large-file storage.
@@ -173,6 +197,15 @@ Why it matters:
173
197
  - lower values externalize more aggressively
174
198
  - higher values keep more payload inline but can bloat storage and compaction inputs
175
199
 
200
+ ### `transcriptGcEnabled`
201
+
202
+ Controls whether `maintain()` rewrites transcript entries for already-externalized tool results.
203
+
204
+ Why it matters:
205
+
206
+ - keep this off unless you want transcript GC to mutate the live session file during maintenance
207
+ - the default is `false`
208
+
176
209
  ## Compaction timing and shape
177
210
 
178
211
  ### `contextThreshold`
@@ -183,6 +216,10 @@ See high-impact settings above.
183
216
 
184
217
  See high-impact settings above.
185
218
 
219
+ ### `freshTailMaxTokens`
220
+
221
+ See high-impact settings above.
222
+
186
223
  ### `leafChunkTokens`
187
224
 
188
225
  See high-impact settings above.
package/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export { default } from "./src/plugin/index.js";
2
- export { buildCompleteSimpleOptions, shouldOmitTemperatureForApi } from "./src/plugin/index.js";