@martian-engineering/lossless-claw 0.11.3 → 0.12.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.
- package/README.md +18 -4
- package/dist/index.js +101 -46
- package/docs/architecture.md +11 -0
- package/docs/configuration.md +29 -5
- package/openclaw.plugin.json +36 -0
- package/package.json +4 -2
- package/skills/lossless-claw/references/config.md +44 -1
- package/skills/lossless-claw/references/session-lifecycle.md +18 -12
package/docs/architecture.md
CHANGED
|
@@ -212,6 +212,17 @@ LCM handles crash recovery through **bootstrap reconciliation**:
|
|
|
212
212
|
|
|
213
213
|
This handles the case where OpenClaw wrote messages to the session file but crashed before LCM could persist them.
|
|
214
214
|
|
|
215
|
+
For forked child sessions, LCM treats a host-copied parent JSONL branch as a
|
|
216
|
+
first-time bootstrap source and imports only the newest messages that fit within
|
|
217
|
+
`bootstrapMaxTokens`. That keeps child LCM state bounded even if the host fork
|
|
218
|
+
payload still contains a long raw parent branch. The remaining fork-continuity
|
|
219
|
+
contract belongs to the host: when lossless-claw advertises the
|
|
220
|
+
`subagent-spawn` requirement for `thread-bootstrap-projection`, OpenClaw should
|
|
221
|
+
bootstrap the child model thread from the context-engine projection rather than
|
|
222
|
+
from the raw copied transcript. If the host cannot provide that capability,
|
|
223
|
+
lossless-claw can preserve bounded durable state, but it cannot stop the host
|
|
224
|
+
from replaying raw JSONL into the model before assembly.
|
|
225
|
+
|
|
215
226
|
## Operation serialization
|
|
216
227
|
|
|
217
228
|
All mutating operations (ingest, compact) are serialized per-session using a promise queue. This prevents races between concurrent afterTurn/compact calls for the same conversation without blocking operations on different conversations.
|
package/docs/configuration.md
CHANGED
|
@@ -58,6 +58,9 @@ Most installations only need to override a handful of keys. If you want a comple
|
|
|
58
58
|
"expansionModel": "",
|
|
59
59
|
"delegationTimeoutMs": 120000,
|
|
60
60
|
"summaryTimeoutMs": 60000,
|
|
61
|
+
"summaryCallWindowMs": 600000,
|
|
62
|
+
"summaryMaxCallsPerWindow": 24,
|
|
63
|
+
"summarySpendBackoffMs": 1800000,
|
|
61
64
|
"timezone": "America/Los_Angeles",
|
|
62
65
|
"pruneHeartbeatOk": false,
|
|
63
66
|
"transcriptGcEnabled": false,
|
|
@@ -87,7 +90,13 @@ Most installations only need to override a handful of keys. If you want a comple
|
|
|
87
90
|
"dynamicLeafChunkTokens": {
|
|
88
91
|
"enabled": true,
|
|
89
92
|
"max": 40000
|
|
90
|
-
}
|
|
93
|
+
},
|
|
94
|
+
"stripInjectedContextTags": [
|
|
95
|
+
"active_memory_plugin",
|
|
96
|
+
"relevant-memories",
|
|
97
|
+
"relevant_memories",
|
|
98
|
+
"hindsight_memories"
|
|
99
|
+
]
|
|
91
100
|
}
|
|
92
101
|
```
|
|
93
102
|
|
|
@@ -144,11 +153,11 @@ openclaw plugins install --link /path/to/lossless-claw
|
|
|
144
153
|
| `autoRotateSessionFiles.createBackups` | `boolean` | `false` | `LCM_AUTO_ROTATE_SESSION_FILES_CREATE_BACKUPS` | Creates or replaces the rolling `rotate-latest` SQLite backup before automatic session-file rotation. Manual `/lcm rotate` backups are always created. |
|
|
145
154
|
| `autoRotateSessionFiles.sizeBytes` | `integer` | `2097152` | `LCM_AUTO_ROTATE_SESSION_FILES_SIZE_BYTES` | Byte threshold that triggers automatic session-file rotation. |
|
|
146
155
|
| `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. |
|
|
147
|
-
| `autoRotateSessionFiles.runtime` | `"rotate" \| "warn" \| "off"` | `"rotate"` | `LCM_AUTO_ROTATE_SESSION_FILES_RUNTIME` | Runtime behavior after `
|
|
156
|
+
| `autoRotateSessionFiles.runtime` | `"rotate" \| "warn" \| "off"` | `"rotate"` | `LCM_AUTO_ROTATE_SESSION_FILES_RUNTIME` | Runtime behavior after post-turn checks. Runtime `rotate` logs deferral for active session JSONL rewrites and leaves direct rotation to startup or manual `/lcm rotate`. |
|
|
148
157
|
|
|
149
158
|
> **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.
|
|
150
159
|
|
|
151
|
-
Automatic session-file rotation 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. Automatic rotation does not create a SQLite backup by default; set `autoRotateSessionFiles.createBackups` to `true` to make
|
|
160
|
+
Automatic session-file rotation rewrites only the live session transcript, keeps the active LCM conversation and durable history intact, and refreshes the bootstrap checkpoint. Before manual or startup rewrites, rotation forces leaf-only compaction for raw context outside the preserved tail so trimmed transcript messages are covered by LCM summaries without running unrelated summary-condensation passes. 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. Runtime rotation checks from `afterTurn()` and `maintain()` intentionally do not directly rewrite active session JSONL because embedded prompt-lock fences can still be open while tool-call loops and host background maintenance overlap; runtime `rotate` logs a deferral until startup, manual `/lcm rotate`, or a future host-owned full-transcript rewrite primitive is available. Automatic rotation does not create a SQLite backup by default; set `autoRotateSessionFiles.createBackups` to `true` to make startup rotation create one pre-rotation LCM database backup for the batch before any transcript is rewritten. Manual `/lcm rotate` always keeps its backup-backed behavior regardless of this flag. 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`. Transcript GC uses the host-provided `rewriteTranscriptEntries` primitive and defers until host-approved background maintenance when `transcriptGcEnabled` is enabled.
|
|
152
161
|
|
|
153
162
|
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`.
|
|
154
163
|
|
|
@@ -180,6 +189,13 @@ Every automatic decision emits grep-able log lines prefixed with `[lcm] auto-rot
|
|
|
180
189
|
| `maxAssemblyTokenBudget` | `integer` | unset | `LCM_MAX_ASSEMBLY_TOKEN_BUDGET` | Optional hard cap for assembly and threshold evaluation, useful with smaller-context models. |
|
|
181
190
|
| `maxExpandTokens` | `integer` | `4000` | `LCM_MAX_EXPAND_TOKENS` | Default token cap for `lcm_expand_query` responses. |
|
|
182
191
|
|
|
192
|
+
Forked child transcripts are also bounded by `bootstrapMaxTokens` when a host
|
|
193
|
+
copies a raw parent JSONL branch into the child file. This protects the LCM
|
|
194
|
+
database from importing unbounded parent history, but the host must still honor
|
|
195
|
+
the `thread-bootstrap-projection` context-engine capability for subagent or
|
|
196
|
+
thread forks so the model starts from the LCM-assembled compact view instead of
|
|
197
|
+
the raw copied transcript.
|
|
198
|
+
|
|
183
199
|
### Model selection, execution, and prompts
|
|
184
200
|
|
|
185
201
|
| Key | Type | Default | Env override | Purpose |
|
|
@@ -192,6 +208,9 @@ Every automatic decision emits grep-able log lines prefixed with `[lcm] auto-rot
|
|
|
192
208
|
| `expansionProvider` | `string` | `""` | `LCM_EXPANSION_PROVIDER` | `lcm_expand_query` sub-agent provider hint for bare model names. |
|
|
193
209
|
| `delegationTimeoutMs` | `integer` | `120000` | `LCM_DELEGATION_TIMEOUT_MS` | Maximum time to wait for delegated expansion work. `lcm_expand_query` advertises a dynamic tool `timeoutMs` default with 30 seconds of extra RPC headroom so OpenClaw's tool watchdog does not fire before this wait completes. |
|
|
194
210
|
| `summaryTimeoutMs` | `integer` | `60000` | `LCM_SUMMARY_TIMEOUT_MS` | Maximum time to wait for one model-backed summarizer call. |
|
|
211
|
+
| `summaryCallWindowMs` | `integer` | `600000` | `LCM_SUMMARY_CALL_WINDOW_MS` | Rolling window for the per-session summarization spend guard. |
|
|
212
|
+
| `summaryMaxCallsPerWindow` | `integer` | `24` | `LCM_SUMMARY_MAX_CALLS_PER_WINDOW` | Maximum model-backed summarization calls per session/window before Lossless opens a non-auth spend backoff. |
|
|
213
|
+
| `summarySpendBackoffMs` | `integer` | `1800000` | `LCM_SUMMARY_SPEND_BACKOFF_MS` | Cooldown after the summarization spend guard opens. |
|
|
195
214
|
| `customInstructions` | `string` | `""` | `LCM_CUSTOM_INSTRUCTIONS` | Extra natural-language instructions injected into every summarization prompt. |
|
|
196
215
|
|
|
197
216
|
Summary calls are executed through OpenClaw's `api.runtime.llm.complete` capability. If you configure an explicit Lossless summary model (`summaryModel`, `largeFileSummaryModel`, or `fallbackProviders`), OpenClaw must allow that runtime LLM override under `plugins.entries.lossless-claw.llm.allowModelOverride` and `plugins.entries.lossless-claw.llm.allowedModels`. `openclaw doctor --fix` can add the minimal policy entries for configured Lossless summary models. Delegated expansion calls use OpenClaw's runtime sub-agent layer; explicit `expansionModel` values require `plugins.entries.lossless-claw.subagent.allowModelOverride` and a matching `subagent.allowedModels` entry, or `"*"` if you intentionally trust any expansion target. `openclaw doctor --fix` can add the minimal subagent policy, and `lcm_expand_query` retries once without the override if the host rejects it.
|
|
@@ -203,6 +222,7 @@ Summary calls are executed through OpenClaw's `api.runtime.llm.complete` capabil
|
|
|
203
222
|
| `fallbackProviders` | `Array<{ provider: string; model: string }>` | `[]` | `LCM_FALLBACK_PROVIDERS` | Explicit provider/model fallback chain for compaction summarization. Format for env vars is `provider/model,provider/model`. |
|
|
204
223
|
| `circuitBreakerThreshold` | `integer` | `5` | `LCM_CIRCUIT_BREAKER_THRESHOLD` | Consecutive auth failures before the summarization circuit breaker trips. |
|
|
205
224
|
| `circuitBreakerCooldownMs` | `integer` | `1800000` | `LCM_CIRCUIT_BREAKER_COOLDOWN_MS` | Cooldown before the summarization circuit breaker resets automatically. |
|
|
225
|
+
| `stripInjectedContextTags` | `string[]` | `["active_memory_plugin", "relevant-memories", "relevant_memories", "hindsight_memories"]` | `LCM_STRIP_INJECTED_CONTEXT_TAGS` | XML tag names whose blocks are stripped from message content before compaction summarization. Memory/context plugins inject these via `prependContext`; stripping prevents ephemeral retrieval context from polluting compacted summaries. Env var format is comma-separated tag names. Set to `[]` (or empty env string) to disable. |
|
|
206
226
|
|
|
207
227
|
### Nested objects
|
|
208
228
|
|
|
@@ -232,7 +252,8 @@ Automatic compaction is threshold-only:
|
|
|
232
252
|
- `afterTurn()` evaluates `contextThreshold` against the active token budget
|
|
233
253
|
- below threshold, no automatic compaction runs and no leaf debt is recorded
|
|
234
254
|
- at or above threshold, inline mode runs a threshold full sweep immediately
|
|
235
|
-
- deferred mode records one coalesced `"threshold"` maintenance row and drains it in the background
|
|
255
|
+
- deferred mode records one coalesced `"threshold"` maintenance row and normally drains it in the background or host-approved `maintain()`
|
|
256
|
+
- pre-assembly drain is reserved as an emergency safeguard when the live prompt is already over the active token budget
|
|
236
257
|
|
|
237
258
|
Lossless still records prompt-cache telemetry for status and diagnostics, but cache hotness no longer delays threshold debt. Legacy `cacheAwareCompaction.*` and `dynamicLeafChunkTokens.*` settings remain accepted so existing OpenClaw config continues to load, but they do not change automatic compaction behavior.
|
|
238
259
|
|
|
@@ -287,6 +308,8 @@ LCM_EXPANSION_MODEL=openai/gpt-5.4-mini
|
|
|
287
308
|
- `*` matches any characters except `:`
|
|
288
309
|
- `**` matches anything, including `:`
|
|
289
310
|
|
|
311
|
+
Cron scheduler keys (`agent:<agent>:cron:<job>...`) are isolated automatically when a new runtime `sessionId` reuses the same `sessionKey`. Configure `ignoreSessionPatterns` for cron only when the run should bypass LCM entirely; leave cron sessions included when they need in-run compaction.
|
|
312
|
+
|
|
290
313
|
Example:
|
|
291
314
|
|
|
292
315
|
```json
|
|
@@ -318,7 +341,8 @@ Lossless-claw now defaults `proactiveThresholdCompactionMode` to `deferred`.
|
|
|
318
341
|
- deferred mode records a single coalesced maintenance debt row per conversation
|
|
319
342
|
- new deferred compaction debt is only created for `contextThreshold` pressure and uses reason `"threshold"`
|
|
320
343
|
- `maintain()` consumes threshold debt when the host explicitly opts in to deferred execution
|
|
321
|
-
- `assemble()`
|
|
344
|
+
- `assemble()` leaves pending threshold debt for after-turn background drain or host-approved `maintain()` while the live prompt is still within budget
|
|
345
|
+
- `assemble()` only consumes pending threshold debt synchronously as an emergency safeguard when the live prompt estimate is already over the active token budget
|
|
322
346
|
- old non-threshold debt from earlier builds is revalidated; if the conversation is no longer over threshold, it is cleared as a no-op
|
|
323
347
|
- `/lcm status` / `/lossless status` shows the current maintenance state, including pending/running/last-failure details
|
|
324
348
|
- status output also surfaces the latest API/cache telemetry as diagnostics, not as a deferral gate
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "lossless-claw",
|
|
3
|
+
"name": "Lossless Context Management",
|
|
3
4
|
"kind": "context-engine",
|
|
4
5
|
"activation": {
|
|
5
6
|
"onStartup": true
|
|
@@ -168,6 +169,18 @@
|
|
|
168
169
|
"label": "Summary Timeout (ms)",
|
|
169
170
|
"help": "Maximum time to wait for a single model-backed LCM summarizer call before timing out"
|
|
170
171
|
},
|
|
172
|
+
"summaryCallWindowMs": {
|
|
173
|
+
"label": "Summary Call Window (ms)",
|
|
174
|
+
"help": "Rolling window used by the summarization spend guard"
|
|
175
|
+
},
|
|
176
|
+
"summaryMaxCallsPerWindow": {
|
|
177
|
+
"label": "Summary Max Calls Per Window",
|
|
178
|
+
"help": "Maximum model-backed summarization calls per session/window before Lossless opens a non-auth spend backoff"
|
|
179
|
+
},
|
|
180
|
+
"summarySpendBackoffMs": {
|
|
181
|
+
"label": "Summary Spend Backoff (ms)",
|
|
182
|
+
"help": "Cooldown after the summarization spend guard opens"
|
|
183
|
+
},
|
|
171
184
|
"maxAssemblyTokenBudget": {
|
|
172
185
|
"label": "Max Assembly Token Budget",
|
|
173
186
|
"help": "Hard ceiling for assembly token budget — caps runtime-provided and fallback budgets. Set for smaller context-window models (e.g., 30000 for 32k models)"
|
|
@@ -263,6 +276,10 @@
|
|
|
263
276
|
"fallbackProviders": {
|
|
264
277
|
"label": "Fallback Providers",
|
|
265
278
|
"help": "Explicit runtime LLM fallback provider/model pairs for compaction summarization; entries require plugins.entries.lossless-claw.llm policy"
|
|
279
|
+
},
|
|
280
|
+
"stripInjectedContextTags": {
|
|
281
|
+
"label": "Strip Injected Context Tags",
|
|
282
|
+
"help": "XML tag names whose blocks are stripped from messages before summarization. Covers memory/context plugin prepended blocks (active-memory, memory-lancedb, hindsight-openclaw). Set to [] to disable."
|
|
266
283
|
}
|
|
267
284
|
},
|
|
268
285
|
"configSchema": {
|
|
@@ -406,6 +423,18 @@
|
|
|
406
423
|
"type": "integer",
|
|
407
424
|
"minimum": 1
|
|
408
425
|
},
|
|
426
|
+
"summaryCallWindowMs": {
|
|
427
|
+
"type": "integer",
|
|
428
|
+
"minimum": 1
|
|
429
|
+
},
|
|
430
|
+
"summaryMaxCallsPerWindow": {
|
|
431
|
+
"type": "integer",
|
|
432
|
+
"minimum": 1
|
|
433
|
+
},
|
|
434
|
+
"summarySpendBackoffMs": {
|
|
435
|
+
"type": "integer",
|
|
436
|
+
"minimum": 1
|
|
437
|
+
},
|
|
409
438
|
"maxAssemblyTokenBudget": {
|
|
410
439
|
"type": "integer",
|
|
411
440
|
"minimum": 1000
|
|
@@ -540,6 +569,13 @@
|
|
|
540
569
|
"required": ["provider", "model"],
|
|
541
570
|
"additionalProperties": false
|
|
542
571
|
}
|
|
572
|
+
},
|
|
573
|
+
"stripInjectedContextTags": {
|
|
574
|
+
"description": "XML tag names whose blocks are stripped from messages before summarization. Memory/context plugins prepend tagged blocks via prependContext that should not leak into compacted summaries.",
|
|
575
|
+
"type": "array",
|
|
576
|
+
"items": {
|
|
577
|
+
"type": "string"
|
|
578
|
+
}
|
|
543
579
|
}
|
|
544
580
|
}
|
|
545
581
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@martian-engineering/lossless-claw",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Lossless Context Management plugin for OpenClaw — DAG-based conversation summarization with threshold compaction",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
"scripts": {
|
|
19
19
|
"build": "esbuild index.ts --bundle --platform=node --target=node22 --format=esm --outfile=dist/index.js --external:openclaw --external:\"@earendil-works/*\" --minify-whitespace",
|
|
20
20
|
"changeset": "changeset",
|
|
21
|
-
"
|
|
21
|
+
"plugin-inspector:ci": "npm exec --yes --package @openclaw/plugin-inspector@0.3.11 -- plugin-inspector ci --plugin-root . --out plugin-inspector-reports",
|
|
22
|
+
"release:verify": "npm run typecheck && npm run build && npm test && npm pack --dry-run",
|
|
22
23
|
"test": "vitest run --dir test",
|
|
24
|
+
"typecheck": "tsc --noEmit --pretty false",
|
|
23
25
|
"version-packages": "changeset version"
|
|
24
26
|
},
|
|
25
27
|
"files": [
|
|
@@ -296,7 +296,7 @@ Why it matters:
|
|
|
296
296
|
- `deferred` also stores provider/model/cache telemetry so Anthropic-family sessions can avoid rewriting a still-hot prompt cache
|
|
297
297
|
- `inline` preserves the legacy foreground compaction path for hosts that do not yet support deferred execution
|
|
298
298
|
- `/lossless status` and `/lcm status` surface pending/running/last-failure maintenance state so operators can see when compaction is queued
|
|
299
|
-
- background `maintain()`
|
|
299
|
+
- after-turn background drain and host-approved `maintain()` consume routine threshold debt; `assemble()` only drains pending threshold debt synchronously as an emergency safeguard when the live prompt estimate is already over budget
|
|
300
300
|
|
|
301
301
|
### `autoRotateSessionFiles`
|
|
302
302
|
|
|
@@ -314,6 +314,7 @@ Why it matters:
|
|
|
314
314
|
|
|
315
315
|
- prevents very large OpenClaw session JSONL files from choking fallback/gateway startup while LCM owns the durable context
|
|
316
316
|
- runtime rotation only creates or replaces the rolling `rotate-latest` DB backup when `createBackups` is `true`; manual `/lossless rotate` / `/lcm rotate` always keeps its backup-backed behavior
|
|
317
|
+
- runtime JSONL rewrites run from `afterTurn()` after the host turn completes; `maintain()` skips rotation and leaves it to `afterTurn()` or startup because background maintenance can overlap an embedded model call
|
|
317
318
|
- 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 only when `createBackups` is `true`
|
|
318
319
|
- 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
|
|
319
320
|
- the preserved transcript tail follows the normal rotate behavior controlled by `freshTailCount`
|
|
@@ -468,6 +469,7 @@ Why it matters:
|
|
|
468
469
|
|
|
469
470
|
- keeps low-value automation or noisy sessions out of the DB
|
|
470
471
|
- useful for excluding certain agent lanes or ephemeral traffic entirely
|
|
472
|
+
- cron scheduler keys are already isolated per runtime run, so ignore them only when they should bypass LCM compaction
|
|
471
473
|
|
|
472
474
|
### `statelessSessionPatterns`
|
|
473
475
|
|
|
@@ -622,6 +624,28 @@ Why it matters:
|
|
|
622
624
|
- guards against runaway summaries that are much larger than their target budget
|
|
623
625
|
- useful when summary models are verbose or unstable
|
|
624
626
|
|
|
627
|
+
### `summaryMaxCallsPerWindow`, `summaryCallWindowMs`, and `summarySpendBackoffMs`
|
|
628
|
+
|
|
629
|
+
Bounds model-backed compaction and large-file summarization calls per session.
|
|
630
|
+
|
|
631
|
+
Defaults:
|
|
632
|
+
|
|
633
|
+
- `summaryMaxCallsPerWindow`: `24`
|
|
634
|
+
- `summaryCallWindowMs`: `600000`
|
|
635
|
+
- `summarySpendBackoffMs`: `1800000`
|
|
636
|
+
|
|
637
|
+
Env overrides:
|
|
638
|
+
|
|
639
|
+
- `LCM_SUMMARY_MAX_CALLS_PER_WINDOW`
|
|
640
|
+
- `LCM_SUMMARY_CALL_WINDOW_MS`
|
|
641
|
+
- `LCM_SUMMARY_SPEND_BACKOFF_MS`
|
|
642
|
+
|
|
643
|
+
Why they matter:
|
|
644
|
+
|
|
645
|
+
- prevents non-auth provider failures, ineffective compaction, or repeated deferred debt from spending unbounded summarization calls
|
|
646
|
+
- keeps provider-auth failures on the separate auth circuit breaker path
|
|
647
|
+
- direct deterministic fallbacks remain available when model-backed large-file summaries are throttled
|
|
648
|
+
|
|
625
649
|
### `customInstructions`
|
|
626
650
|
|
|
627
651
|
Natural-language instructions injected into summarization prompts.
|
|
@@ -631,6 +655,25 @@ Why it matters:
|
|
|
631
655
|
- lets operators steer formatting or emphasis without patching code
|
|
632
656
|
- should be used sparingly; low-quality instructions can degrade summary quality system-wide
|
|
633
657
|
|
|
658
|
+
### `stripInjectedContextTags`
|
|
659
|
+
|
|
660
|
+
| | |
|
|
661
|
+
| --- | --- |
|
|
662
|
+
| Type | `string[]` |
|
|
663
|
+
| Default | `["active_memory_plugin", "relevant-memories", "relevant_memories", "hindsight_memories"]` |
|
|
664
|
+
| Env | `LCM_STRIP_INJECTED_CONTEXT_TAGS` (comma-separated) |
|
|
665
|
+
|
|
666
|
+
XML tag names whose blocks are stripped from message content before compaction summarization.
|
|
667
|
+
|
|
668
|
+
Why it matters:
|
|
669
|
+
|
|
670
|
+
- Memory and context plugins (active-memory, memory-lancedb, hindsight-openclaw) prepend XML-tagged blocks to user messages via the `prependContext` hook. These blocks are ephemeral retrieval context — they helped the model on that specific turn but are not part of the actual conversation.
|
|
671
|
+
- Without stripping, the summarizer treats injected memories as real conversation content, permanently corrupting compacted summaries with auto-retrieved context that the user never said.
|
|
672
|
+
- The default list covers well-known OpenClaw memory plugin tags. Add custom tag names if you use plugins that inject context via other tags.
|
|
673
|
+
- Set to `[]` (or empty env string) to disable stripping.
|
|
674
|
+
|
|
675
|
+
Design note: stripping happens at compaction time, not at message ingestion. The raw message stored in the LCM database still contains the original injected blocks, so `lcm_expand` and `lcm_grep` can still surface the full context the model saw on any given turn. Only the summarizer input is cleaned.
|
|
676
|
+
|
|
634
677
|
## Practical operator workflow
|
|
635
678
|
|
|
636
679
|
1. Install and enable the plugin.
|
|
@@ -8,25 +8,28 @@ For stock `lossless-claw` on current main:
|
|
|
8
8
|
|
|
9
9
|
- OpenClaw handles `/new` and `/reset` as session-reset operations.
|
|
10
10
|
- `lossless-claw` handles `/lossless rotate` (`/lcm rotate`) as transcript maintenance on the current conversation.
|
|
11
|
-
- `lossless-claw` does **not** currently register its own `before_reset` hook or a custom reset policy.
|
|
12
11
|
- `lossless-claw` prefers **`sessionKey`** as the stable identity for an LCM conversation.
|
|
13
|
-
-
|
|
12
|
+
- `/reset` archives the active conversation and creates a fresh active row for the same stable `sessionKey`.
|
|
13
|
+
- Cron scheduler keys (`agent:<agent>:cron:<job>...`) are isolated per runtime run when a new `sessionId` reuses the same `sessionKey`.
|
|
14
|
+
- For ordinary non-cron session keys, continuity still follows the stable `sessionKey`.
|
|
14
15
|
|
|
15
16
|
## What that means in practice
|
|
16
17
|
|
|
17
|
-
If a user asks whether `/new` or `/reset` gives them a fresh LCM conversation,
|
|
18
|
+
If a user asks whether `/new` or `/reset` gives them a fresh LCM conversation, distinguish the commands.
|
|
18
19
|
|
|
19
|
-
They get a fresh OpenClaw session runtime, but LCM continuity still follows the stable `sessionKey` when one is available.
|
|
20
|
+
They get a fresh OpenClaw session runtime, but LCM continuity usually still follows the stable `sessionKey` when one is available.
|
|
20
21
|
|
|
21
22
|
So today:
|
|
22
23
|
|
|
23
|
-
- `/new`
|
|
24
|
-
-
|
|
24
|
+
- `/new` prunes active context but keeps the same LCM conversation row
|
|
25
|
+
- `/reset` archives the active LCM conversation row and creates a fresh active row
|
|
26
|
+
- ordinary chat/thread LCM history may continue in the same row across runtime `sessionId` changes when the stable `sessionKey` continues
|
|
27
|
+
- cron scheduler keys create fresh LCM rows per runtime run so prior runs do not enter the new run's assembled context
|
|
25
28
|
- `/lossless rotate` keeps that same conversation row, summaries, and context items in place while compacting only the live transcript backing
|
|
26
29
|
|
|
27
30
|
## Why
|
|
28
31
|
|
|
29
|
-
Current lossless-claw conversation resolution does this:
|
|
32
|
+
Current lossless-claw conversation resolution generally does this:
|
|
30
33
|
|
|
31
34
|
1. look up by `sessionKey` first
|
|
32
35
|
2. fall back to `sessionId` only when no `sessionKey` match exists
|
|
@@ -34,6 +37,8 @@ Current lossless-claw conversation resolution does this:
|
|
|
34
37
|
|
|
35
38
|
That behavior preserves continuity across session resets for the same chat identity.
|
|
36
39
|
|
|
40
|
+
Cron keys are the exception: when an active cron conversation exists for the same `sessionKey` but a different runtime `sessionId`, lossless-claw archives the prior active row and starts a fresh one for the new run. Prior messages remain persisted on the archived conversation.
|
|
41
|
+
|
|
37
42
|
## `/lossless rotate`
|
|
38
43
|
|
|
39
44
|
`/lossless rotate` is distinct from `/new` and `/reset`.
|
|
@@ -49,22 +54,23 @@ This makes rotate the lightweight option when the problem is transcript bloat ra
|
|
|
49
54
|
|
|
50
55
|
## Important limitation
|
|
51
56
|
|
|
52
|
-
There is
|
|
57
|
+
There is a plugin-specific `/new` vs `/reset` split in current lossless-claw behavior.
|
|
53
58
|
|
|
54
59
|
If someone is asking for semantics like:
|
|
55
60
|
|
|
56
61
|
- `/new` gives them a fresh LCM conversation row
|
|
57
|
-
- `/reset` archives old LCM conversation and starts a new one for the same stable `sessionKey`
|
|
58
62
|
|
|
59
|
-
that
|
|
63
|
+
that remains a **design/spec topic**, not current stock behavior.
|
|
60
64
|
|
|
61
65
|
## Safe operator guidance
|
|
62
66
|
|
|
63
67
|
When answering users:
|
|
64
68
|
|
|
65
|
-
- do not promise that `/new`
|
|
69
|
+
- do not promise that `/new` clears LCM history
|
|
70
|
+
- explain that `/reset` archives the active LCM row and starts a fresh one for the same stable `sessionKey`
|
|
66
71
|
- explain that `/lossless rotate` compacts the current transcript without splitting the LCM conversation
|
|
67
|
-
- explain that current stock behavior follows `sessionKey` continuity
|
|
72
|
+
- explain that ordinary current stock behavior follows `sessionKey` continuity
|
|
73
|
+
- explain that cron scheduler session keys are isolated per runtime run while preserving archived prior runs
|
|
68
74
|
- if they need a truly separate LCM history, use a different session key context (for example a different chat/thread/binding) or explicit non-MVP migration/surgery tools
|
|
69
75
|
|
|
70
76
|
## Relation to `/status`
|