anolisa-tokenless 0.7.14 → 0.8.1

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 (32) hide show
  1. package/README.md +226 -79
  2. package/adapters/tokenless/claude-code/.claude-plugin/plugin.json +1 -1
  3. package/adapters/tokenless/claude-code/hooks/run-hook.sh +62 -0
  4. package/adapters/tokenless/claude-code/scripts/detect.sh +50 -7
  5. package/adapters/tokenless/codex/.codex-plugin/plugin.json +1 -1
  6. package/adapters/tokenless/common/cosh-extension.json +4 -4
  7. package/adapters/tokenless/common/hooks/compress_response_hook.py +180 -96
  8. package/adapters/tokenless/common/hooks/compress_schema_hook.py +19 -31
  9. package/adapters/tokenless/common/hooks/hook_utils.py +240 -70
  10. package/adapters/tokenless/common/hooks/rewrite_hook.py +53 -169
  11. package/adapters/tokenless/dsh/dist/index.js +353 -264
  12. package/adapters/tokenless/dsh/package.json +2 -2
  13. package/adapters/tokenless/hermes/__init__.py +338 -363
  14. package/adapters/tokenless/hermes/plugin.yaml +2 -2
  15. package/adapters/tokenless/manifest.json +17 -1
  16. package/adapters/tokenless/openclaw/dist/index.d.ts +4 -16
  17. package/adapters/tokenless/openclaw/dist/index.js +291 -507
  18. package/adapters/tokenless/openclaw/index.ts +408 -628
  19. package/adapters/tokenless/openclaw/openclaw.plugin.json +4 -20
  20. package/adapters/tokenless/openclaw/package.json +6 -4
  21. package/adapters/tokenless/openclaw/scripts/install.sh +51 -12
  22. package/adapters/tokenless/qoder/.qoder-plugin/plugin.json +1 -1
  23. package/adapters/tokenless/qwencode/hooks/run-hook.sh +62 -0
  24. package/adapters/tokenless/qwencode/qwen-extension.json +4 -4
  25. package/adapters/tokenless/qwenpaw/plugin.json +17 -0
  26. package/adapters/tokenless/qwenpaw/plugin.py +390 -0
  27. package/adapters/tokenless/qwenpaw/requirements.txt +6 -0
  28. package/adapters/tokenless/qwenpaw/scripts/detect.sh +131 -0
  29. package/adapters/tokenless/qwenpaw/scripts/install.sh +98 -0
  30. package/adapters/tokenless/qwenpaw/scripts/uninstall.sh +61 -0
  31. package/package.json +5 -5
  32. package/adapters/tokenless/common/hooks/compress_toon_hook.py +0 -174
package/README.md CHANGED
@@ -2,52 +2,59 @@
2
2
 
3
3
  [中文版](README_zh.md)
4
4
 
5
- **LLM token optimization toolkit** — schema/response compression + command rewriting + tool environment readiness.
5
+ **LLM token optimization toolkit** — content-aware compression + command rewriting + diagnostics.
6
6
 
7
7
  Token-Less combines complementary strategies to minimize LLM token consumption:
8
8
 
9
- - **Schema & Response Compression** — Compresses OpenAI Function Calling tool definitions and API responses via the `tokenless-schema` library, cutting structural overhead before tokens ever reach the context window.
9
+ - **Lifecycle-aware Compression** — Protocol v2 owns BeforeModel schema handling, PreTool RTK rewriting, PostTool routing, and authorized Retrieve; the PostTool Pipeline compresses JSON, CSV/TSV tables, and recognized build/test command logs.
10
10
  - **TOON Context Compression** — Encodes JSON responses to TOON (Token-Oriented Object Notation) format via the `toon-format` library linked into `tokenless`, reducing syntax overhead for suitable structured data.
