opencode-acp 1.12.10 → 1.13.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.
- package/NOTICE +29 -0
- package/README.md +116 -36
- package/README.zh-CN.md +94 -20
- package/dist/index.js +878 -44
- package/dist/index.js.map +1 -1
- package/dist/lib/compress/pipeline.d.ts.map +1 -1
- package/dist/lib/compress/quality-gate/algorithms/index.d.ts +3 -0
- package/dist/lib/compress/quality-gate/algorithms/index.d.ts.map +1 -0
- package/dist/lib/compress/quality-gate/evaluate.d.ts +8 -0
- package/dist/lib/compress/quality-gate/evaluate.d.ts.map +1 -0
- package/dist/lib/compress/quality-gate/index.d.ts +5 -0
- package/dist/lib/compress/quality-gate/index.d.ts.map +1 -0
- package/dist/lib/compress/quality-gate/registry.d.ts +6 -0
- package/dist/lib/compress/quality-gate/registry.d.ts.map +1 -0
- package/dist/lib/compress/quality-gate/types.d.ts +51 -0
- package/dist/lib/compress/quality-gate/types.d.ts.map +1 -0
- package/dist/lib/config-validation.d.ts.map +1 -1
- package/dist/lib/config.d.ts +9 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/messages/inject/policy/index.d.ts +5 -0
- package/dist/lib/messages/inject/policy/index.d.ts.map +1 -0
- package/dist/lib/messages/inject/policy/registry.d.ts +8 -0
- package/dist/lib/messages/inject/policy/registry.d.ts.map +1 -0
- package/dist/lib/messages/inject/policy/types.d.ts +2 -0
- package/dist/lib/messages/inject/policy/types.d.ts.map +1 -0
- package/dist/lib/messages/inject/utils.d.ts +0 -9
- package/dist/lib/messages/inject/utils.d.ts.map +1 -1
- package/dist/lib/messages/utils.d.ts.map +1 -1
- package/dist/lib/ui/notification.d.ts.map +1 -1
- package/package.json +5 -2
- package/dist/lib/prompts/compression-rules.d.ts +0 -20
- package/dist/lib/prompts/compression-rules.d.ts.map +0 -1
package/NOTICE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
opencode-acp — NOTICE
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ranxianglei
|
|
4
|
+
Licensed under AGPL-3.0-or-later (see ./LICENSE).
|
|
5
|
+
|
|
6
|
+
This distribution bundles portions of context-compress-algorithms
|
|
7
|
+
(https://github.com/ranxianglei/context-compress-algorithms), which is
|
|
8
|
+
originally published under the MIT License. The MIT-licensed source retains
|
|
9
|
+
its MIT status when consumed directly from that project; the bytes inlined
|
|
10
|
+
into this AGPL distribution become part of the combined AGPL work.
|
|
11
|
+
|
|
12
|
+
For the standalone MIT-licensed version, install
|
|
13
|
+
`context-compress-algorithms` directly.
|
|
14
|
+
|
|
15
|
+
MIT License (context-compress-algorithms):
|
|
16
|
+
|
|
17
|
+
Copyright (c) 2026 ranxianglei
|
|
18
|
+
|
|
19
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
|
20
|
+
copy of this software and associated documentation files (the "Software"),
|
|
21
|
+
to deal in the Software without restriction, including without limitation
|
|
22
|
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
23
|
+
and/or sell copies of the Software, and to permit persons to whom the
|
|
24
|
+
Software is furnished to do so, subject to the following conditions:
|
|
25
|
+
|
|
26
|
+
The above copyright notice and this permission notice shall be included
|
|
27
|
+
in all copies or substantial portions of the Software.
|
|
28
|
+
|
|
29
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
<strong>Active Context Pruning</strong> for <a href="https://opencode.ai">OpenCode</a>
|
|
5
5
|
<br />
|
|
6
6
|
The model decides <em>when</em> and <em>what</em> to compress — not a hard limit.
|
|
7
|
+
<br />
|
|
8
|
+
<strong>200K tokens is enough.</strong>
|
|
7
9
|
</p>
|
|
8
10
|
|
|
9
11
|
---
|
|
@@ -28,10 +30,14 @@ is, to date, the best context-management implementation on the market.
|
|
|
28
30
|
|
|
29
31
|
This brings two concrete effects:
|
|
30
32
|
|
|
31
|
-
- **
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
- **200K tokens is enough.** Across 30,000+ API calls in 50 real engineering
|
|
34
|
+
sessions, **97% of requests stayed under 200K tokens** — p90 at 150K, p95 at
|
|
35
|
+
180K. Every API call re-bills the full context, so keeping context low directly
|
|
36
|
+
reduces cost — even with a 90%+ prompt-cache hit rate, the non-cached portion
|
|
37
|
+
is billed at full price.
|
|
38
|
+
- **It supports ultra-long sessions without losing key content** — observed at
|
|
39
|
+
**3,300+ messages and 300M+ cumulative tokens** per session; architecturally
|
|
40
|
+
supports up to **100,000 messages** (5-digit message-ID space).
|
|
35
41
|
|
|
36
42
|
---
|
|
37
43
|
|
|
@@ -39,22 +45,23 @@ This brings two concrete effects:
|
|
|
39
45
|
|
|
40
46
|
Real engineering context, in practice.
|
|
41
47
|
|
|
42
|
-
**
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
**Across 6 active engineering sessions (11,000+ API calls), context p90 stays
|
|
49
|
+
at 150K–190K (15–19%), p95 at 160K–210K (16–21%) of the 1M window — with an
|
|
50
|
+
aggregate prompt-cache hit ratio of 91%.** (Why aggregate — not per-session —
|
|
51
|
+
matters is explained in [Impact on Prompt Caching](#impact-on-prompt-caching),
|
|
52
|
+
where it turns out to save far more tokens than traditional compression.)
|
|
53
|
+
|
|
54
|
+
| Session | Duration | Messages | API calls | Cumulative | Cache hit | Context p50 | Context p90 | Context p95 |
|
|
55
|
+
| --------- | ----------- | -------- | --------- | ---------- | --------- | ----------- | ----------- | ----------- |
|
|
56
|
+
| 0b89319b | 230h (9.5d) | 3,344 | 2,796 | 339M | 93% | 108K (11%) | 167K (17%) | 210K (21%) |
|
|
57
|
+
| 0a3be0cd | 130h (5.4d) | 3,183 | 2,499 | 276M | 91% | 104K (10%) | 145K (15%) | 153K (15%) |
|
|
58
|
+
| 0b2cd5a7 | 131h (5.4d) | 2,560 | 2,181 | 314M | 91% | 142K (14%) | 191K (19%) | 197K (20%) |
|
|
59
|
+
| 08f2d501 | 37h (1.5d) | 1,985 | 1,888 | 196M | 95% | 100K (10%) | 156K (16%) | 168K (17%) |
|
|
60
|
+
| 1410c791† | 865h (36d) | 1,279 | 1,100 | 218M | 87% | 132K (13%) | 407K (41%) | 427K (43%) |
|
|
61
|
+
| 096cf8c4 | 72h (3d) | 1,041 | 918 | 91M | 89% | 92K (9%) | 148K (15%) | 161K (16%) |
|
|
62
|
+
|
|
63
|
+
† Bug-testing session; p95 is abnormally high. Excluding it, p95 stays ≤ 210K
|
|
64
|
+
across all other sessions.
|
|
58
65
|
|
|
59
66
|
(Context percentages are of the 1M window.)
|
|
60
67
|
|
|
@@ -81,9 +88,10 @@ Or add to your opencode config:
|
|
|
81
88
|
## How It Works
|
|
82
89
|
|
|
83
90
|
ACP hands the context-compression tool directly to the model. The model is
|
|
84
|
-
**100% responsible** for context compression. The model's
|
|
85
|
-
|
|
86
|
-
|
|
91
|
+
**100% responsible** for context compression. The model's primary tools are
|
|
92
|
+
**compress** and **decompress**, supported by **acp_status** (context monitoring)
|
|
93
|
+
and **search_context** (search compressed content). A hardcoded 100% GC fallback
|
|
94
|
+
acts as a safety net when the context window is completely full.
|
|
87
95
|
|
|
88
96
|
### Lifecycle
|
|
89
97
|
|
|
@@ -122,27 +130,46 @@ interfere with the model's self-attention, short blocks lead the model to compre
|
|
|
122
130
|
some content first, handle the urgent matter, then decompress what it needs in
|
|
123
131
|
later work.
|
|
124
132
|
|
|
125
|
-
###
|
|
133
|
+
### GC safety net
|
|
134
|
+
|
|
135
|
+
When context reaches 100%, the system automatically truncates old-gen block summaries to prevent overflow. This is a last-resort safety net and does not interfere with the model's normal compress/decompress operations.
|
|
136
|
+
|
|
137
|
+
### Quality gate (non-blocking, off by default)
|
|
138
|
+
|
|
139
|
+
After each `compress` call, ACP can run a pluggable quality gate to detect summaries that catastrophically lost content (e.g., a 5K-token range compressed to a 147-char summary with none of the technical keywords). Failures only emit `logger.warn` — they never reject the compression (the result is already committed to state and visible to the model).
|
|
140
|
+
|
|
141
|
+
The default algorithm (`rouge-recall-v1`) is a two-layer gate calibrated against 6,913 real-world blocks:
|
|
142
|
+
|
|
143
|
+
- **L1 (length floor)**: Catches catastrophic retention failures — summaries shorter than 200 chars OR with <1% retention vs. the original. 100% recall, 0% FPR.
|
|
144
|
+
- **L2 (content coverage)**: Only runs on blocks that pass L1. Flags when **both** ROUGE-1 F1 < 0.05 **and** top-20 keyword recall < 0.20 (AND-combine keeps FPR at ~6.6%).
|
|
145
|
+
|
|
146
|
+
The interface is pluggable: future algorithms (e.g., LLM-as-judge via external API) can be registered through `registerQualityGate()` without touching pipeline wiring. Tokenizer uses hand-rolled word-level tokenization (English keywords + Chinese unigrams/bigrams) — not ACP's BPE tokenizer, which is too coarse for ROUGE-style matching.
|
|
126
147
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
148
|
+
Off by default for one release of burn-in. To enable:
|
|
149
|
+
|
|
150
|
+
```jsonc
|
|
151
|
+
{
|
|
152
|
+
"qualityGate": {
|
|
153
|
+
"enabled": true,
|
|
154
|
+
"algorithm": "rouge-recall-v1",
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
```
|
|
131
158
|
|
|
132
159
|
---
|
|
133
160
|
|
|
134
161
|
## Impact on Prompt Caching
|
|
135
162
|
|
|
136
163
|
Historically, ACP has fixed many of the low-cache-hit-rate problems caused by
|
|
137
|
-
DCP. The overall cache hit rate is now **~
|
|
164
|
+
DCP. The overall cache hit rate is now **~91%**.
|
|
138
165
|
|
|
139
166
|
Compared to traditional compression — which only compresses at 80–90% and, once it
|
|
140
167
|
compresses, forces 100% of the context to re-hit — ACP's hit rate is effectively
|
|
141
168
|
higher.
|
|
142
169
|
|
|
143
|
-
Additionally, ACP keeps total context around **~
|
|
144
|
-
traditional **50–80%**. So total
|
|
145
|
-
compression.
|
|
170
|
+
Additionally, ACP keeps total context around **~10–15% most of the time** (p50
|
|
171
|
+
100K, p90 150K of the 1M window), versus the traditional **50–80%**. So total
|
|
172
|
+
token savings are far higher than traditional compression.
|
|
146
173
|
|
|
147
174
|
**Conclusion:** ACP simultaneously raises the overall cache hit rate **and**
|
|
148
175
|
ensures key context information is not lost.
|
|
@@ -209,8 +236,8 @@ Each level overrides the previous, so project settings take priority over global
|
|
|
209
236
|
"debug": false,
|
|
210
237
|
// Notification display: "off", "minimal", or "detailed"
|
|
211
238
|
"pruneNotification": "detailed",
|
|
212
|
-
// Notification type: "chat" (
|
|
213
|
-
"pruneNotificationType": "
|
|
239
|
+
// Notification type: "chat" (deprecated, falls back to toast) or "toast" (system toast)
|
|
240
|
+
"pruneNotificationType": "toast",
|
|
214
241
|
// Slash commands configuration
|
|
215
242
|
"commands": {
|
|
216
243
|
"enabled": true,
|
|
@@ -319,6 +346,28 @@ Each level overrides the previous, so project settings take priority over global
|
|
|
319
346
|
// run major GC when context usage exceeds this (hardcoded, not configurable)
|
|
320
347
|
"majorGcThresholdPercent": "100%",
|
|
321
348
|
},
|
|
349
|
+
// Post-compression quality gate (non-blocking; off by default)
|
|
350
|
+
"qualityGate": {
|
|
351
|
+
// Master switch. When false, no evaluation runs.
|
|
352
|
+
"enabled": false,
|
|
353
|
+
// Algorithm name. Pluggable — future algorithms (including external
|
|
354
|
+
// API judges) can be registered without changing pipeline wiring.
|
|
355
|
+
"algorithm": "rouge-recall-v1",
|
|
356
|
+
// Per-algorithm config
|
|
357
|
+
"algorithms": {
|
|
358
|
+
"rouge-recall-v1": {
|
|
359
|
+
// Hard floor on summary length (chars). Below this → L1 fails.
|
|
360
|
+
"layer1MinChars": 200,
|
|
361
|
+
// Min retention = summaryLen / (compressedTokens*4) * 100.
|
|
362
|
+
// Catches catastrophic retention failures (<1%) with 0% FPR.
|
|
363
|
+
"layer1MinRetentionPct": 1.0,
|
|
364
|
+
// L2 fails (combined with top20Recall via AND) when below this.
|
|
365
|
+
"layer2MaxRougeF1": 0.05,
|
|
366
|
+
// L2 fails (combined with rougeF1 via AND) when below this.
|
|
367
|
+
"layer2MaxTop20Recall": 0.20,
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
},
|
|
322
371
|
}
|
|
323
372
|
```
|
|
324
373
|
|
|
@@ -350,7 +399,7 @@ By default, these tools are always protected from pruning:
|
|
|
350
399
|
|
|
351
400
|
The `protectedTools` arrays in `commands` and `strategies` add to this default list.
|
|
352
401
|
|
|
353
|
-
For the `compress` tool, `compress.protectedTools` ensures specific tool outputs are **hard-excluded** from compression ranges (v1.10.0+). When the model compresses a range that includes a protected tool message, that message survives intact in visible context — only the surrounding non-protected messages are compressed. By default `compress.protectedTools` includes
|
|
402
|
+
For the `compress` tool, `compress.protectedTools` ensures specific tool outputs are **hard-excluded** from compression ranges (v1.10.0+). When the model compresses a range that includes a protected tool message, that message survives intact in visible context — only the surrounding non-protected messages are compressed. By default `compress.protectedTools` includes only `skill` — this is sufficient in practice, as skill outputs are the one tool type whose content must never be lost to compression.
|
|
354
403
|
|
|
355
404
|
---
|
|
356
405
|
|
|
@@ -422,6 +471,35 @@ For the complete list with root cause analysis, see the [bug tracker](https://gi
|
|
|
422
471
|
|
|
423
472
|
## Changelog
|
|
424
473
|
|
|
474
|
+
### v1.13.1 — cc-alg Extraction + Compress Notification Freeze Fix (PRs #167, #168)
|
|
475
|
+
|
|
476
|
+
**Problem (compress notification freeze, #167)**: After every successful `compress` tool call, ACP injected a user-role notification message with a single `ignored: true` text part. opencode strips `ignored` parts before sending to the LLM, leaving an empty user message. The provider (zhipuai-lb / glm-5.2) rejects this with HTTP 400 code 1214 (`"messages 参数非法"`), `isRetryable: false` — opencode does not retry, and the session freezes until external recovery. 113 total occurrences across active sessions (8 in a single 3,156-message session).
|
|
477
|
+
|
|
478
|
+
**Fix (compress notification freeze, #167)**: (1) `lib/ui/notification.ts:280-298` — `sendCompressNotification` now always uses `client.tui.showToast`; the prior `chat` branch (which called `sendIgnoredMessage`) is removed. A warn log fires once per compress when the user explicitly set `pruneNotificationType: "chat"` so the behavior change is discoverable. (2) `lib/messages/utils.ts:232-269` — `dropEmptyMessages` now treats text parts carrying `ignored: true` as contributing to emptiness, so any future ignored-only user message is dropped before reaching the provider (defense in depth). (3) `lib/config.ts:175` — default `pruneNotificationType` changed from `"chat"` to `"toast"` so default-configured users see no deprecation warning.
|
|
479
|
+
|
|
480
|
+
**Problem (cc-alg extraction, #168)**: Reusable compression algorithms (ROUGE-1 quality gate, hand-rolled tokenizer, trigger policy, compression-rules prompt) were locked inside ACP's AGPL codebase, preventing MIT-licensed reuse by other projects. Internal coupling between algorithm modules and ACP plumbing made independent testing and reuse difficult.
|
|
481
|
+
|
|
482
|
+
**Fix (cc-alg extraction, #168)**: 4 modules extracted to external MIT package `context-compress-algorithms@1.0.0` (npm: https://www.npmjs.com/package/context-compress-algorithms, GitHub: https://github.com/ranxianglei/context-compress-algorithms). ACP imports via `^1.0.0` and inline-bundles into `dist/index.js` via tsup `noExternal`, so hosts install no extra dependency. NOTICE file added for MIT attribution of bundled code. New trigger policy registry at `lib/messages/inject/policy/` enables host-side customization of nudge trigger behavior (default policy comes from cc-alg's `defaultTriggerPolicy`). Provenance audit confirmed zero derivation from DCP upstream (AGPL-3.0) — search for `rouge` / `qualityGate` / `computeShouldNudge` / `HOW_TO_COMPRESS_RULES` against DCP repo all returned 0 hits, so MIT extraction is legally safe. AGENTS.md updated with new Git Safety Rule forbidding `version` field bumps on non-release branches to prevent future version-number drift.
|
|
483
|
+
|
|
484
|
+
Files (compress notification): `lib/ui/notification.ts`, `lib/messages/utils.ts`, `lib/config.ts`, `tests/drop-empty-messages.test.ts`.
|
|
485
|
+
Files (cc-alg extraction): `lib/compress/quality-gate/tokenizer.ts` (deleted), `lib/compress/quality-gate/algorithms/rouge-recall-v1.ts` (deleted), `lib/prompts/compression-rules.ts` (deleted), `lib/compress/quality-gate/{index,algorithms/index}.ts` (re-export from cc-alg for backward compat), `lib/messages/inject/{inject,utils}.ts`, `lib/messages/inject/policy/{types,registry,index}.ts` (new), `lib/prompts/{system,context-limit-nudge,turn-nudge,iteration-nudge}.ts`, `package.json`, `tsup.config.ts`, `NOTICE` (new), `AGENTS.md`. Tests: `tests/quality-gate-tokenizer.test.ts` (deleted, moved to cc-alg), `tests/quality-gate-rouge-recall-v1.test.ts` (deleted, moved to cc-alg — 55 tests migrated), `tests/quality-gate-pipeline-integration.test.ts` (uses inline stub gate), `tests/trigger-policy-integration.test.ts` (new). 794 tests pass (cc-alg has its own 95 tests in its own repo).
|
|
486
|
+
|
|
487
|
+
### v1.13.0 — Pluggable Quality Gate (Issue #20)
|
|
488
|
+
|
|
489
|
+
**Problem**: ACP had no mechanism to detect summaries that catastrophically lost content. The model could compress a 5K-token range into a 147-char summary missing every technical keyword, and the system would silently accept it. Issue #20 (calibrated against 6,913 real-world blocks from real sessions) identified two distinct failure modes: (1) length-floor failures — summaries <1% the size of the original (caught with 100% recall, 0% FPR via simple char count), and (2) content-coverage failures — summaries long enough to pass the length floor but capturing none of the original's keywords (e.g., a 996-char summary of a 5K-token original that recovers 0.6% of content words).
|
|
490
|
+
|
|
491
|
+
**Fix**: Added a pluggable `qualityGate` subsystem under `lib/compress/quality-gate/` with a `QualityGate` interface (`name`, `version`, `description`, `evaluate(ctx, config)`). The pipeline calls `evaluateBatchQuality()` in `finalizeSession()` after state is saved — failures only emit `logger.warn` (non-blocking: the compression result is already committed). The default algorithm `rouge-recall-v1` is a two-layer gate: L1 is a length/retention floor (200 chars AND 1% retention), L2 is an AND-combine of ROUGE-1 F1 < 0.05 AND top-20 keyword recall < 0.20 (AND keeps FPR at ~6.6% while still catching the long-but-empty failure mode). Tokenizer is hand-rolled word-level (English keywords ≥4 chars + Chinese unigrams/bigrams) — separate from ACP's BPE tokenizer, which is too coarse for ROUGE matching. Config defaults `enabled: false` for one release of burn-in. Interface leaves room for future algorithms including external API judges (sync signature today; future async gates need either type widening or internal wait+timeout wrap, registry/config unchanged).
|
|
492
|
+
|
|
493
|
+
Files: `lib/compress/quality-gate/{types,registry,tokenizer,evaluate,index}.ts`, `lib/compress/quality-gate/algorithms/{rouge-recall-v1,index}.ts`, `lib/compress/pipeline.ts`, `lib/config.ts`, `lib/config-validation.ts`, `dcp.schema.json`. Tests: `tests/quality-gate-{tokenizer,registry,rouge-recall-v1,pipeline-integration}.test.ts` (NEW, 74 tests). 842 tests pass.
|
|
494
|
+
|
|
495
|
+
### v1.12.11 — README Refresh (PR #164)
|
|
496
|
+
|
|
497
|
+
**Problem**: README documentation had drifted from code reality. The tagline under-emphasized ACP's core capability. The "Deletion strategy" section in the English README described a feature that no longer exists and contradicted the Chinese version. Cache hit rate and context usage statistics were stale (87%, ~30%). The `compress.protectedTools` default was documented as 5 tools (`task, skill, todowrite, todoread, decompress`) when the actual code default is only `skill`.
|
|
498
|
+
|
|
499
|
+
**Fix**: (1) Added `<strong>200K tokens is enough.</strong>` tagline alongside the existing one-liner. (2) Refreshed "Proven at scale" table with real API-level data from 6 active sessions (Duration, Messages, API calls, Cumulative tokens, Cache hit %, P50/P90/P95 context), with outlier annotated. Aggregate cache hit ~91%. (3) Replaced "Deletion strategy" section (EN) with "GC safety net" matching the Chinese version. (4) Updated "How It Works" to list `acp_status` and `search_context` as supporting tools. (5) Updated cache stats: 87% → 91%, context ~30% → ~10–15% (p50 100K, p90 150K of 1M window). (6) Corrected `compress.protectedTools` default documentation to `skill` only (matches `COMPRESS_DEFAULT_PROTECTED_TOOLS` at `lib/config.ts:121`).
|
|
500
|
+
|
|
501
|
+
Files: `README.md`, `README.zh-CN.md`. No code changes. Tests: 768 pass (unchanged).
|
|
502
|
+
|
|
425
503
|
### v1.12.10 — Batch Compress + Decompress Range Mode + GC Memory-Loss Fix + Token Classification + Nudge Quality (PRs #73, #155, #156, #157, #158, #159, #161)
|
|
426
504
|
|
|
427
505
|
**Problem**: Seven issues across compression UX, token accounting, GC safety, and nudge quality. (1) `decompress` required a per-block `acp_status` → decompress-per-block loop to restore multiple compressed blocks. (2) Since v1.12.9 (compress-as-anchor), compress tool `summary` content was misclassified as `toolTokens` instead of `summaryTokens`, inflating tool% and deflating summary% in the context breakdown. (3) The `compress` tool only accepted a single range per call — the model had to issue multiple calls to compress unrelated ranges, wasting turns. (4) The `[PROTECTED: ...]` label listed every tool in a protected message instead of only the triggering tools. (5) When all visible content was protected, the nudge still fired with an empty recommendation list. (6) When a nudge was suppressed, the next-turn check re-evaluated every turn. (7) **The GC system was silently destroying model-written summaries**: any block with `summary.length > 6000` chars was force-truncated to 3000 regardless of context pressure (0% pressure triggered truncation), and blocks with high `survivedCount` were auto-deactivated — causing irrecoverable memory loss across hundreds of sessions.
|
|
@@ -440,7 +518,7 @@ Files: `lib/messages/prune.ts`, `lib/messages/utils.ts`, `lib/compress/recap.ts`
|
|
|
440
518
|
|
|
441
519
|
### v1.12.8 — Phantom Block Rejection (PR #148)
|
|
442
520
|
|
|
443
|
-
**Problem**: When the model called `compress` on a range that was already covered by an active compression block, `applyCompressionState` still created a new block with `directMessageIds: []`, `compressedTokens: 0`, and `effectiveMessageIds` inherited from the consumed block. The model saw "0 tokens removed" in the notification, retried the same range, and entered a death loop: each phantom block added ~1K of summary overhead while compressing nothing, causing context to
|
|
521
|
+
**Problem**: When the model called `compress` on a range that was already covered by an active compression block, `applyCompressionState` still created a new block with `directMessageIds: []`, `compressedTokens: 0`, and `effectiveMessageIds` inherited from the consumed block. The model saw "0 tokens removed" in the notification, retried the same range, and entered a death loop: each phantom block added ~1K of summary overhead while compressing nothing, causing context to _grow_ with every compression call (issues #93, #135). User sessions showed 9 consecutive phantom compressions (b12–b20) on the same range before the user manually intervened.
|
|
444
522
|
|
|
445
523
|
**Fix**: Added `checkPhantomBlock()` — a stateless pre-check in `lib/compress/pipeline.ts` that mirrors `applyCompressionState`'s `newlyCompressedMessageIds` computation. For each plan, it builds the effective message set (plan messages + consumed blocks' effective messages) and checks whether ANY message is "new" (i.e., has no active block covering it BEFORE mutation). If no message is new, the plan is a phantom and the entire compress call is rejected with a clear error before any state mutation occurs. Wired into both range-mode (`compress/range.ts`) and message-mode (`compress/message.ts`) after plan preparation, before snapshot. 12 tests cover: empty plans, all-new messages, consumed-block inheritance, GC'd messages (deactivated blocks count as new), and the exact `applyCompressionState` mirroring.
|
|
446
524
|
|
|
@@ -569,6 +647,7 @@ This release fixes two critical compression-injection bugs (#20 echo, #78 drift)
|
|
|
569
647
|
#### Tool-Result Recap Injection — Fixes #20 & #78 (PR #95)
|
|
570
648
|
|
|
571
649
|
**Problem**: Compression summaries were injected as text-based `role:assistant` or `role:user` messages. Both roles misled the model:
|
|
650
|
+
|
|
572
651
|
- `role:assistant` (Bug 37 path) → model treated summaries as its own prior output and echoed them verbatim (#20, GLM-5.2).
|
|
573
652
|
- `role:user` (Bug 36 merge path) → model treated summaries as user instructions and chased old topics (#78, gpt-5.5).
|
|
574
653
|
|
|
@@ -611,6 +690,7 @@ Fixes the over-compression bug reported in issue #18 and GitHub #85, where the `
|
|
|
611
690
|
Additionally, the `compress.toolOutputNudgeThreshold` config key was **dead** — declared in the type but missing from the config merge, validation list, and JSON schema, so user overrides were silently dropped.
|
|
612
691
|
|
|
613
692
|
**Fix** (4 coordinated changes):
|
|
693
|
+
|
|
614
694
|
- `lib/messages/inject/inject.ts`: `toolOutputThreshold` now defaults to `nudgeGrowthTokens` (adaptive) instead of the hardcoded `5000`.
|
|
615
695
|
- `lib/config.ts` `mergeCompress`: `toolOutputNudgeThreshold` override now flows through the config merge.
|
|
616
696
|
- `lib/config-validation.ts`: `compress.toolOutputNudgeThreshold` registered as a valid config key.
|
package/README.zh-CN.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
<strong>Active Context Pruning</strong> — <a href="https://opencode.ai">OpenCode</a> 的主动上下文剪枝插件
|
|
5
5
|
<br />
|
|
6
6
|
由模型决定<em>何时</em>压缩、压缩<em>什么</em> — 而非硬性截断。
|
|
7
|
+
<br />
|
|
8
|
+
<strong>20 万 token 足矣。</strong>
|
|
7
9
|
</p>
|
|
8
10
|
|
|
9
11
|
---
|
|
@@ -26,8 +28,8 @@ ACP 将上下文管理的所有权限全部交给模型自己,而不依靠外
|
|
|
26
28
|
|
|
27
29
|
这带来两个影响:
|
|
28
30
|
|
|
29
|
-
-
|
|
30
|
-
- **超长上下文不丢关键内容** ——
|
|
31
|
+
- **20 万 token 足矣。** 在 50 个真实工程会话、3 万余次 API 调用中,**97% 的请求低于 20 万 token** —— p90 约 15 万,p95 约 18 万。每次 API 调用都会对完整上下文重新计费,因此上下文越低越省钱 —— 即使缓存命中率达 90%+,未缓存部分仍按全价计费。
|
|
32
|
+
- **超长上下文不丢关键内容** —— 实测单会话 **3,300+ 条消息、3 亿+ 累计 token**;架构上支持单会话 **10 万条消息**(5 位消息 ID 空间)。
|
|
31
33
|
|
|
32
34
|
---
|
|
33
35
|
|
|
@@ -35,19 +37,18 @@ ACP 将上下文管理的所有权限全部交给模型自己,而不依靠外
|
|
|
35
37
|
|
|
36
38
|
真实工程中的上下文情况。
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
**在 6 个活跃工程会话(11,000+ 次 API 调用)中,上下文 p90 稳定在 15 万–19 万(15–19%),p95 在 16 万–21 万(16–21%)—— 聚合缓存命中率达 91%。**(注意这是平均缓存命中率,不是单会话命中率——后面[对 Prompt 缓存的影响](#对-prompt-缓存的影响)会解释,这实际上比传统压缩算法大幅度节省了 token。)
|
|
41
|
+
|
|
42
|
+
| 会话 | 时长 | 消息数 | API 调用 | 累计 token | 缓存命中率 | 上下文 p50 | 上下文 p90 | 上下文 p95 |
|
|
43
|
+
| --------- | ----------- | ------ | -------- | ---------- | ---------- | ----------- | ----------- | ----------- |
|
|
44
|
+
| 0b89319b | 230h (9.5d) | 3,344 | 2,796 | 3.39 亿 | 93% | 10.8万(11%) | 16.7万(17%) | 21.0万(21%) |
|
|
45
|
+
| 0a3be0cd | 130h (5.4d) | 3,183 | 2,499 | 2.76 亿 | 91% | 10.4万(10%) | 14.5万(15%) | 15.3万(15%) |
|
|
46
|
+
| 0b2cd5a7 | 131h (5.4d) | 2,560 | 2,181 | 3.14 亿 | 91% | 14.2万(14%) | 19.1万(19%) | 19.7万(20%) |
|
|
47
|
+
| 08f2d501 | 37h (1.5d) | 1,985 | 1,888 | 1.96 亿 | 95% | 10.0万(10%) | 15.6万(16%) | 16.8万(17%) |
|
|
48
|
+
| 1410c791† | 865h (36d) | 1,279 | 1,100 | 2.18 亿 | 87% | 13.2万(13%) | 40.7万(41%) | 42.7万(43%) |
|
|
49
|
+
| 096cf8c4 | 72h (3d) | 1,041 | 918 | 0.91 亿 | 89% | 9.2万(9%) | 14.8万(15%) | 16.1万(16%) |
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
| ----------------------- | -------------- | -------------- |
|
|
42
|
-
| **消息总条数** | 3,024 | 2,028 |
|
|
43
|
-
| **累计处理 token** | 5.82 亿 | 4.63 亿 |
|
|
44
|
-
| **prompt-cache 命中率** | 86.2% | 89.0% |
|
|
45
|
-
| **上下文 p50(中位)** | 1.2 K(<1%) | 1.8 K(<1%) |
|
|
46
|
-
| **上下文 p75** | 2.8 K | 3.5 K |
|
|
47
|
-
| **上下文 p90** | 10.8 万(11%) | 5.8 万(6%) |
|
|
48
|
-
| **上下文 p95** | 25.1 万(25%) | 33.5 万(34%) |
|
|
49
|
-
| **上下文 p99** | 42.5 万(43%) | 44.2 万(44%) |
|
|
50
|
-
| **峰值** | 48.8 万(49%) | 76.9 万(77%) |
|
|
51
|
+
† Bug 测试会话,p95 异常偏高。排除该会话后,其余会话 p95 均 ≤ 21 万。
|
|
51
52
|
|
|
52
53
|
(上下文百分比均以 1M 窗口计。)
|
|
53
54
|
|
|
@@ -73,7 +74,7 @@ opencode plugin opencode-acp@latest --global
|
|
|
73
74
|
|
|
74
75
|
## 工作原理
|
|
75
76
|
|
|
76
|
-
ACP
|
|
77
|
+
ACP 把上下文压缩工具直接交给模型。模型对上下文压缩**负全责**。模型的主要工具是 **compress** 和 **decompress**,辅以 **acp_status**(上下文监控)和 **search_context**(搜索已压缩内容)。当上下文达到 100% 时,系统自动触发 GC 截断作为兜底。
|
|
77
78
|
|
|
78
79
|
### 生命周期
|
|
79
80
|
|
|
@@ -108,15 +109,37 @@ stateDiagram-v2
|
|
|
108
109
|
|
|
109
110
|
当上下文达到 100% 时,系统自动截断老年代 block 摘要,防止上下文溢出。这是最后的兜底机制,不影响模型的正常压缩/解压操作。
|
|
110
111
|
|
|
112
|
+
### 质量门控(非阻塞,默认关闭)
|
|
113
|
+
|
|
114
|
+
每次 `compress` 调用之后,ACP 可以运行一个可拔插的质量门控,检测摘要是否灾难性丢失了内容(例如:5K token 的范围被压缩成 147 字符、且不含任何技术关键词的摘要)。失败只发出 `logger.warn`——绝不拒绝压缩(结果已经提交到状态、对模型可见)。
|
|
115
|
+
|
|
116
|
+
默认算法 `rouge-recall-v1` 是基于 6,913 个真实块校准的两层门控:
|
|
117
|
+
|
|
118
|
+
- **L1(长度下限)**:捕获灾难性留存失败——摘要短于 200 字符 OR 留存率低于原始的 1%。100% 召回,0% 误报。
|
|
119
|
+
- **L2(内容覆盖)**:只在通过 L1 的块上运行。当 **同时** ROUGE-1 F1 < 0.05 **且** top-20 关键词召回 < 0.20 时触发(AND 合并使误报率维持在 ~6.6%)。
|
|
120
|
+
|
|
121
|
+
接口可拔插:未来算法(例如通过外部 API 的 LLM-as-judge)可通过 `registerQualityGate()` 注册,无需改动 pipeline 接线。分词器使用手写的词级分词(英文关键词 + 中文 unigram/bigram),不使用 ACP 的 BPE 分词器——后者对 ROUGE 风格的匹配粒度过粗。
|
|
122
|
+
|
|
123
|
+
默认关闭,发布一个版本的烧入期后再开启。启用方式:
|
|
124
|
+
|
|
125
|
+
```jsonc
|
|
126
|
+
{
|
|
127
|
+
"qualityGate": {
|
|
128
|
+
"enabled": true,
|
|
129
|
+
"algorithm": "rouge-recall-v1",
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
111
134
|
---
|
|
112
135
|
|
|
113
136
|
## 对 Prompt 缓存的影响
|
|
114
137
|
|
|
115
|
-
历史上 ACP 修复了大量由 DCP 导致的低缓存命中率问题。目前整体缓存命中率约为 **
|
|
138
|
+
历史上 ACP 修复了大量由 DCP 导致的低缓存命中率问题。目前整体缓存命中率约为 **91%**。
|
|
116
139
|
|
|
117
140
|
相比传统压缩——只在 80–90% 时才压缩,一旦压缩就强制 100% 的上下文重新命中——ACP 的命中率实际上更高。
|
|
118
141
|
|
|
119
|
-
此外:ACP 大部分时间将总上下文维持在 **~
|
|
142
|
+
此外:ACP 大部分时间将总上下文维持在 **~10–15%**(p50 10 万、p90 15 万,以 1M 窗口计),而传统方案是 50–80%。因此总 token 节省远高于传统压缩。
|
|
120
143
|
|
|
121
144
|
**结论:** ACP 在提高整体缓存命中率的同时,确保关键上下文信息不丢失。
|
|
122
145
|
|
|
@@ -182,8 +205,8 @@ ACP 使用自己的配置文件,按以下顺序搜索:
|
|
|
182
205
|
"debug": false,
|
|
183
206
|
// Notification display: "off", "minimal", or "detailed"
|
|
184
207
|
"pruneNotification": "detailed",
|
|
185
|
-
// Notification type: "chat" (
|
|
186
|
-
"pruneNotificationType": "
|
|
208
|
+
// Notification type: "chat" (deprecated, falls back to toast) or "toast" (system toast)
|
|
209
|
+
"pruneNotificationType": "toast",
|
|
187
210
|
// Slash commands configuration
|
|
188
211
|
"commands": {
|
|
189
212
|
"enabled": true,
|
|
@@ -292,6 +315,27 @@ ACP 使用自己的配置文件,按以下顺序搜索:
|
|
|
292
315
|
// 上下文使用率超过此值时执行主 GC(兜底,硬编码为 100%)
|
|
293
316
|
"majorGcThresholdPercent": "100%",
|
|
294
317
|
},
|
|
318
|
+
// 压缩后质量门控(非阻塞;默认关闭)
|
|
319
|
+
"qualityGate": {
|
|
320
|
+
// 主开关。false 时不执行任何评估
|
|
321
|
+
"enabled": false,
|
|
322
|
+
// 算法名。可拔插——未来算法(包括外部 API 评审)可以注册而无需改 pipeline
|
|
323
|
+
"algorithm": "rouge-recall-v1",
|
|
324
|
+
// 各算法的独立配置
|
|
325
|
+
"algorithms": {
|
|
326
|
+
"rouge-recall-v1": {
|
|
327
|
+
// 摘要长度硬下限(字符)。低于此值 → L1 失败
|
|
328
|
+
"layer1MinChars": 200,
|
|
329
|
+
// 最小留存率 = summaryLen / (compressedTokens*4) * 100
|
|
330
|
+
// 捕获灾难性留存失败(<1%),0% 误报
|
|
331
|
+
"layer1MinRetentionPct": 1.0,
|
|
332
|
+
// 当 ROUGE-1 F1 低于此值时(与 top20Recall 经 AND 合并)L2 失败
|
|
333
|
+
"layer2MaxRougeF1": 0.05,
|
|
334
|
+
// 当 top-20 关键词召回低于此值时(与 rougeF1 经 AND 合并)L2 失败
|
|
335
|
+
"layer2MaxTop20Recall": 0.20,
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
},
|
|
295
339
|
}
|
|
296
340
|
```
|
|
297
341
|
|
|
@@ -323,7 +367,7 @@ ACP 暴露六个可编辑的 prompt:
|
|
|
323
367
|
|
|
324
368
|
`commands` 和 `strategies` 中的 `protectedTools` 数组会添加到此默认列表。
|
|
325
369
|
|
|
326
|
-
对于 `compress` 工具,`compress.protectedTools` 确保特定工具的输出被**硬排除**在压缩范围之外(v1.10.0+)。当模型压缩包含受保护工具消息的范围时,该消息完整保留在可见上下文中 —
|
|
370
|
+
对于 `compress` 工具,`compress.protectedTools` 确保特定工具的输出被**硬排除**在压缩范围之外(v1.10.0+)。当模型压缩包含受保护工具消息的范围时,该消息完整保留在可见上下文中 — 只有周围的非受保护消息被压缩。默认仅包含 `skill` —— 实践中这一个就够了,因为 skill 输出是唯一绝不能被压缩丢失的工具类型。
|
|
327
371
|
|
|
328
372
|
---
|
|
329
373
|
|
|
@@ -395,6 +439,35 @@ ACP 在首次启动时自动将配置从 `dcp.jsonc` 迁移到 `acp.jsonc`,将
|
|
|
395
439
|
|
|
396
440
|
## 更新日志
|
|
397
441
|
|
|
442
|
+
### v1.13.1 — cc-alg 抽取 + 压缩通知冻结修复(PR #167, #168)
|
|
443
|
+
|
|
444
|
+
**问题(压缩通知冻结,#167)**:每次 `compress` 工具调用成功后,ACP 会注入一条 user 角色通知消息,其中只包含一个带 `ignored: true` 标记的 text part。opencode 在发送给 LLM 前会剥离 ignored parts,于是这条消息变成空 user 消息。Provider(zhipuai-lb / glm-5.2)会以 HTTP 400 code 1214(`"messages 参数非法"`)拒绝,且 `isRetryable: false`——opencode 不会重试,会话冻结,直到外部恢复。所有活跃会话累计发生 113 次(单个 3,156 条消息的会话出现 8 次)。
|
|
445
|
+
|
|
446
|
+
**修复(压缩通知冻结,#167)**:(1)`lib/ui/notification.ts:280-298`——`sendCompressNotification` 改为始终调用 `client.tui.showToast`;移除了原本调用 `sendIgnoredMessage` 的 `chat` 分支。当用户显式配置 `pruneNotificationType: "chat"` 时,输出一次 warn 日志以便发现行为变化。(2)`lib/messages/utils.ts:232-269`——`dropEmptyMessages` 现在将带 `ignored: true` 的 text part 也视为"可丢弃",任何未来出现的 ignored-only user 消息会在到达 provider 之前被丢弃(纵深防御)。(3)`lib/config.ts:175`——默认 `pruneNotificationType` 从 `"chat"` 改为 `"toast"`,使用默认配置的用户不会看到弃用警告。
|
|
447
|
+
|
|
448
|
+
**问题(cc-alg 抽取,#168)**:可复用的压缩算法(ROUGE-1 质量门控、手写 tokenizer、trigger policy、compression-rules prompt)锁在 ACP 的 AGPL 代码库里,其他项目无法以 MIT 协议复用。算法模块与 ACP 管道的内部耦合也使独立测试和复用困难。
|
|
449
|
+
|
|
450
|
+
**修复(cc-alg 抽取,#168)**:4 个模块抽取到独立 MIT 包 `context-compress-algorithms@1.0.0`(npm:https://www.npmjs.com/package/context-compress-algorithms,GitHub:https://github.com/ranxianglei/context-compress-algorithms)。ACP 通过 `^1.0.0` 引用,并用 tsup `noExternal` 把 cc-alg inline-bundle 进 `dist/index.js`,host 不需要安装额外依赖。新增 `NOTICE` 文件按开源合规要求随包发布 MIT 归属。新增 `lib/messages/inject/policy/` 注册表支持 host 端自定义 nudge trigger 行为(默认 policy 来自 cc-alg 的 `defaultTriggerPolicy`)。Provenance 审计确认对 DCP 上游(AGPL-3.0)零 derivation——在 DCP 仓库搜索 `rouge` / `qualityGate` / `computeShouldNudge` / `HOW_TO_COMPRESS_RULES` 均为 0 hit,MIT 抽取法律安全。AGENTS.md 新增 Git 安全规则:非 release 分支禁止修改 `version` 字段,避免今后版本号再次被改乱。
|
|
451
|
+
|
|
452
|
+
文件(压缩通知):`lib/ui/notification.ts`、`lib/messages/utils.ts`、`lib/config.ts`、`tests/drop-empty-messages.test.ts`。
|
|
453
|
+
文件(cc-alg 抽取):`lib/compress/quality-gate/tokenizer.ts`(删除)、`lib/compress/quality-gate/algorithms/rouge-recall-v1.ts`(删除)、`lib/prompts/compression-rules.ts`(删除)、`lib/compress/quality-gate/{index,algorithms/index}.ts`(从 cc-alg re-export,向后兼容)、`lib/messages/inject/{inject,utils}.ts`、`lib/messages/inject/policy/{types,registry,index}.ts`(新增)、`lib/prompts/{system,context-limit-nudge,turn-nudge,iteration-nudge}.ts`、`package.json`、`tsup.config.ts`、`NOTICE`(新增)、`AGENTS.md`。测试:`tests/quality-gate-tokenizer.test.ts`(删除,迁到 cc-alg)、`tests/quality-gate-rouge-recall-v1.test.ts`(删除,迁到 cc-alg——55 个测试迁移)、`tests/quality-gate-pipeline-integration.test.ts`(改用 inline stub gate)、`tests/trigger-policy-integration.test.ts`(新增)。794 个测试通过(cc-alg 自身在独立仓库有 95 个测试)。
|
|
454
|
+
|
|
455
|
+
### v1.13.0 — 可拔插质量门控(Issue #20)
|
|
456
|
+
|
|
457
|
+
**问题**:ACP 没有机制检测摘要是否灾难性丢失了内容。模型可能把 5K token 的范围压缩成 147 字符、且不含任何技术关键词的摘要,系统也会默默接受。Issue #20(基于真实会话的 6,913 个块校准)识别出两种不同的失败模式:(1) 长度下限失败——摘要 < 原始的 1%(通过简单的字符计数即可 100% 召回,0% 误报);(2) 内容覆盖失败——摘要长度足够通过长度门,但没有捕获原始内容中的任何关键词(例如:5K token 原始内容的 996 字符摘要只恢复了 0.6% 的内容词)。
|
|
458
|
+
|
|
459
|
+
**修复**:在 `lib/compress/quality-gate/` 下添加可拔插的 `qualityGate` 子系统,定义 `QualityGate` 接口(`name`、`version`、`description`、`evaluate(ctx, config)`)。pipeline 在 `finalizeSession()` 中状态保存之后调用 `evaluateBatchQuality()`——失败仅发出 `logger.warn`(非阻塞:压缩结果已经提交)。默认算法 `rouge-recall-v1` 是两层门控:L1 是长度/留存下限(200 字符 AND 1% 留存),L2 是 ROUGE-1 F1 < 0.05 与 top-20 关键词召回 < 0.20 的 AND 合并(AND 把误报率维持在 ~6.6%,同时仍能捕获"长但空"的失败模式)。分词器为手写的词级分词(英文关键词 ≥4 字符 + 中文 unigram/bigram),与 ACP 的 BPE 分词器分离——后者对 ROUGE 匹配粒度过粗。配置默认 `enabled: false`,发布一个版本的烧入期。接口为未来算法留出空间,包括外部 API 评审(当前为同步签名;未来异步门控需要扩展类型或在内部 wait+timeout 包装,registry/config 不变)。
|
|
460
|
+
|
|
461
|
+
文件:`lib/compress/quality-gate/{types,registry,tokenizer,evaluate,index}.ts`、`lib/compress/quality-gate/algorithms/{rouge-recall-v1,index}.ts`、`lib/compress/pipeline.ts`、`lib/config.ts`、`lib/config-validation.ts`、`dcp.schema.json`。测试:`tests/quality-gate-{tokenizer,registry,rouge-recall-v1,pipeline-integration}.test.ts`(新增,74 个测试)。842 个测试通过。
|
|
462
|
+
|
|
463
|
+
### v1.12.11 — README 文档刷新(PR #164)
|
|
464
|
+
|
|
465
|
+
**问题**:README 文档与代码实际脱节。tagline 没有突出 ACP 的核心能力。英文版的 "Deletion strategy" 章节描述了一个已不存在的功能,且与中文版不一致。缓存命中率和上下文使用率数据过期(87%、~30%)。`compress.protectedTools` 默认值文档列出了 5 个工具(`task, skill, todowrite, todoread, decompress`),但代码实际默认值只有 `skill`。
|
|
466
|
+
|
|
467
|
+
**修复**:(1)新增 `<strong>20 万 token 足矣。</strong>` tagline。(2)"Proven at scale" 表格更新为 6 个活跃会话的真实 API 级数据(运行时长、消息数、API 调用数、累计 token、缓存命中率、P50/P90/P95),离群值标注。(3)英文版 "Deletion strategy" 替换为 "GC safety net",与中文版 "GC 兜底" 一致。(4)"工作原理" 列出 `acp_status` 和 `search_context` 为辅助工具。(5)缓存统计更新:87% → 91%,上下文 ~30% → ~10–15%(1M 窗口的 p50 10 万、p90 15 万)。(6)`compress.protectedTools` 默认值文档更正为仅 `skill`(匹配 `lib/config.ts:121` 的 `COMPRESS_DEFAULT_PROTECTED_TOOLS`)。
|
|
468
|
+
|
|
469
|
+
文件:`README.md`、`README.zh-CN.md`。无代码改动。测试:768 通过(不变)。
|
|
470
|
+
|
|
398
471
|
### v1.12.10 — 批量压缩 + Decompress 范围模式 + GC 记忆丢失修复 + Token 分类 + Nudge 质量(PR #73, #155, #156, #157, #158, #159, #161)
|
|
399
472
|
|
|
400
473
|
**问题**:七个问题,涉及压缩 UX、token 统计、GC 安全和 nudge 质量。(1)`decompress` 需要先 `acp_status` 再逐块 decompress 的循环才能恢复多个压缩块。(2)自 v1.12.9 起,compress 工具的 `summary` 内容被错误分类为 `toolTokens` 而非 `summaryTokens`,导致上下文分布中 tool% 虚高、summary% 虚低。(3)`compress` 工具每次调用只能压缩一个范围 —— 模型需要多次调用才能压缩不相关的范围,浪费轮次。(4)`[PROTECTED: ...]` 标签列出受保护消息中的所有工具而非仅触发保护的工具。(5)当所有可见内容都是受保护内容时,nudge 仍然以空推荐列表注入。(6)当 nudge 被抑制时,下一轮检查每轮都重新评估。(7)**GC 系统在静默销毁模型编写的 summary**:任何 `summary.length > 6000` 字符的块在零上下文压力下被强制截断到 3000,且 `survivedCount` 过高的块被自动 deactivate —— 导致数百个会话的不可恢复记忆丢失。
|
|
@@ -542,6 +615,7 @@ Issue #23(上下文内存泄露)的综合修复。7 个 commit,22 个文
|
|
|
542
615
|
#### 工具结果注入 — 修复 #20 & #78(PR #95)
|
|
543
616
|
|
|
544
617
|
**问题**:压缩摘要以文本形式的 `role:assistant` 或 `role:user` 消息注入。两种角色都会误导模型:
|
|
618
|
+
|
|
545
619
|
- `role:assistant`(Bug 37 路径)→ 模型将摘要当作自己的前文,逐字复读(#20,GLM-5.2)。
|
|
546
620
|
- `role:user`(Bug 36 合并路径)→ 模型将摘要当作用户指令,去执行旧话题(#78,gpt-5.5)。
|
|
547
621
|
|