@parad0x_labs/openclaw-context-capsule 1.4.0 → 1.6.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 +55 -57
- package/SKILL.md +125 -0
- package/dist/compression.d.ts +67 -0
- package/dist/compression.js +1142 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +290 -0
- package/dist/platform.d.ts +14 -0
- package/dist/platform.js +46 -0
- package/openclaw.plugin.json +17 -0
- package/package.json +23 -11
- package/src/compression.ts +0 -176
- package/src/index.ts +0 -312
package/README.md
CHANGED
|
@@ -1,59 +1,31 @@
|
|
|
1
1
|
# context-capsule — OpenClaw ContextEngine plugin
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
the compression core is vendored inline (`src/compression.ts`) — no external
|
|
7
|
-
runtime dependency, and no network, file-system, or on-chain access. It uses
|
|
8
|
-
only Node's built-in `zlib` and `crypto`.
|
|
9
|
-
|
|
10
|
-
Sessions under 20 messages pass through unchanged. Longer sessions have their
|
|
11
|
-
older history compressed into a capsule summary (injected as a system message)
|
|
12
|
-
while the last 10 messages are kept verbatim — giving the model full coherence
|
|
13
|
-
on recent turns without paying for the full transcript.
|
|
14
|
-
|
|
15
|
-
> **Before you use this skill — read these:**
|
|
16
|
-
>
|
|
17
|
-
> - **All messages are vault-scanned** for secrets and PII on every path (short
|
|
18
|
-
> sessions, verbatim tail, and compressed history alike). Matched values are
|
|
19
|
-
> replaced with typed placeholders. However, the vault scan covers common
|
|
20
|
-
> patterns — it is not a guarantee that all sensitive content is removed.
|
|
21
|
-
> Do not rely on it as the sole protection for highly sensitive sessions.
|
|
22
|
-
>
|
|
23
|
-
> - **Compression alters history fidelity.** Older messages are summarised, not
|
|
24
|
-
> preserved verbatim. Detail, nuance, and exact wording can be lost. Do not
|
|
25
|
-
> use this skill where exact transcript fidelity is required.
|
|
26
|
-
>
|
|
27
|
-
> - **Compressed history is injected as a system message.** This places
|
|
28
|
-
> summarised content in a privileged prompt position. Be aware that prior
|
|
29
|
-
> user/assistant content will influence the model from the system role after
|
|
30
|
-
> compression.
|
|
31
|
-
>
|
|
32
|
-
> - **No external runtime dependency.** The compression core is vendored inline
|
|
33
|
-
> (`src/compression.ts`), so there is nothing external to resolve or verify.
|
|
34
|
-
> The standalone `@parad0x_labs/context-capsule` library on npm is optional and
|
|
35
|
-
> only relevant for non-OpenClaw use.
|
|
36
|
-
|
|
37
|
-
**Most useful for:** local models (Ollama, LM Studio) and GPT-4 where context
|
|
38
|
-
cost matters. Claude users with a 200k context window and built-in compaction
|
|
39
|
-
enabled may not need this.
|
|
40
|
-
|
|
41
|
-
## Benchmark
|
|
42
|
-
|
|
43
|
-
| Metric | Result | CI gate |
|
|
44
|
-
|---|---|---|
|
|
45
|
-
| Token savings | 99.3% | >= 95% |
|
|
46
|
-
| Recovery score | 100% | >= 90% |
|
|
47
|
-
| Runtime | 29ms | < 1000ms |
|
|
48
|
-
|
|
49
|
-
Reproduce locally:
|
|
3
|
+
Self-contained OpenClaw context engine that reduces prompt tokens in long agent
|
|
4
|
+
sessions. It keeps the recent tail verbatim and converts older history into a
|
|
5
|
+
bounded, model-readable extractive capsule.
|
|
50
6
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
7
|
+
The capsule preserves high-value older context:
|
|
8
|
+
|
|
9
|
+
- decisions and constraints
|
|
10
|
+
- open tasks and requested work
|
|
11
|
+
- errors and failed attempts
|
|
12
|
+
- files, commands, and links
|
|
13
|
+
- open questions and durable facts
|
|
14
|
+
|
|
15
|
+
It also keeps a zlib-compressed payload and Merkle root for auditability, but the
|
|
16
|
+
LLM is given the extractive capsule, not opaque compressed bytes.
|
|
55
17
|
|
|
56
|
-
|
|
18
|
+
## Safety and limits
|
|
19
|
+
|
|
20
|
+
- **Lossy by design.** Older messages are not preserved verbatim in the model
|
|
21
|
+
prompt. Exact wording, nuance, and low-priority details can be lost.
|
|
22
|
+
- **Recent context remains verbatim.** `keepRecentMessages` controls how many
|
|
23
|
+
latest messages stay untouched.
|
|
24
|
+
- **Best-effort vault scan.** Text content is scanned for common secrets and PII
|
|
25
|
+
before compression or model injection. This is useful defense-in-depth, not a
|
|
26
|
+
formal guarantee.
|
|
27
|
+
- **No external runtime dependency.** The plugin uses only Node built-ins
|
|
28
|
+
(`zlib` and `crypto`) and makes no network, file-system, or on-chain calls.
|
|
57
29
|
|
|
58
30
|
## Activation
|
|
59
31
|
|
|
@@ -71,19 +43,45 @@ CI fails if savings drop below 95% or recovery falls below 90%.
|
|
|
71
43
|
## Config options
|
|
72
44
|
|
|
73
45
|
| Key | Default | Description |
|
|
74
|
-
|
|
75
|
-
| `minMessages` | `20` | Sessions shorter than this pass through unchanged |
|
|
76
|
-
| `keepRecentMessages` | `10` | Recent messages kept verbatim after compression |
|
|
46
|
+
| --- | ---: | --- |
|
|
47
|
+
| `minMessages` | `20` | Sessions shorter than this pass through unchanged. |
|
|
48
|
+
| `keepRecentMessages` | `10` | Recent messages kept verbatim after compression. |
|
|
49
|
+
| `maxCapsuleTokens` | `700` | Hard cap for the injected extractive capsule. |
|
|
50
|
+
| `capsuleTokenRatio` | `0.08` | If OpenClaw provides a model token budget, cap the capsule to this fraction of the budget. |
|
|
51
|
+
| `minCompressTokens` | `900` | Estimated transcript-token floor before compression activates. |
|
|
77
52
|
|
|
78
53
|
```jsonc
|
|
79
54
|
{
|
|
80
55
|
"plugins": {
|
|
81
56
|
"entries": {
|
|
82
57
|
"context-capsule": {
|
|
83
|
-
"minMessages":
|
|
84
|
-
"keepRecentMessages":
|
|
58
|
+
"minMessages": 20,
|
|
59
|
+
"keepRecentMessages": 10,
|
|
60
|
+
"maxCapsuleTokens": 700,
|
|
61
|
+
"capsuleTokenRatio": 0.08,
|
|
62
|
+
"minCompressTokens": 900
|
|
85
63
|
}
|
|
86
64
|
}
|
|
87
65
|
}
|
|
88
66
|
}
|
|
89
67
|
```
|
|
68
|
+
|
|
69
|
+
## Packaging
|
|
70
|
+
|
|
71
|
+
The npm/ClawHub package ships compiled `dist/` JavaScript. It does not require
|
|
72
|
+
TypeScript support from the host runtime.
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
npm run typecheck
|
|
76
|
+
npm test
|
|
77
|
+
npm pack --dry-run
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## When to use
|
|
81
|
+
|
|
82
|
+
Use this for long-running local or hosted model sessions where resending the full
|
|
83
|
+
conversation is too expensive or pushes the model toward context overflow.
|
|
84
|
+
|
|
85
|
+
Do not use it for workflows where old transcript wording must remain exact. For
|
|
86
|
+
that, keep normal OpenClaw history or use a retrieval system that can quote the
|
|
87
|
+
original source.
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: context-capsule
|
|
3
|
+
description: Compresses older OpenClaw agent session history into a bounded, lane-change-aware context capsule — keeps recent messages verbatim, flags abandoned directions, quarantines injected instructions, and redacts secrets. Local, deterministic, any model.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Context Capsule
|
|
7
|
+
|
|
8
|
+
Compress older agent session history before it hits the LLM, so long chats stop
|
|
9
|
+
re-sending the full transcript every turn. It keeps the recent tail verbatim and
|
|
10
|
+
turns older history into a bounded extractive capsule with decisions, tasks,
|
|
11
|
+
errors, paths, links, questions, and durable facts. Works with any model —
|
|
12
|
+
Claude, GPT, Ollama, Mistral, LM Studio.
|
|
13
|
+
|
|
14
|
+
**What sets it apart:**
|
|
15
|
+
|
|
16
|
+
- **Lane-change aware.** When the session pivots ("replace X with Y", "forget X,
|
|
17
|
+
use Y instead"), the capsule marks the abandoned direction as superseded and
|
|
18
|
+
keeps the live one — so the model never wanders back into a dropped plan. On a
|
|
19
|
+
held-out pivot set it cleans 83% of abandoned subjects with **zero** wrongly
|
|
20
|
+
flagged live choices.
|
|
21
|
+
- **High fidelity per token.** Distinctive signals — file paths, IDs, ports,
|
|
22
|
+
URLs, commands, errors, decisions — are emitted as dense atoms, so the capsule
|
|
23
|
+
keeps **79% of key signals at ~5× reduction and 93% at ~3.4×** on real
|
|
24
|
+
sessions (measured, see `test/fidelity-bench.mjs`).
|
|
25
|
+
|
|
26
|
+
> **Self-contained (v1.6.0):** The compression core is bundled directly in this
|
|
27
|
+
> skill (`src/compression.ts`). There is **no external runtime dependency**, and
|
|
28
|
+
> the plugin makes **no network, file-system, or on-chain calls**. Everything
|
|
29
|
+
> runs locally using only Node's built-in `zlib` and `crypto`, and is fully
|
|
30
|
+
> deterministic. Capsules carry a `schema` tag (`context-capsule.v2`).
|
|
31
|
+
|
|
32
|
+
> **Protections (defense-in-depth, all CI-gated by `npm test`):**
|
|
33
|
+
> - **Secret redaction (every surface).** API keys (OpenAI, Anthropic, AWS,
|
|
34
|
+
> Google, GitHub classic + fine-grained, GitLab, npm, Slack, Stripe, SendGrid,
|
|
35
|
+
> Twilio), JWTs, PEM blocks, URL basic-auth, `DATABASE_URL=` DSNs, and
|
|
36
|
+
> `key=value` credentials are detected by prefix/shape/context — never by raw
|
|
37
|
+
> entropy, so public IDs (git SHAs, UUIDs, chain addresses) are untouched.
|
|
38
|
+
> Redaction runs **before compression**, so no secret survives even in the zlib
|
|
39
|
+
> audit blob, and again on output — the core never emits a secret even if called
|
|
40
|
+
> directly. Each redaction carries a one-way **SHA-256 fingerprint**
|
|
41
|
+
> (`[REDACTED_AWS_KEY#a1b2c3d4]`) so the same key is correlatable across turns
|
|
42
|
+
> without ever exposing its value. Best-effort pattern matching — strong, not a
|
|
43
|
+
> guarantee for the most sensitive chats.
|
|
44
|
+
> - **Injection quarantine** — instruction-injection patterns in older history
|
|
45
|
+
> ("ignore previous instructions", "you are now…", "reveal your prompt") are
|
|
46
|
+
> wrapped as inert untrusted text, never surfaced as a live instruction.
|
|
47
|
+
> - **Bounded work** — every extraction pass runs on size-capped input, so a
|
|
48
|
+
> megabyte message or an adversarial string finishes in milliseconds instead of
|
|
49
|
+
> hanging the turn.
|
|
50
|
+
|
|
51
|
+
## When to use
|
|
52
|
+
|
|
53
|
+
- Long-running agent sessions (default: more than 20 messages) where the
|
|
54
|
+
transcript is large and you want to cut per-call token cost.
|
|
55
|
+
- Any model/provider — local or hosted.
|
|
56
|
+
|
|
57
|
+
## When NOT to use
|
|
58
|
+
|
|
59
|
+
- Sessions that require **exact, verbatim transcript fidelity**. Older history is
|
|
60
|
+
summarized into a compact capsule; detail and nuance can be lost. Only the most
|
|
61
|
+
recent 10 messages are kept verbatim.
|
|
62
|
+
- As your only safeguard for secrets/PII. The vault scan is best-effort, and the
|
|
63
|
+
compressed history is injected into the **system** context position.
|
|
64
|
+
|
|
65
|
+
## How it works
|
|
66
|
+
|
|
67
|
+
Keeps the last 10 messages verbatim by default. Older history is zlib-compressed
|
|
68
|
+
for auditability, then converted into a model-readable extractive capsule. The
|
|
69
|
+
model sees compact sections for decisions/constraints, tasks, errors, files,
|
|
70
|
+
commands, links, questions, and durable facts. The capsule is capped by
|
|
71
|
+
`maxCapsuleTokens` and adapts to the host token budget with
|
|
72
|
+
`capsuleTokenRatio`.
|
|
73
|
+
|
|
74
|
+
## Savings
|
|
75
|
+
|
|
76
|
+
| | Without | With |
|
|
77
|
+
| --------------------- | ------- | -------- |
|
|
78
|
+
| Prompt history sent | Full transcript | Capsule + recent tail |
|
|
79
|
+
| Compression trigger | N/A | Message + token threshold |
|
|
80
|
+
| Runtime dependencies | N/A | Node built-ins only |
|
|
81
|
+
|
|
82
|
+
## Install
|
|
83
|
+
|
|
84
|
+
This skill is self-contained — no extra packages to install. Register it as your
|
|
85
|
+
context engine in `openclaw.json`:
|
|
86
|
+
|
|
87
|
+
```jsonc
|
|
88
|
+
{
|
|
89
|
+
"plugins": {
|
|
90
|
+
"slots": { "contextEngine": "context-capsule" }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Optional config (defaults shown):
|
|
96
|
+
|
|
97
|
+
```jsonc
|
|
98
|
+
{
|
|
99
|
+
"plugins": {
|
|
100
|
+
"entries": {
|
|
101
|
+
"context-capsule": {
|
|
102
|
+
"minMessages": 20,
|
|
103
|
+
"keepRecentMessages": 10,
|
|
104
|
+
"maxCapsuleTokens": 1400,
|
|
105
|
+
"capsuleTokenRatio": 0.14,
|
|
106
|
+
"minCompressTokens": 900
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Source
|
|
114
|
+
|
|
115
|
+
github.com/Parad0x-Labs/openclaw-skills/tree/main/skills/context-capsule
|
|
116
|
+
|
|
117
|
+
The standalone library (`@parad0x_labs/context-capsule`) is published separately
|
|
118
|
+
on npm for non-OpenClaw use; this skill vendors only the two pure functions it
|
|
119
|
+
needs and does not depend on it at runtime.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
💜 If Context Capsule is quietly shrinking your token bill, a ⭐ on ClawHub helps
|
|
124
|
+
other agent builders find it.
|
|
125
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-contained compression core for the Context Capsule skill.
|
|
3
|
+
*
|
|
4
|
+
* The model cannot use opaque zlib bytes directly, so this module stores the
|
|
5
|
+
* compressed payload for auditability but injects a bounded extractive capsule:
|
|
6
|
+
* decisions, tasks, errors, paths, URLs, questions, and durable facts selected
|
|
7
|
+
* from older history. This is still lossy, but it preserves the material that
|
|
8
|
+
* usually matters in long agent sessions while keeping prompt tokens bounded.
|
|
9
|
+
*
|
|
10
|
+
* Crypto/compression run through a platform shim (./platform): the Node build
|
|
11
|
+
* uses `node:zlib` + `node:crypto`; a browser build aliases it to
|
|
12
|
+
* ./platform.browser (@noble/hashes + pako) so this exact source also runs in a
|
|
13
|
+
* browser tab. The SHA-256 path is byte-identical across backends, so a capsule's
|
|
14
|
+
* merkleRoot / capsuleId / injected memory are identical in a browser and in Node
|
|
15
|
+
* (the audit blob is round-trip-identical) — see test/platform-parity.test.mjs.
|
|
16
|
+
* No network, file I/O, or dynamic imports.
|
|
17
|
+
*/
|
|
18
|
+
export interface Message {
|
|
19
|
+
role: string;
|
|
20
|
+
content: string;
|
|
21
|
+
}
|
|
22
|
+
export type CapsuleFactKind = "decision" | "task" | "error" | "file" | "question" | "fact";
|
|
23
|
+
export interface CapsuleFact {
|
|
24
|
+
kind: CapsuleFactKind;
|
|
25
|
+
text: string;
|
|
26
|
+
role: string;
|
|
27
|
+
sourceIndex: number;
|
|
28
|
+
score: number;
|
|
29
|
+
}
|
|
30
|
+
/** A compressed, auditable snapshot of an agent session's message history. */
|
|
31
|
+
export interface ContextCapsule {
|
|
32
|
+
/** Schema/version tag for forward-compatibility (e.g. "context-capsule.v2"). */
|
|
33
|
+
schema: string;
|
|
34
|
+
sessionId: string;
|
|
35
|
+
capsuleId: string;
|
|
36
|
+
originalTokenEstimate: number;
|
|
37
|
+
compressedBytes: number;
|
|
38
|
+
compressionRatio: string;
|
|
39
|
+
topics: string[];
|
|
40
|
+
facts: CapsuleFact[];
|
|
41
|
+
/** Subjects a later turn abandoned/replaced; surfaced as superseded. */
|
|
42
|
+
superseded: string[];
|
|
43
|
+
droppedFactCount: number;
|
|
44
|
+
maxOutputTokens: number;
|
|
45
|
+
merkleRoot: string;
|
|
46
|
+
createdAt: number;
|
|
47
|
+
compressedBase64: string;
|
|
48
|
+
}
|
|
49
|
+
export interface CompressOptions {
|
|
50
|
+
sessionId?: string;
|
|
51
|
+
maxOutputTokens?: number;
|
|
52
|
+
maxFacts?: number;
|
|
53
|
+
}
|
|
54
|
+
export interface InjectOptions {
|
|
55
|
+
maxOutputTokens?: number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Compress a session's message history into a ContextCapsule.
|
|
59
|
+
* Pure function — extractive capsule + zlib deflate + SHA-256 only, no I/O.
|
|
60
|
+
*/
|
|
61
|
+
export declare function compressContext(messages: Message[], opts?: CompressOptions): ContextCapsule;
|
|
62
|
+
/**
|
|
63
|
+
* Generate a bounded injection string that replaces full older history in an
|
|
64
|
+
* LLM call. The output intentionally contains useful extracted facts, not the
|
|
65
|
+
* opaque compressed payload.
|
|
66
|
+
*/
|
|
67
|
+
export declare function injectCapsule(capsule: ContextCapsule, opts?: InjectOptions): string;
|