11
11
  - **Command Rewriting** — Integrates [RTK](https://github.com/rtk-ai/rtk) to filter and rewrite CLI command output, eliminating noise that would otherwise waste 60–90% of tokens.
12
12
  - **Tool Ready (legacy, hard-disabled)** — Its pre-call dependency checks are retained in source but unconditionally bypassed while the readiness model is redesigned.
13
13
 
14
14
  Agent adapters are available for:
15
15
 
16
- - **OpenClaw plugin** — covers command rewriting, response compression, and schema compression in one plugin.
16
+ - **OpenClaw plugin** — delegates PreTool RTK rewriting and PostTool optimization to Protocol v2 Core.
17
17
  - **copilot-shell hook** — intercepts Shell commands via a PreToolUse hook and delegates to RTK for command rewriting + output filtering.
18
- - **Hermes Agent plugin** — response compression, TOON encoding, command rewriting (block + suggest), and registered but hard-disabled Tool Ready via Hermes's native plugin system.
19
- - **Qoder CLI plugin** — registered but hard-disabled Tool Ready, command rewriting, and response compression via Qoder's native hook system.
20
- - **Claude Code plugin** — RTK command rewriting, response/TOON compression, and registered but hard-disabled Tool Ready via Claude Code's official plugin marketplace.
18
+ - **Hermes Agent plugin** — delegates block-and-suggest command rewriting and model-bound result optimization to Core, with Marker-directed recovery through its shell tool.
19
+ - **Qoder CLI plugin** — registered but hard-disabled Tool Ready, command rewriting, response compression, and Marker-directed recovery via Qoder's native hook system.
20
+ - **Claude Code plugin** — RTK command rewriting, response/TOON compression, Marker-directed recovery, and registered but hard-disabled Tool Ready via Claude Code's official plugin marketplace.
21
21
  - **Codex plugin** — RTK command rewriting, environment-failure diagnostics, and registered but hard-disabled Tool Ready via Codex's native hook system.
22
- - **OpenCode plugin** — schema/response/TOON compression, registered but hard-disabled Tool Ready, and command rewriting via OpenCode's local plugin API.
23
- - **DeepSeek Harness plugin** — native response compression and environment-error attribution through DSH's `tools/post-execute` seam.
22
+ - **OpenCode plugin** — schema/response/TOON compression, Marker-directed recovery, registered but hard-disabled Tool Ready, and command rewriting via OpenCode's local plugin API.
23
+ - **Qwen Code extension** — command rewriting and registered but hard-disabled Tool Ready; current host releases cannot replace post-tool output and skip the declared schema event.
24
+ - **QwenPaw plugin** — schema compression, RTK command rewriting, response/TOON compression, and static-tool recovery through an AgentScope middleware registered by QwenPaw's plugin system; the plugin embeds the `anolisa_tokenless` wheel in-process.
25
+ - **DeepSeek Harness plugin** — native response compression, Marker-directed recovery, and environment-error attribution through DSH's `tools/post-execute` seam.
24
26
 
25
- For framework developers, the self-contained Python SDK and separate **AgentScope integration**
26
- cover schema compression, RTK rewriting, response compression, TOON, retrieval, and attribution.
27
+ For framework developers, the Python SDK has a framework-neutral layer and an **AgentScope-specific
28
+ layer**. Together they cover schema compression, RTK rewriting, response compression, TOON,
29
+ retrieval, and attribution.
27
30
 
28
31
  ## Features
29
32
 
30
33
  | Capability | Savings indicator | Details |
31
34
  |---|---|---|
32
35
  | Schema compression | 47.3% on reference fixture | Compresses OpenAI Function Calling tool schemas |
33
- | Response compression | 65.8% on reference fixture | Compresses API / tool responses |
34
- | Reversible compression (stash) | | Dropped array items are stashed and retrievable via `<<tokenless:KEY>>` markers |
36
+ | Content-aware response compression | 36.3% lossless savings on the JSON reference fixture | Routes successful JSON through `JsonCompressor`; lossless candidates saving at least 15% take priority, while recoverable record arrays can be reduced to a 32-record base budget |
37
+ | Build-log compression | workload-dependent | Cleans terminal control output and reduces repeated routine progress in recognized Cargo, pytest, npm/Jest, Go, Make/C, and generic command logs while preserving diagnostics, summaries, phases, and stack traces |
38
+ | CSV/TSV table compression | workload-dependent | Preserves every cell when compacting quoting and record separators; larger tables can retain selected rows with an explicit incomplete-table notice and byte-exact original retrieval. Requires a text replacement slot; file reads pass through |
39
+ | Reversible compression (stash) | — | Omitted record collections and bounded values are stashed; supported agents run `tokenless retrieve HASH` or call their static Retrieve Tool when full data is needed |
35
40
  | TOON context compression | 17.0% on reference response | Encodes JSON to TOON format for LLMs |
36
41
  | Command rewriting | 60–90% | Filters CLI output via RTK (70+ commands supported) |
37
42
  | Tool Ready | reduces retry waste | Legacy pre-call check, auto-fix, and blocking; hard-disabled |
38
- | OpenClaw plugin | — | Command rewriting ✅, Response compression ✅, Schema compression |
39
- | copilot-shell hooks | — | Tool Ready ⛔ hard-disabled, Command rewriting ✅, Response compression ✅, TOON ✅, Schema compression |
40
- | Hermes Agent plugin | — | Tool Ready ⛔ hard-disabled, Command rewriting ✅, Response compression ✅, TOON ✅, Schema compression |
41
- | Qoder CLI plugin | — | Tool Ready ⛔ hard-disabled, Command rewriting ✅, Response compression ✅ |
42
- | Claude Code plugin | — | Tool Ready ⛔ hard-disabled, Command rewriting ✅, Response compression ✅, TOON ✅ |
43
+ | OpenClaw plugin | — | RTK ✅, lossless transcript PostTool ✅, Schema/Retrieve unavailable in the host |
44
+ | copilot-shell hooks | — | Tool Ready ⛔ hard-disabled, Command rewriting ✅; Cosh-NG supports response compression and Marker-command recovery, while legacy copilot-shell remains lossless-only; Common BeforeModel passes schemas through without authorized Retrieve |
45
+ | Hermes Agent plugin | — | Tool Ready ⛔ hard-disabled, Core-owned command rewriting/response/TOON ✅, Marker-command recovery ✅, Schema unavailable |
46
+ | Qoder CLI plugin | — | Tool Ready ⛔ hard-disabled, Command rewriting ✅, Response compression ✅, Marker-command recovery ✅ |
47
+ | Claude Code plugin | — | Tool Ready ⛔ hard-disabled, Command rewriting ✅, Response compression ✅, TOON ✅, Marker-command recovery on Claude Code 2.1.121 or newer |
43
48
  | Codex plugin | — | Tool Ready ⛔ hard-disabled, Command rewriting ✅, Environment diagnostics ✅, Response compression — protocol-blocked |
44
- | OpenCode plugin | — | Tool Ready ⛔ hard-disabled, Command rewriting ✅, Schema compression ✅, Response compression ✅, TOON ✅ |
45
- | DeepSeek Harness plugin | — | Response compression ✅, Environment-error attribution |
49
+ | OpenCode plugin | — | Tool Ready ⛔ hard-disabled, Command rewriting ✅, Schema compression ✅, Response compression ✅, TOON ✅, Marker-command recovery ✅ |
50
+ | Qwen Code extension | — | Tool Ready hard-disabled, Command rewriting ✅, Response/Schema replacement unavailable in current host |
51
+ | QwenPaw plugin | — | Schema compression ✅, Command rewriting ✅, Response compression ✅, TOON ✅, Retrieve Tool recovery ✅ |
52
+ | DeepSeek Harness plugin | — | Response compression ✅, Marker-command recovery ✅, Environment-error attribution ✅ |
46
53
  | AgentScope framework integration | — | Schema ✅, RTK ✅, Response ✅, TOON ✅, Retrieval ✅ |
47
54
  | Zero runtime deps | — | Pure Rust, single static binary |
48
55
 
49
- The schema, response, and TOON figures above are isolated Tokenless 0.7.11
50
- results on the repository's committed reference fixtures; they are neither a
56
+ The schema, response, and TOON figures above are isolated results on the
57
+ repository's committed reference fixtures; they are neither a
51
58
  production range nor additive. Compression depends on payload size and shape,
52
59
  removable fields, configured thresholds, and the share of tool data in the
53
60
  session. Short or already compact payloads may save only a few percent or pass
@@ -65,7 +72,7 @@ on the share and shape of that content in the session.
65
72
 
66
73
  | Workload | Primary strategy | Why |
67
74
  |----------|-----------------|-----|
68
- | Shell-heavy (build/test/triage) | Command rewriting (RTK) | `cargo`/`npm`/`go`/`pytest` output carries lots of progress/warning noise; RTK cuts 60–90% |
75
+ | Shell-heavy (build/test/triage) | Build-log compression + RTK | Recognized build/test commands keep their native output for PostTool compression; other supported shell commands use RTK |
69
76
  | API/fetch-heavy (REST, web_fetch) | Response compression + TOON | JSON may carry removable debug/null/empty fields; sufficiently large, regular structures also have reducible syntax overhead |
70
77
  | Agents with many tools | Schema compression | Many Function Calling definitions carry verbose descriptions and removable metadata |
71
78
  | Long responses that must stay faithful | Reversible compression (Stash) | Truncated content is `retrieve`-able end-to-end lossless; thresholds can be tightened safely |
@@ -97,16 +104,18 @@ on the share and shape of that content in the session.
97
104
 
98
105
  Example: dashboard shows 60% compression rate, but if tool responses account for 20% of total consumption, the actual savings rate is 60% × 20% = **12%**. This is why savings feel "lighter than a feather" in experiments consuming 15 million tokens — tokenless only optimizes the ~3 million tokens of tool responses.
99
106
 
100
- > Stash makes compression **end-to-end lossless**: you can tighten truncation thresholds for higher inline savings and recover the original via the `<<tokenless:KEY>>` marker when needed, with no correctness impact. Use `TOKENLESS_COMPRESSION_ENABLED=0/1` dual runs to compare real savings.
107
+ > Recoverable omissions include an optional action: `If needed, run in shell: tokenless retrieve HASH`. AgentScope instead sees `If needed, call tool tokenless_retrieve with hash_or_marker=HASH` (using its configured static Tool name). Recovery returns the saved payload while it remains in Stash; it costs additional tokens and is not required for every omission. Historical `<<tokenless:HASH>>` markers remain readable but are no longer generated. Use `TOKENLESS_COMPRESSION_ENABLED=0/1` dual runs to compare real savings.
101
108
  > See [user manual](../../docs/user-guide/en/token-saving/tokenless/user-manual.md) for per-strategy trigger conditions.
102
109
 
103
110
  ## Architecture
104
111
 
105
112
  ```
106
113
  Token-Less/
107
- ├── crates/tokenless-schema/ # Core library: SchemaCompressor + ResponseCompressor
114
+ ├── crates/tokenless-schema/ # BeforeModel tool-schema compressor
108
115
  ├── crates/tokenless-ccr/ # Reversible compression stash (Compress-Cache-Retrieve)
109
- ├── crates/tokenless-runtime/ # Stateful in-process compression and retrieval API
116
+ ├── crates/tokenless-runtime/ # Lifecycle API and Runtime-owned PostTool pipeline
117
+ ├── crates/tokenless-protocol/ # Versioned adapter contract and token estimator
118
+ ├── crates/tokenless-compressors/ # JSON, tabular, and build-log compressors
110
119
  ├── crates/tokenless-cli/ # CLI binary: `tokenless` command (env-check, compress, retrieve, stats)
111
120
  ├── python/tokenless/ # PyO3 package: `anolisa_tokenless`
112
121
  ├── python/agentscope/ # Pure-Python AgentScope integration package
@@ -124,6 +133,7 @@ Token-Less/
124
133
  │ ├── claude-code/ # Claude Code plugin + marketplace + hooks
125
134
  │ ├── codex/ # Codex plugin + scripts
126
135
  │ ├── opencode/ # OpenCode local plugin + scripts
136
+ │ ├── qwenpaw/ # QwenPaw plugin (AgentScope middleware) + scripts
127
137
  │ └── dsh/ # Native DeepSeek Harness bundle
128
138
  ├── third_party/rtk/ # RTK vendored source (justfile clone+patch from GitHub)
129
139
  ├── third_party/patches/ # Patches for vendored third_party sources
@@ -200,7 +210,7 @@ make setup
200
210
  The source setup installs `tokenless` to `~/.local/bin`, places the `rtk`
201
211
  helper alongside it, and deploys all adapters for development.
202
212
 
203
- ### Build the Python runtime
213
+ ### Build the Python SDK
204
214
 
205
215
  Framework authors can build the in-process Python API from source:
206
216
 
@@ -222,8 +232,12 @@ where its native wheel was built. It exposes the four Tokenless lifecycle
222
232
  methods and bundles the matching RTK executable; TOON is linked into the native
223
233
  runtime. It does not require the Tokenless CLI or system helper binaries. The
224
234
  package is built and tested in this repository but is not yet published to
225
- PyPI. See the [runtime design](docs/design/runtime-library.md)
226
- and the [user manual](../../docs/user-guide/en/token-saving/tokenless/user-manual.md#build-the-python-runtime-from-source).
235
+ PyPI. See the [Python SDK guide](../../docs/user-guide/en/token-saving/tokenless/sdk.md) for
236
+ runnable lifecycle and Stats examples, the
237
+ [AgentScope SDK integration](../../docs/user-guide/en/token-saving/tokenless/sdk/agentscope.md) for
238
+ AgentScope attachment, the
239
+ [Agent integration guide](../../docs/user-guide/en/token-saving/tokenless/framework-integration.md)
240
+ for product adapters, and the [runtime design](docs/design/runtime-library.md) for internal contracts.
227
241
 
228
242
  The same wheel provides typed, read-only statistics queries without requiring
229
243
  the CLI. Point `TokenlessStats` at the state directory used by the runtime, or
@@ -255,7 +269,31 @@ The description, string, array, and depth limits in the
255
269
  [CLI reference](../../docs/user-guide/en/token-saving/tokenless/cli-reference.md)
256
270
  trigger individual transformations; they are not minimum total payload sizes.
257
271
  Agent adapters may apply separate pre-check thresholds; see the
258
- [framework integration guide](../../docs/user-guide/en/token-saving/tokenless/framework-integration.md#adapter-processing-rules).
272
+ [Agent integration guide](../../docs/user-guide/en/token-saving/tokenless/framework-integration.md#adapter-processing-rules).
273
+
274
+ ### compress
275
+
276
+ Shared Agent hooks send lifecycle requests to `tokenless compress`; only
277
+ successful, non-bypassed PostTool JSON, CSV/TSV tables, and eligible command-output build logs
278
+ enter the Runtime-owned Pipeline. Tool errors bypass compression and keep their
279
+ original output while Core attaches environment-diagnostic context.
280
+
281
+ PreTool leaves recognized Cargo, pytest, npm/Jest, Go, and Make build/test
282
+ commands unchanged so their native output has a single PostTool owner. Other
283
+ supported commands may be rewritten by RTK, and their results continue to
284
+ bypass PostTool compression.
285
+
286
+ Claude Code 2.1.121 or newer, Qoder CLI, OpenCode, and Cosh-NG can replace the
287
+ live result. Their PostTool requests enable recovery when bare `tokenless`
288
+ also resolves on the shell `PATH`. A compression Marker then tells the model to
289
+ run the exact `tokenless retrieve` command through the existing shell tool. The
290
+ hook recognizes only a successful, standalone command
291
+ with a valid Hash or Marker and sends its output through the Retrieve bypass,
292
+ preventing a second compression pass. Legacy copilot-shell and other hosts that
293
+ cannot replace the result remain lossless-only. BeforeModel Schema compression
294
+ still requires its separate authorized recovery capability. See the
295
+ [CLI reference](../../docs/user-guide/en/token-saving/tokenless/cli-reference.md#compress)
296
+ for the request/response contract and an executable example.
259
297
 
260
298
  ### compress-schema
261
299
 
@@ -314,9 +352,8 @@ hash or any text containing a `<<tokenless:HASH>>` marker:
314
352
  # Bare hash
315
353
  tokenless retrieve c30ccf5ed1125e0ed871ba8e
316
354
 
317
- # Or paste the whole truncation line — the hash is extracted automatically.
318
- # (Use the FULL 24-hex hash from your output; the value below is shorthand.)
319
- tokenless retrieve "<... 160 items truncated, run: tokenless retrieve '<<tokenless:c30ccf5ed1125e0ed871ba8e>>'>"
355
+ # Historical markers remain accepted
356
+ tokenless retrieve '<<tokenless:c30ccf5ed1125e0ed871ba8e>>'
320
357
  ```
321
358
 
322
359
  ### compress-toon / decompress-toon
@@ -361,6 +398,25 @@ duplicate intermediate token counts. See
361
398
  [Measuring Tokenless Savings](../../docs/user-guide/en/token-saving/tokenless/measuring-savings.md)
362
399
  for options and measurement limits.
363
400
 
401
+ ### Trace correlation
402
+
403
+ Exported SLS records carry the trace identity of the host span they were
404
+ produced under, so an observability backend such as AgentLoop can attribute
405
+ token savings to a trace. Two optional environment variables supply it:
406
+
407
+ - `TOKENLESS_TRACEPARENT` — adapter-facing override, read first.
408
+ - `TRACEPARENT` — standard W3C variable, used when the override is absent,
409
+ empty, or unparsable.
410
+
411
+ Injecting one is the launcher's responsibility: OpenTelemetry keeps the active
412
+ span in an in-process carrier and does not export it to child processes, so a
413
+ host or adapter that wants correlation must set one of them before spawning
414
+ Tokenless. Without a usable context the record shape is unchanged, and the
415
+ identity is written only to the SLS JSONL — never to the local `stats.db`. See
416
+ [Measuring Tokenless Savings](../../docs/user-guide/en/token-saving/tokenless/measuring-savings.md)
417
+ and
418
+ [Configuration and Data Privacy](../../docs/user-guide/en/token-saving/tokenless/configuration-and-privacy.md).
419
+
364
420
  ### Database location
365
421
 
366
422
  Tokenless stores statistics and reversible-compression data in
@@ -386,7 +442,7 @@ The adapter provides hooks that are auto-discovered by copilot-shell via the cos
386
442
  | Tool Ready (hard-disabled) | PreToolUse (all tools) | `tool_ready_hook.sh` | Silent pass-through; no check, repair, context, or block |
387
443
  | Command rewriting | PreToolUse (Shell) | `rewrite_hook.py` | Rewrite commands via RTK |
388
444
  | Response compression + attribution + TOON | PostToolUse | `compress_response_hook.py` | Compress + env error attribution + TOON |
389
- | Schema compression | BeforeModel | `compress_schema_hook.py` | Compress tool schemas |
445
+ | Schema compression | BeforeModel | `compress_schema_hook.py` | Passes through lossy transformations until the host exposes marker-authorized recovery |
390
446
 
391
447
  ### Install
392
448
 
@@ -463,49 +519,69 @@ String format `"jq"` is also supported (auto-converts to object).
463
519
 
464
520
  ## OpenClaw Plugin
465
521
 
466
- The plugin hooks into the OpenClaw agent loop at two stages:
522
+ The plugin translates two OpenClaw events into Protocol v2 lifecycle operations:
467
523
 
468
524
  | Hook | Event | Action | Status |
469
525
  |---|---|---|---|
470
526
  | Tool Ready | `before_tool_call` | Registered silent pass-through; no check, repair, context, or block | ⛔ Hard-disabled |
471
- | Command rewriting | `before_tool_call` | Rewrites `exec` commands to RTK equivalents for filtered output | ✅ Active |
472
- | Response compression | `tool_result_persist` | Compresses tool results before they enter the context window | ✅ Active |
473
- | Schema compression | — | Not supported by OpenClaw's hook system | |
527
+ | PreTool | `before_tool_call` | Sends `exec` arguments to Core and applies the returned RTK rewrite | ✅ Active |
528
+ | PostTool | `tool_result_persist` | Rewrites supported OpenClaw-owned transcript tool results | ✅ Active |
529
+ | BeforeModel / Retrieve | — | OpenClaw exposes neither a reliable schema-transform seam nor marker-authorized recovery | — |
530
+
531
+ Core owns RTK execution, JSON detection, cleanup, TOON selection, thresholds, diagnostics, and final
532
+ arbitration. The plugin carries Core's per-call `output_optimization` from PreTool into the matching
533
+ PostTool request, so RTK output is not compressed twice. The local CLI recovery command is a trusted
534
+ operator entry rather than Agent authorization, so the plugin applies only lossless candidates.
474
535
 
475
- **Response compression details:**
476
- - Automatically compresses results from all tool types (`web_search`, `web_fetch`, `read_file`, etc.)
477
- - Skips `exec` tool results when RTK is enabled RTK already produces optimized output, avoiding double-compression
478
- - Observed savings: **~78%** on `web_fetch` results, varies by content type
536
+ `tool_result_persist` is a synchronous OpenClaw transcript seam. It can replace a persisted string,
537
+ a structured value, or a single text block while preserving the surrounding Tool Result envelope;
538
+ media and multi-block results pass through. It does not replace a tool result already consumed by
539
+ the model in the same turn, and it does not cover non-OpenClaw transcript implementations.
479
540
 
480
- Each hook degrades gracefully — if the corresponding binary (`rtk` or `tokenless`) is not installed, that hook is silently skipped.
541
+ Both operations use the single `tokenless compress` entry point and fail open if Tokenless is
542
+ missing or returns an invalid response.
481
543
 
482
544
  ### Configuration
483
545
 
546
+ The adapter requires OpenClaw Plugin API `2026.4.22` or newer; package metadata enforces this
547
+ minimum during installation on hosts that support compatibility checks.
548
+
484
549
  Options in `openclaw.plugin.json`:
485
550
 
486
551
  | Option | Default | Description |
487
552
  |---|---|---|
488
553
  | `rtk_enabled` | `true` | Enable RTK command rewriting |
489
- | `schema_compression_enabled` | `true` | Enable tool schema compression (pending OpenClaw support) |
490
- | `response_compression_enabled` | `true` | Enable tool response compression via `tool_result_persist` |
491
- | `verbose` | `true` | Log detailed rewrite/compression info |
554
+ | `post_tool_enabled` | `true` | Enable Protocol v2 PostTool handling of persisted tool results |
555
+ | `tool_ready_enabled` | `true` | Register the currently hard-disabled Tool Ready hook |
556
+ | `verbose` | `false` | Log lifecycle rewrites and applied PostTool results |
557
+
558
+ The previous response, TOON, skip-tool, and shell-tool configuration keys are removed; Core now
559
+ owns those decisions.
492
560
 
493
561
  ## Hermes Agent Plugin
494
562
 
495
- The plugin registers hooks at three Hermes events, covering five strategies:
563
+ The plugin registers hooks at three Hermes events while Core owns the lifecycle policy:
496
564
 
497
565
  | Strategy | Event | Action | Status |
498
566
  |---|---|---|---|
499
567
  | Tool Ready | `pre_tool_call` | Registered silent pass-through; no check, repair, context, or block | ⛔ Hard-disabled |
500
- | Command rewriting | `pre_tool_call` | Blocks original command, suggests `rtk`-rewritten version (one extra round-trip) | ✅ Active |
501
- | Response compression | `transform_tool_result` | Compresses tool results via `tokenless compress-response` | ✅ Active |
502
- | TOON encoding | `transform_tool_result` | Pipeline step after response compression — encodes JSON to TOON format | ✅ Active |
568
+ | Command rewriting | `pre_tool_call` | Sends the command to Core, then blocks and suggests the returned RTK form | ✅ Active |
569
+ | PostTool optimization | `transform_tool_result` | Sends the final model-bound result to Core and applies accepted output | ✅ Active |
503
570
  | Session tracking | `on_session_start` | Propagates agent/session IDs for stats recording | ✅ Active |
504
- | Schema compression | — | Not supported by Hermes hook system (no hook exposes tool schemas) | Blocked |
571
+ | Schema compression | — | Hermes exposes no schema-transform seam | |
572
+ | Marker recovery | `transform_tool_result` | Labels a successful standalone `tokenless retrieve` shell result for the Core bypass | ✅ Active |
505
573
 
506
- **How command rewriting works in Hermes**: Hermes's `pre_tool_call` hook can only block tool execution (not modify arguments), so the plugin blocks the original shell command and returns a message suggesting the RTK-rewritten version. The agent then re-executes with the optimized command, adding one extra tool-call round-trip. This is safe — `rtk rewrite` only does text substitution and never executes the command.
574
+ **How command rewriting works in Hermes**: to remain compatible with Hermes releases that only
575
+ support blocking, the plugin asks Core for a rewrite, blocks the original shell command, and tells
576
+ the agent to retry with the returned command. The retry adds one tool-call round-trip. The final
577
+ hook recognizes Core's attributed RTK wrapper from the command Hermes actually executed, so RTK
578
+ output bypasses a second compression pass without correlating two different tool-call IDs.
507
579
 
508
- Each hook degrades gracefully if the corresponding binary is not installed, that hook is silently skipped.
580
+ When compression omits recoverable data, the Marker tells Hermes to run
581
+ `tokenless retrieve` through its existing shell tool. The adapter checks the
582
+ actual executed command; a successful standalone retrieve is returned unchanged
583
+ and never compressed again. If the Tokenless operation is unavailable or fails,
584
+ the hook leaves the host value unchanged.
509
585
 
510
586
  ### Install
511
587
 
@@ -539,6 +615,10 @@ The plugin registers hooks at three Qoder events, covering three strategies:
539
615
 
540
616
  Each hook degrades gracefully — if the corresponding binary is not installed, that hook is silently skipped.
541
617
 
618
+ When a compressed result contains a Retrieve Marker, Qoder can execute its
619
+ command through the existing shell tool. The successful result bypasses response
620
+ compression so the recovered payload reaches the model unchanged.
621
+
542
622
  ### Install
543
623
 
544
624
  ```bash
@@ -558,6 +638,10 @@ The plugin registers hooks at two Claude Code events, covering four strategies:
558
638
 
559
639
  Claude Code v2 requires plugins to be sourced from a registered marketplace. We expose the adapter's `claude-code/` directory as a single-plugin marketplace (`anolisa-tokenless`), then install `tokenless@anolisa-tokenless` from it. The marketplace name is component-scoped so multiple ANOLISA components can each register their own without colliding.
560
640
 
641
+ On Claude Code 2.1.121 or newer, a compressed result can direct the model to
642
+ run `tokenless retrieve` through Bash. The successful command result bypasses
643
+ compression and restores the complete payload.
644
+
561
645
  ### Install
562
646
 
563
647
  ```bash
@@ -609,13 +693,55 @@ The installer creates a `tokenless.js` symbolic link in OpenCode's global
609
693
  `OPENCODE_CONFIG_DIR`, `XDG_CONFIG_HOME`, and the explicit
610
694
  `TOKENLESS_OPENCODE_CONFIG_DIR` override.
611
695
 
696
+ If a response contains a Retrieve Marker, OpenCode can run the embedded
697
+ `tokenless retrieve` command through its existing shell tool. The adapter sends
698
+ the successful recovery result through the Core bypass without recompressing it.
699
+
700
+ ## QwenPaw Plugin
701
+
702
+ The QwenPaw adapter is a native QwenPaw plugin. Its `plugin.py` registers an
703
+ AgentScope middleware through `api.register_middleware` and a
704
+ `tokenless_retrieve` tool through `api.register_tool`, and calls the in-process
705
+ `anolisa_tokenless.TokenlessSdk` directly:
706
+
707
+ | Feature | Middleware hook | Behavior | Status |
708
+ |---|---|---|---|
709
+ | Schema compression | `on_model_call` | Compresses tool schemas and appends the retrieve tool | ✅ Active |
710
+ | Command rewriting | `on_acting` | Rewrites `execute_shell_command` input via RTK after QwenPaw's approval step | ✅ Active |
711
+ | Response + TOON compression | `on_acting` | Replaces text blocks of the tool result for QwenPaw's built-in tools; file readers and tools outside the built-in table pass through untouched | ✅ Active |
712
+ | Recovery | `tokenless_retrieve` tool | Restores omitted content from the hash in a visible recovery instruction | ✅ Active |
713
+
714
+ ```bash
715
+ make qwenpaw-install
716
+ ```
717
+
718
+ The installer runs `qwenpaw plugin install <bundle> --force`; QwenPaw copies the
719
+ bundle into `<working dir>/plugins/tokenless/` (`QWENPAW_WORKING_DIR`, else
720
+ `COPAW_WORKING_DIR`, else an existing `~/.copaw`, else `~/.qwenpaw`) and installs
721
+ the `anolisa_tokenless` wheel listed in `requirements.txt` from the matching
722
+ GitHub Release. Records are written under `<workspace>/.tokenless`.
723
+
612
724
  ## DeepSeek Harness Plugin
613
725
 
614
- The native DSH bundle compresses successful single-block JSON tool results
615
- through `tools/post-execute` and keeps the original result unless the Tokenless
616
- CLI returns strictly smaller valid JSON. Content-retrieval tools remain
617
- lossless by default. Environment-error attribution stays active when response
618
- compression is disabled, skipped, or unable to reduce the result.
726
+ The native DSH bundle sends replaceable single-text tool results through
727
+ Tokenless PostTool Core on `tools/post-execute`. Core owns content detection,
728
+ JSON cleanup, TOON selection, acceptance, and environment-error diagnostics.
729
+ When a reduced response contains a Retrieve Marker, DSH can run the embedded
730
+ `tokenless retrieve` command through its existing shell tool. The adapter
731
+ classifies the successful standalone command from `exec.arguments.command` and
732
+ sends its output through the Core Retrieve bypass, so it remains unchanged.
733
+ Recoverable compression is enabled only when bare `tokenless` resolves on the
734
+ shell `PATH` to the same executable selected by `tokenlessBin` or
735
+ `TOKENLESS_BIN` for Core. An absolute plugin-only or different binary is not
736
+ sufficient because the Marker emits the bare command.
737
+ DSH removes inherited `TOKENLESS_*` variables from model shell commands, so the
738
+ adapter publishes the selected state directory and optional statistics/Stash
739
+ database overrides as managed DSH shell facts. Core uses the same paths. The
740
+ data directory defaults to `.tokenless` in the session workspace and contains
741
+ a self-ignoring `.gitignore`; set `TOKENLESS_DATA_DIR`, `TOKENLESS_STATS_DB`, or
742
+ `TOKENLESS_STASH_DB` before starting DSH to select other absolute paths that
743
+ DSH's shell sandbox can access.
744
+ Error guidance stays active when response compression is disabled.
619
745
 
620
746
  Enable the bundle for every desired DSH profile in one command by repeating
621
747
  `--profile`:
@@ -659,13 +785,16 @@ Installation requires an explicit session identifier.
659
785
 
660
786
  ```python
661
787
  from agentscope.agent import ReActAgent
662
- from tokenless_agentscope import TokenlessAgentScope, TokenlessConfig
788
+ from anolisa_tokenless import ContentOrigin
789
+ from tokenless_agentscope import TokenlessAgentScope, TokenlessConfig, ToolContract
663
790
 
664
791
  integration = TokenlessAgentScope(
665
792
  TokenlessConfig(
666
- mode="balanced",
667
793
  data_dir="/absolute/path/to/tenant-tokenless-data",
668
794
  ),
795
+ tool_contracts={
796
+ "application_tool": ToolContract(ContentOrigin.API_RESPONSE),
797
+ },
669
798
  )
670
799
  toolkit = integration.create_toolkit()
671
800
  toolkit.register_tool_function(application_tool)
@@ -680,14 +809,17 @@ patch versions.
680
809
  ```python
681
810
  from agentscope.agent import Agent
682
811
  from agentscope.tool import Toolkit
683
- from tokenless_agentscope import TokenlessAgentScope, TokenlessConfig
812
+ from anolisa_tokenless import ContentOrigin
813
+ from tokenless_agentscope import TokenlessAgentScope, TokenlessConfig, ToolContract
684
814
 
685
815
  integration = TokenlessAgentScope(
686
816
  TokenlessConfig(
687
- mode="balanced",
688
817
  data_dir="/absolute/path/to/tenant-tokenless-data",
689
818
  # retrieve_tool_name="tenant_tokenless_retrieve",
690
819
  ),
820
+ tool_contracts={
821
+ "application_tool": ToolContract(ContentOrigin.API_RESPONSE),
822
+ },
691
823
  )
692
824
  toolkit = Toolkit(tools=[*application_tools, *integration.tools])
693
825
 
@@ -698,7 +830,7 @@ agent = Agent(
698
830
  )
699
831
  ```
700
832
 
701
- AgentScope App is supported from 2.0.1. It derives an isolated Tokenless data
833
+ AgentScope App is supported from 2.0.3. It derives an isolated Tokenless data
702
834
  directory for every user/agent/session below the configured absolute base
703
835
  directory:
704
836
 
@@ -708,25 +840,31 @@ from agentscope.app import create_app
708
840
  app = create_app(..., **integration.app_options())
709
841
  ```
710
842
 
843
+ `app_options()` supplies one Middleware factory. AgentScope publishes that
844
+ Middleware instance's static Retrieve Tool through `list_tools()` and persists
845
+ Marker authorization in `AgentState.middle_context`.
846
+
711
847
  Set a unique `retrieve_tool_name` in `TokenlessConfig` if the application
712
848
  already defines `tokenless_retrieve`; App assembly does not expose the other
713
849
  tools to this factory for a preflight collision check.
714
850
 
715
- AgentScope 2.0.0 does not expose App-level Agent middleware or Tool injection,
716
- so that patch release supports direct Agent construction only. The existing
717
- `TokenlessMiddleware` 2.x API remains available for compatibility; new code
718
- should use `TokenlessAgentScope` so it does not depend on patch-specific
719
- Toolkit mutation or automatic Tool collection.
720
-
721
- | Mode | Policy |
722
- |---|---|
723
- | `conservative` | Compress every non-excluded tool with 1 MiB / 65,536 / depth 32 limits |
724
- | `balanced` | Skip Read/Glob/Grep; use 65,536 / 128 / depth 8 for Shell and conservative limits elsewhere |
725
- | `aggressive` | Skip Read/Glob/Grep; use CLI defaults of 4,096 / 32 / depth 8 elsewhere |
726
-
727
- `balanced` is the default. The read-only retrieval Tool is published to the
728
- model only when a marker is visible and accepts only a hash from the exact
729
- marker set retained for that model call. Pass a different absolute `data_dir`
851
+ AgentScope 2.0.0 through 2.0.2 support direct Agent construction only; their App
852
+ APIs do not provide both Middleware-owned Tool publication and persisted
853
+ Middleware state. The existing `TokenlessMiddleware` 2.x API remains available
854
+ for compatibility; new code should use `TokenlessAgentScope`.
855
+
856
+ AgentScope supplies explicit contracts for its known shell, file, and API tools.
857
+ Register every custom tool with `ToolContract`: select `COMMAND_OUTPUT`,
858
+ `FILE_CONTENT`, or `API_RESPONSE`, and set `command_field` only for commands
859
+ that may be rewritten by RTK. Unknown custom tools fail during registration or
860
+ at the model boundary rather than guessing from output text. Compression
861
+ thresholds, TOON selection, diagnostics, and retrieval authorization remain in
862
+ Rust Core.
863
+
864
+ The read-only retrieval Tool has a static declaration and remains in the model
865
+ tool list across calls, avoiding tool-list churn when Marker visibility changes.
866
+ It accepts only a hash from the exact Marker set retained for the current model
867
+ call. Pass a different absolute `data_dir`
730
868
  to each user or tenant for direct Agents;
731
869
  `TOKENLESS_DATA_DIR` is only a process-wide fallback when `data_dir` is omitted.
732
870
  Retain the default one-hour stash TTL unless the application has a deliberate
@@ -742,6 +880,10 @@ transformed. Tool Ready remains hard-disabled.
742
880
 
743
881
  ## Build
744
882
 
883
+ For installed-package checks and optional real Agent tasks, see the
884
+ [release regression suite](tests/release_regression/README.md). It reports
885
+ tool-output savings and retrieval overhead separately.
886
+
745
887
  | Target | Description |
746
888
  |---|---|
747
889
  | `make build` | Build `tokenless` + `rtk` (release mode) |
@@ -773,6 +915,8 @@ transformed. Tool Ready remains hard-disabled.
773
915
  | `make codex-uninstall` | Remove Codex plugin |
774
916
  | `make opencode-install` | Install OpenCode local plugin |
775
917
  | `make opencode-uninstall` | Remove OpenCode local plugin |
918
+ | `make qwenpaw-install` | Install QwenPaw plugin via the qwenpaw CLI |
919
+ | `make qwenpaw-uninstall` | Remove QwenPaw plugin |
776
920
  | `make setup` | Full setup: build + install + all adapters |
777
921
 
778
922
  Override install paths:
@@ -819,8 +963,10 @@ layout and single-target interface.
819
963
  | Path | Description |
820
964
  |---|---|
821
965
  | `crates/tokenless-cli/` | CLI binary — `tokenless` command (compress, stats, env-check) |
822
- | `crates/tokenless-schema/` | Core Rust library — `SchemaCompressor` and `ResponseCompressor` |
823
- | `crates/tokenless-runtime/` | Stateful Rust API shared by the CLI and language bindings |
966
+ | `crates/tokenless-schema/` | BeforeModel tool-schema compression — `SchemaCompressor` |
967
+ | `crates/tokenless-compressors/` | Content-domain engines `JsonCompressor`, `TabularCompressor` and `BuildLogCompressor` are connected to PostTool |
968
+ | `crates/tokenless-runtime/` | Lifecycle API and Runtime-owned `PostToolPipeline`, shared by CLI and language bindings |
969
+ | `crates/tokenless-protocol/` | Versioned adapter contract and shared `heuristic-v1` token estimator |
824
970
  | `python/tokenless/` | PyO3 package exposing `anolisa_tokenless` for CPython 3.11+ |
825
971
  | `python/agentscope/` | Independent AgentScope framework integration and wheel metadata |
826
972
  | `adapters/tokenless/` | FHS adapter bundle — manifest, env-check spec/fix, hooks, OpenClaw plugin |
@@ -829,6 +975,7 @@ layout and single-target interface.
829
975
  | `adapters/tokenless/claude-code/` | Claude Code adapter — marketplace + plugin + hooks dispatcher |
830
976
  | `adapters/tokenless/codex/` | Codex adapter — plugin + Python hook scripts |
831
977
  | `adapters/tokenless/opencode/` | OpenCode adapter — local JavaScript plugin + lifecycle scripts |
978
+ | `adapters/tokenless/qwenpaw/` | QwenPaw adapter — plugin manifest, AgentScope middleware, wheel requirements + lifecycle scripts |
832
979
  | `third_party/rtk/` | RTK vendored source — command rewriting engine (justfile clone+patch) |
833
980
  | `third_party/patches/` | Patches for vendored third_party sources |
834
981
  | `packaging/raw/` | Component-owned ANOLISA raw packer and target validation |
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokenless",
3
- "version": "0.7.14",
3
+ "version": "0.8.1",
4
4
  "description": "Token-Less context compression for Claude Code — RTK command rewriting, response/TOON compression, and Tool Ready environment pre-check",
5
5
  "author": { "name": "ANOLISA" },
6
6
  "license": "Apache-2.0",
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env bash
2
+ # run-hook.sh — Locate and exec a shared tokenless hook script.
3
+ #
4
+ # Prefer hooks from the wrapper's own adapter tree so concurrent RPM, Makefile,
5
+ # and raw installations cannot cross-load another version. Hosts that copy the
6
+ # wrapper into a detached cache still use the historical FHS fallbacks.
7
+ #
8
+ # Usage: run-hook.sh <hook-script-basename> [args...]
9
+ # Examples: run-hook.sh rewrite_hook.py
10
+ # run-hook.sh compress_response_hook.py
11
+ # run-hook.sh tool_ready_hook.sh
12
+ #
13
+ # Fail-open contract: any not-found / missing-interpreter condition emits
14
+ # an empty JSON object on stdout and exits 0, so the host never blocks
15
+ # on us.
16
+ #
17
+ # PreToolUse matcher overlap is by design: hooks.json registers both a
18
+ # Bash-specific entry (rewrite) and a catch-all entry (tool-ready). Bash
19
+ # tool calls therefore fire both — the host evaluates each matching
20
+ # matcher independently, so this is the documented way to attach a
21
+ # tool-specific hook alongside a global one. The timeout values are
22
+ # upper bounds; observed runtimes are well under them.
23
+ set -euo pipefail
24
+
25
+ SCRIPT_DIR="$(CDPATH='' cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
26
+ SCRIPT="${1:?usage: run-hook.sh <hook-script-basename> [args...]}"
27
+ shift
28
+
29
+ fail_open() { echo "{}"; exit 0; }
30
+
31
+ # Reject anything but a bare basename. Practical risk is low — hooks.json is
32
+ # RPM-installed root:root 0644 and unwritable at runtime — but a defense-in-
33
+ # depth check costs one line and stops any future caller from smuggling a
34
+ # traversal segment through this argument.
35
+ case "$SCRIPT" in
36
+ */*|"") fail_open ;;
37
+ esac
38
+
39
+ CANDIDATES=(
40
+ "${SCRIPT_DIR}/../../common/hooks/${SCRIPT}"
41
+ "/usr/local/share/anolisa/adapters/tokenless/common/hooks/${SCRIPT}"
42
+ "/usr/share/anolisa/adapters/tokenless/common/hooks/${SCRIPT}"
43
+ "${HOME}/.local/share/anolisa/adapters/tokenless/common/hooks/${SCRIPT}"
44
+ )
45
+
46
+ for candidate in "${CANDIDATES[@]}"; do
47
+ [ -f "$candidate" ] || continue
48
+ case "$candidate" in
49
+ *.py)
50
+ command -v python3 >/dev/null 2>&1 || fail_open
51
+ exec python3 "$candidate" "$@"
52
+ ;;
53
+ *.sh)
54
+ exec bash "$candidate" "$@"
55
+ ;;
56
+ *)
57
+ fail_open
58
+ ;;
59
+ esac
60
+ done
61
+
62
+ fail_open