@martian-engineering/lossless-claw 0.2.8 → 0.4.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 +151 -4
- package/docs/configuration.md +69 -0
- package/index.ts +2 -1136
- package/openclaw.plugin.json +43 -2
- package/package.json +11 -4
- package/src/assembler.ts +128 -13
- package/src/compaction.ts +60 -8
- package/src/db/config.ts +62 -0
- package/src/db/connection.ts +95 -46
- package/src/db/migration.ts +7 -0
- package/src/engine.ts +696 -198
- package/src/expansion-auth.ts +14 -0
- package/src/plugin/index.ts +1375 -0
- package/src/retrieval.ts +5 -1
- package/src/session-patterns.ts +23 -0
- package/src/startup-banner-log.ts +48 -0
- package/src/store/conversation-store.ts +87 -9
- package/src/store/summary-store.ts +17 -2
- package/src/summarize.ts +104 -20
- package/src/tools/lcm-conversation-scope.ts +55 -4
- package/src/tools/lcm-describe-tool.ts +19 -7
- package/src/tools/lcm-expand-query-tool.ts +4 -0
- package/src/tools/lcm-expand-tool.delegation.ts +27 -3
- package/src/tools/lcm-grep-tool.ts +20 -4
- package/src/types.ts +2 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# lossless-claw
|
|
2
2
|
|
|
3
|
-
Lossless Context Management plugin for [OpenClaw](https://github.com/openclaw/openclaw), based on the [LCM paper](https://papers.voltropy.com/LCM). Replaces OpenClaw's built-in sliding-window compaction with a DAG-based summarization system that preserves every message while keeping active context within model token limits.
|
|
3
|
+
Lossless Context Management plugin for [OpenClaw](https://github.com/openclaw/openclaw), based on the [LCM paper](https://papers.voltropy.com/LCM) from [Voltropy](https://x.com/Voltropy). Replaces OpenClaw's built-in sliding-window compaction with a DAG-based summarization system that preserves every message while keeping active context within model token limits.
|
|
4
4
|
|
|
5
5
|
## Table of contents
|
|
6
6
|
|
|
@@ -94,7 +94,12 @@ Add a `lossless-claw` entry under `plugins.entries` in your OpenClaw config:
|
|
|
94
94
|
"config": {
|
|
95
95
|
"freshTailCount": 32,
|
|
96
96
|
"contextThreshold": 0.75,
|
|
97
|
-
"incrementalMaxDepth": -1
|
|
97
|
+
"incrementalMaxDepth": -1,
|
|
98
|
+
"ignoreSessionPatterns": [
|
|
99
|
+
"agent:*:cron:**"
|
|
100
|
+
],
|
|
101
|
+
"summaryProvider": "anthropic",
|
|
102
|
+
"summaryModel": "claude-3-5-haiku"
|
|
98
103
|
}
|
|
99
104
|
}
|
|
100
105
|
}
|
|
@@ -102,12 +107,17 @@ Add a `lossless-claw` entry under `plugins.entries` in your OpenClaw config:
|
|
|
102
107
|
}
|
|
103
108
|
```
|
|
104
109
|
|
|
110
|
+
`summaryModel` and `summaryProvider` let you pin compaction summarization to a cheaper or faster model than your main OpenClaw session model. When unset, LCM uses OpenClaw's configured default model/provider.
|
|
111
|
+
|
|
105
112
|
### Environment variables
|
|
106
113
|
|
|
107
114
|
| Variable | Default | Description |
|
|
108
115
|
|----------|---------|-------------|
|
|
109
116
|
| `LCM_ENABLED` | `true` | Enable/disable the plugin |
|
|
110
117
|
| `LCM_DATABASE_PATH` | `~/.openclaw/lcm.db` | Path to the SQLite database |
|
|
118
|
+
| `LCM_IGNORE_SESSION_PATTERNS` | `""` | Comma-separated glob patterns for session keys to exclude from LCM storage |
|
|
119
|
+
| `LCM_STATELESS_SESSION_PATTERNS` | `""` | Comma-separated glob patterns for session keys that may read from LCM but never write to it |
|
|
120
|
+
| `LCM_SKIP_STATELESS_SESSIONS` | `true` | Enable stateless-session write skipping for matching session keys |
|
|
111
121
|
| `LCM_CONTEXT_THRESHOLD` | `0.75` | Fraction of context window that triggers compaction (0.0–1.0) |
|
|
112
122
|
| `LCM_FRESH_TAIL_COUNT` | `32` | Number of recent messages protected from compaction |
|
|
113
123
|
| `LCM_LEAF_MIN_FANOUT` | `8` | Minimum raw messages per leaf summary |
|
|
@@ -121,11 +131,67 @@ Add a `lossless-claw` entry under `plugins.entries` in your OpenClaw config:
|
|
|
121
131
|
| `LCM_LARGE_FILE_TOKEN_THRESHOLD` | `25000` | File blocks above this size are intercepted and stored separately |
|
|
122
132
|
| `LCM_LARGE_FILE_SUMMARY_PROVIDER` | `""` | Provider override for large-file summarization |
|
|
123
133
|
| `LCM_LARGE_FILE_SUMMARY_MODEL` | `""` | Model override for large-file summarization |
|
|
124
|
-
| `LCM_SUMMARY_MODEL` |
|
|
125
|
-
| `LCM_SUMMARY_PROVIDER` |
|
|
134
|
+
| `LCM_SUMMARY_MODEL` | `""` | Model override for compaction summarization; falls back to OpenClaw's default model when unset |
|
|
135
|
+
| `LCM_SUMMARY_PROVIDER` | `""` | Provider override for compaction summarization; falls back to `OPENCLAW_PROVIDER` or the provider embedded in the model ref |
|
|
136
|
+
| `LCM_EXPANSION_MODEL` | *(from OpenClaw)* | Model override for `lcm_expand_query` sub-agent (e.g. `anthropic/claude-haiku-4-5`) |
|
|
137
|
+
| `LCM_EXPANSION_PROVIDER` | *(from OpenClaw)* | Provider override for `lcm_expand_query` sub-agent |
|
|
126
138
|
| `LCM_AUTOCOMPACT_DISABLED` | `false` | Disable automatic compaction after turns |
|
|
127
139
|
| `LCM_PRUNE_HEARTBEAT_OK` | `false` | Retroactively delete `HEARTBEAT_OK` turn cycles from LCM storage |
|
|
128
140
|
|
|
141
|
+
### Expansion model override requirements
|
|
142
|
+
|
|
143
|
+
If you want `lcm_expand_query` to run on a dedicated model via `expansionModel` or `LCM_EXPANSION_MODEL`, OpenClaw must explicitly trust the plugin to request sub-agent model overrides.
|
|
144
|
+
|
|
145
|
+
Add a `subagent` policy under `plugins.entries.lossless-claw` and allowlist the canonical `provider/model` target you want the plugin to use:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"models": {
|
|
150
|
+
"openai/gpt-4.1-mini": {}
|
|
151
|
+
},
|
|
152
|
+
"plugins": {
|
|
153
|
+
"entries": {
|
|
154
|
+
"lossless-claw": {
|
|
155
|
+
"enabled": true,
|
|
156
|
+
"subagent": {
|
|
157
|
+
"allowModelOverride": true,
|
|
158
|
+
"allowedModels": ["openai/gpt-4.1-mini"]
|
|
159
|
+
},
|
|
160
|
+
"config": {
|
|
161
|
+
"expansionModel": "openai/gpt-4.1-mini"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
- `subagent.allowModelOverride` is required for OpenClaw to honor plugin-requested per-run `provider`/`model` overrides.
|
|
170
|
+
- `subagent.allowedModels` is optional but recommended. Use `"*"` only if you intentionally want to trust any target model.
|
|
171
|
+
- The chosen expansion target must also be available in OpenClaw's normal model catalog. If it is not already configured elsewhere, add it under the top-level `models` map as shown above.
|
|
172
|
+
- If you prefer splitting provider and model, set `config.expansionProvider` and use a bare `config.expansionModel`.
|
|
173
|
+
|
|
174
|
+
Plugin config equivalents:
|
|
175
|
+
|
|
176
|
+
- `ignoreSessionPatterns`
|
|
177
|
+
- `statelessSessionPatterns`
|
|
178
|
+
- `skipStatelessSessions`
|
|
179
|
+
- `summaryModel`
|
|
180
|
+
- `summaryProvider`
|
|
181
|
+
|
|
182
|
+
Environment variables still win over plugin config when both are set.
|
|
183
|
+
|
|
184
|
+
### Summary model priority
|
|
185
|
+
|
|
186
|
+
For compaction summarization, lossless-claw resolves the model in this order:
|
|
187
|
+
|
|
188
|
+
1. `LCM_SUMMARY_MODEL` / `LCM_SUMMARY_PROVIDER`
|
|
189
|
+
2. Plugin config `summaryModel` / `summaryProvider`
|
|
190
|
+
3. OpenClaw's default compaction model/provider
|
|
191
|
+
4. Legacy per-call model/provider hints
|
|
192
|
+
|
|
193
|
+
If `summaryModel` already includes a provider prefix such as `anthropic/claude-sonnet-4-20250514`, `summaryProvider` is ignored for that choice. Otherwise, the provider falls back to the matching override, then `OPENCLAW_PROVIDER`, then the provider inferred by the caller.
|
|
194
|
+
|
|
129
195
|
### Recommended starting configuration
|
|
130
196
|
|
|
131
197
|
```
|
|
@@ -138,6 +204,87 @@ LCM_CONTEXT_THRESHOLD=0.75
|
|
|
138
204
|
- **incrementalMaxDepth=-1** enables unlimited automatic condensation after each compaction pass — the DAG cascades as deep as needed. Set to `0` (default) for leaf-only, or a positive integer for a specific depth cap.
|
|
139
205
|
- **contextThreshold=0.75** triggers compaction when context reaches 75% of the model's window, leaving headroom for the model's response.
|
|
140
206
|
|
|
207
|
+
### Session exclusion patterns
|
|
208
|
+
|
|
209
|
+
Use `ignoreSessionPatterns` or `LCM_IGNORE_SESSION_PATTERNS` to keep low-value sessions completely out of LCM. Matching sessions do not create conversations, do not store messages, and do not participate in compaction or delegated expansion grants.
|
|
210
|
+
|
|
211
|
+
Pattern rules:
|
|
212
|
+
|
|
213
|
+
- `*` matches any characters except `:`
|
|
214
|
+
- `**` matches anything, including `:`
|
|
215
|
+
- Patterns match the full session key
|
|
216
|
+
|
|
217
|
+
Examples:
|
|
218
|
+
|
|
219
|
+
- `agent:*:cron:**` excludes cron sessions for any agent, including isolated run sessions like `agent:main:cron:daily-digest:run:run-123`
|
|
220
|
+
- `agent:main:subagent:**` excludes all main-agent subagent sessions
|
|
221
|
+
- `agent:ops:**` excludes every session under the `ops` agent id
|
|
222
|
+
|
|
223
|
+
Environment variable example:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
LCM_IGNORE_SESSION_PATTERNS=agent:*:cron:**,agent:main:subagent:**
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Plugin config example:
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"plugins": {
|
|
234
|
+
"entries": {
|
|
235
|
+
"lossless-claw": {
|
|
236
|
+
"config": {
|
|
237
|
+
"ignoreSessionPatterns": [
|
|
238
|
+
"agent:*:cron:**",
|
|
239
|
+
"agent:main:subagent:**"
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Stateless session patterns
|
|
249
|
+
|
|
250
|
+
Use `statelessSessionPatterns` or `LCM_STATELESS_SESSION_PATTERNS` for sessions that should still be able to read from existing LCM context, but should never create or mutate LCM state themselves. This is useful for delegated or temporary sub-agent sessions that should benefit from retained context without polluting the database.
|
|
251
|
+
|
|
252
|
+
When `skipStatelessSessions` or `LCM_SKIP_STATELESS_SESSIONS` is enabled, matching sessions:
|
|
253
|
+
|
|
254
|
+
- skip bootstrap imports
|
|
255
|
+
- skip message persistence during ingest and after-turn hooks
|
|
256
|
+
- skip compaction writes and delegated expansion grant writes
|
|
257
|
+
- can still assemble context from already-persisted conversations when a matching conversation exists
|
|
258
|
+
|
|
259
|
+
Pattern rules are the same as `ignoreSessionPatterns`, and matching is done against the full session key.
|
|
260
|
+
|
|
261
|
+
Environment variable example:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
LCM_STATELESS_SESSION_PATTERNS=agent:*:subagent:**,agent:ops:subagent:**
|
|
265
|
+
LCM_SKIP_STATELESS_SESSIONS=true
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Plugin config example:
|
|
269
|
+
|
|
270
|
+
```json
|
|
271
|
+
{
|
|
272
|
+
"plugins": {
|
|
273
|
+
"entries": {
|
|
274
|
+
"lossless-claw": {
|
|
275
|
+
"config": {
|
|
276
|
+
"statelessSessionPatterns": [
|
|
277
|
+
"agent:*:subagent:**",
|
|
278
|
+
"agent:ops:subagent:**"
|
|
279
|
+
],
|
|
280
|
+
"skipStatelessSessions": true
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
141
288
|
### OpenClaw session reset settings
|
|
142
289
|
|
|
143
290
|
LCM preserves history through compaction, but it does **not** change OpenClaw's core session reset policy. If sessions are resetting sooner than you want, increase OpenClaw's `session.reset.idleMinutes` or use a channel/type-specific override.
|
package/docs/configuration.md
CHANGED
|
@@ -103,6 +103,75 @@ export LCM_SUMMARY_PROVIDER=anthropic
|
|
|
103
103
|
|
|
104
104
|
Using a cheaper/faster model for summarization can reduce costs, but quality matters — poor summaries compound as they're condensed into higher-level nodes.
|
|
105
105
|
|
|
106
|
+
When more than one source is present, compaction summarization resolves in this order:
|
|
107
|
+
|
|
108
|
+
1. `LCM_SUMMARY_MODEL` / `LCM_SUMMARY_PROVIDER`
|
|
109
|
+
2. Plugin config `summaryModel` / `summaryProvider`
|
|
110
|
+
3. OpenClaw's default compaction model/provider
|
|
111
|
+
4. Legacy per-call model/provider hints
|
|
112
|
+
|
|
113
|
+
If `summaryModel` already includes a provider prefix such as `anthropic/claude-sonnet-4-20250514`, `summaryProvider` is ignored for that choice.
|
|
114
|
+
|
|
115
|
+
## Session controls
|
|
116
|
+
|
|
117
|
+
### Excluding sessions entirely
|
|
118
|
+
|
|
119
|
+
Use `ignoreSessionPatterns` or `LCM_IGNORE_SESSION_PATTERNS` to keep low-value sessions completely out of LCM. Matching sessions do not create conversations, do not store messages, and do not participate in compaction or delegated expansion grants.
|
|
120
|
+
|
|
121
|
+
- Matching uses the full session key.
|
|
122
|
+
- `*` matches any characters except `:`.
|
|
123
|
+
- `**` matches anything, including `:`.
|
|
124
|
+
|
|
125
|
+
Example:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
export LCM_IGNORE_SESSION_PATTERNS=agent:*:cron:**,agent:main:subagent:**
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Stateless sessions
|
|
132
|
+
|
|
133
|
+
Use `statelessSessionPatterns` or `LCM_STATELESS_SESSION_PATTERNS` for sessions that should be able to read from LCM without writing to it. This is especially useful for sub-agent sessions, which use real OpenClaw keys like `agent:<agentId>:subagent:<uuid>`.
|
|
134
|
+
|
|
135
|
+
Enable enforcement with `skipStatelessSessions` or `LCM_SKIP_STATELESS_SESSIONS=true`.
|
|
136
|
+
|
|
137
|
+
When a session key matches a stateless pattern and enforcement is enabled, LCM will:
|
|
138
|
+
|
|
139
|
+
- skip bootstrap imports
|
|
140
|
+
- skip ingest and after-turn persistence
|
|
141
|
+
- skip compaction writes
|
|
142
|
+
- skip delegated expansion grant writes
|
|
143
|
+
- still allow read-side assembly from existing persisted context
|
|
144
|
+
|
|
145
|
+
Example:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
export LCM_STATELESS_SESSION_PATTERNS=agent:*:subagent:**,agent:ops:subagent:**
|
|
149
|
+
export LCM_SKIP_STATELESS_SESSIONS=true
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Plugin config example:
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"plugins": {
|
|
157
|
+
"entries": {
|
|
158
|
+
"lossless-claw": {
|
|
159
|
+
"config": {
|
|
160
|
+
"ignoreSessionPatterns": [
|
|
161
|
+
"agent:*:cron:**"
|
|
162
|
+
],
|
|
163
|
+
"statelessSessionPatterns": [
|
|
164
|
+
"agent:*:subagent:**",
|
|
165
|
+
"agent:ops:subagent:**"
|
|
166
|
+
],
|
|
167
|
+
"skipStatelessSessions": true
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
106
175
|
## TUI conversation window size
|
|
107
176
|
|
|
108
177
|
`LCM_TUI_CONVERSATION_WINDOW_SIZE` (default `200`) controls how many messages `lcm-tui` loads per keyset-paged conversation window when a session has an LCM `conversation_id`.
|