billion-context-omp 0.1.0 → 0.1.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/README.md +168 -30
- package/README.zh-CN.md +168 -30
- package/dist/auto-compress.d.ts +65 -0
- package/dist/commands.d.ts +8 -0
- package/dist/compat.d.ts +24 -0
- package/dist/compress-tool.d.ts +27 -0
- package/dist/config.d.ts +92 -0
- package/dist/decompress-tool.d.ts +15 -0
- package/dist/dump.d.ts +22 -0
- package/dist/footer-status.d.ts +2 -0
- package/dist/home.d.ts +2 -0
- package/dist/index.d.ts +5 -59
- package/dist/index.js +4755 -43
- package/dist/index.js.map +1 -1
- package/dist/log.d.ts +21 -0
- package/dist/messages.d.ts +54 -0
- package/dist/runtime.d.ts +34 -0
- package/dist/search-index.d.ts +18 -0
- package/dist/search-tool.d.ts +11 -0
- package/dist/status-tool.d.ts +17 -0
- package/dist/system-prompt.d.ts +2 -0
- package/dist/tokens.d.ts +16 -0
- package/dist/tool-guardrails.d.ts +13 -0
- package/dist/update.d.ts +2 -0
- package/dist/user-config.d.ts +26 -0
- package/package.json +74 -65
package/README.md
CHANGED
|
@@ -1,61 +1,199 @@
|
|
|
1
|
+
# billion-context-omp
|
|
2
|
+
|
|
1
3
|
[English](./README.md) | [中文](./README.zh-CN.md)
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>Billion-Context</strong> for <a href="https://github.com/can1357/oh-my-pi">omp (oh-my-pi)</a>
|
|
7
|
+
<br />
|
|
8
|
+
The model decides <em>when</em> and <em>what</em> to compress — not a hard limit.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="https://www.npmjs.com/package/billion-context-omp"><img src="https://img.shields.io/npm/v/billion-context-omp.svg?style=flat-square" alt="npm"></a>
|
|
15
|
+
<a href="https://github.com/ranxianglei/billion-context-omp/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/billion-context-omp.svg?style=flat-square" alt="license"></a>
|
|
16
|
+
<a href="https://github.com/ranxianglei/billion-context-omp"><img src="https://img.shields.io/badge/GitHub-ranxianglei%2Fbillion--context--omp-181717?style=flat-square&logo=github" alt="GitHub"></a>
|
|
17
|
+
</p>
|
|
4
18
|
|
|
5
|
-
|
|
19
|
+
<p align="center">
|
|
20
|
+
<code>omp install billion-context-omp</code>
|
|
21
|
+
</p>
|
|
6
22
|
|
|
7
|
-
|
|
23
|
+
---
|
|
8
24
|
|
|
9
|
-
|
|
10
|
-
> Wire them to omp's actual provider/`base_url` config shape as you build it out.
|
|
25
|
+
## Why?
|
|
11
26
|
|
|
12
|
-
|
|
27
|
+
When conversations get long, the model runs out of context. Most tools hard-truncate — silently dropping earlier messages. **billion-context** gives the model a `compress` tool: the LLM decides **when** and **what** to compress into high-fidelity summaries, preserving critical details (file paths, decisions, error strings) while reclaiming context space.
|
|
13
28
|
|
|
14
|
-
|
|
29
|
+
Unlike omp's built-in auto-compaction (which replaces everything with a single summary), billion-context:
|
|
30
|
+
- **Preserves structure** — compressed ranges become labeled blocks you can decompress later
|
|
31
|
+
- **Multi-tier** — summaries can be further distilled (T1 → T2 → T3) as sessions grow
|
|
32
|
+
- **Searchable** — `search_context` finds information inside compressed blocks without decompressing
|
|
33
|
+
- **Selective** — protected tools, user messages, and the recent working set are never compressed
|
|
15
34
|
|
|
16
|
-
|
|
35
|
+
This means:
|
|
36
|
+
|
|
37
|
+
1. **A single session handles enormous workloads.** Per simulation tests of the three-tier architecture (see [opencode-acp](https://github.com/ranxianglei/opencode-acp)), one session can process on the order of 10–60 billion cumulative tokens — while retaining long-term memory of distant key information (paths, decisions, signatures). You can work in the **same session for months** without outgrowing the context.
|
|
38
|
+
2. **Context stays lean over the long run.** In practice context typically holds under ~150K tokens (opencode-acp keeps it under ~200K), so compared to traditional compaction that lets context balloon toward 1M, **a single session costs roughly 5× less in tokens**.
|
|
17
39
|
|
|
18
40
|
## Install
|
|
19
41
|
|
|
20
42
|
```bash
|
|
21
|
-
|
|
43
|
+
omp install billion-context-omp
|
|
22
44
|
```
|
|
23
45
|
|
|
24
|
-
|
|
46
|
+
That's it. The extension auto-loads on next omp startup. No configuration needed — it reads your model's context window automatically.
|
|
47
|
+
|
|
48
|
+
Or add it to your omp settings (`~/.omp/agent/settings.json` or project `.omp/settings.json`):
|
|
25
49
|
|
|
26
|
-
```
|
|
27
|
-
|
|
50
|
+
```jsonc
|
|
51
|
+
{
|
|
52
|
+
"extensions": ["billion-context-omp"]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
28
55
|
|
|
29
|
-
|
|
56
|
+
## How it works
|
|
30
57
|
|
|
31
|
-
|
|
32
|
-
omp.buildBaseUrl('https://api.openai.com/v1');
|
|
33
|
-
// => 'http://localhost:8787/bili/https://api.openai.com/v1'
|
|
58
|
+
billion-context intercepts omp's `context` event (fired before each LLM call) and runs the acp-kernel pipeline:
|
|
34
59
|
|
|
35
|
-
// Detect an already-routed URL (use to self-disable / avoid double compression):
|
|
36
|
-
omp.isBiliBaseUrl('http://localhost:8787/bili/https://api.openai.com/v1'); // => true
|
|
37
60
|
```
|
|
61
|
+
assign refs → fold in-stream compress calls → prune → nudge → emergency truncate
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Each message gets an invisible `<acp>` ref tag (`m00001`, `m00002`, ...) visible to the model but not the user. The model uses these refs to specify compression ranges.
|
|
38
65
|
|
|
39
|
-
|
|
66
|
+
**The session stream is the single source of truth.** Compress calls live in the stream itself: every compress tool call's arguments (ranges + summaries) are re-applied deterministically on each LLM call, on restart, and on resume — no sidecar state file to drift out of sync. Position ids (`p1..pN`) and model-facing refs (`m00001..`) are re-derived from the stream every turn; prefix rewrites (retry, rewind, host compaction) are detected and safely re-folded, with fingerprint guards against replaying a call onto the wrong messages.
|
|
40
67
|
|
|
41
|
-
|
|
68
|
+
omp's built-in `/compact` is intercepted and replaced by an ACP model-summarized compaction that also preserves prior compress-call summaries — nothing is lost to the gap between the summary and the kept entries.
|
|
69
|
+
|
|
70
|
+
## Plugin compatibility
|
|
71
|
+
|
|
72
|
+
**Keep exactly one context-compression plugin installed.** If two compression extensions both rewrite the message list, they clobber each other's work — compressed ranges can be re-expanded or corrupted. omp's own `/compact` is already intercepted automatically by billion-context-omp, but any *third-party* compression/compaction extension should be uninstalled.
|
|
73
|
+
|
|
74
|
+
## Model-facing tools
|
|
75
|
+
|
|
76
|
+
| Tool | What it does |
|
|
77
|
+
|------|-------------|
|
|
78
|
+
| `compress` | Replace a contiguous message range with a detailed summary |
|
|
79
|
+
| `decompress` | Restore a previously compressed block's content (to file by default; `inline:true` for single messages) |
|
|
80
|
+
| `search_context` | Search compressed block summaries (and visible messages) by keyword |
|
|
81
|
+
| `acp_status` | Show context usage, compressed blocks, compressible ranges |
|
|
82
|
+
|
|
83
|
+
> The `acp_delegate` sub-agent subsystem from the Pi build is intentionally **not** registered — omp ships its own multi-agent orchestration, and duplicate delegation tools would conflict.
|
|
84
|
+
|
|
85
|
+
## `/acp` command
|
|
86
|
+
|
|
87
|
+
Rich status display for the user:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
╭─────────────────────────────────────────────╮
|
|
91
|
+
│ ACP Context Analysis │
|
|
92
|
+
╰─────────────────────────────────────────────╯
|
|
93
|
+
billion-context-omp@0.1.1
|
|
94
|
+
|
|
95
|
+
Context: 6% (57k / 1.0M)
|
|
96
|
+
|
|
97
|
+
Token Breakdown:
|
|
98
|
+
SysPrompt ██░░░░░░░░░░░░░░░░░░ 10% 5.9k
|
|
99
|
+
Framework ██████████████████░░ 90% 51k
|
|
100
|
+
|
|
101
|
+
Nudge: idle — max compressible 0 < threshold 20000; growth 0 < floor 20000
|
|
102
|
+
|
|
103
|
+
Blocks: 2 active / 2 total (21k tokens compressed)
|
|
104
|
+
[b1] T1 5.1k→1.0k: Fold architecture port
|
|
105
|
+
[b2] T1 15k→799: Replay guard hardening
|
|
106
|
+
|
|
107
|
+
Tag visibility: tags injected to LLM only (deep copy), not persisted in session, not shown in terminal.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Configuration
|
|
111
|
+
|
|
112
|
+
billion-context-omp works out of the box with no configuration. Optional keys can be set in a JSON config file.
|
|
113
|
+
|
|
114
|
+
### Config file
|
|
115
|
+
|
|
116
|
+
Create `~/.omp/acp-omp.json` (global) and/or `<project>/.omp/acp-omp.json` (project-local, overrides global):
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"debug": false,
|
|
121
|
+
"autoUpdate": true,
|
|
122
|
+
"modelContextLimit": 200000,
|
|
123
|
+
"compressModel": "zhipuai:glm-5.2",
|
|
124
|
+
"toolBashDefaultTimeout": 60,
|
|
125
|
+
"toolOutputMaxBytes": 200000,
|
|
126
|
+
"compress": {
|
|
127
|
+
"maxContextLimit": "75%",
|
|
128
|
+
"emergencyThresholdPercent": "95%",
|
|
129
|
+
"nudgeGrowthTokens": 50000
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
"prompts": {
|
|
133
|
+
"compressPhilosophy": "Override the compression philosophy...",
|
|
134
|
+
"howToCompressRules": "Override tier-1 rules...",
|
|
135
|
+
"tier2DistillRules": "Override tier-2 distillation rules...",
|
|
136
|
+
"tier3CondenseRules": "Override tier-3 condensation rules..."
|
|
137
|
+
},
|
|
138
|
+
"acknowledgePromptsRisk": true
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
| Key | Default | Description |
|
|
143
|
+
|-----|---------|-------------|
|
|
144
|
+
| `debug` | `false` | Enable verbose **debug-level** events in the log. The always-on log (lifecycle events, errors, warnings) is written regardless; `debug` only adds extra diagnostics. Also enabled by env `ACP_DEBUG=1`. |
|
|
145
|
+
| `autoUpdate` | `true` | On session start (throttled to one check per 3 minutes), check npm for a newer version and auto-install it. Disable to avoid all startup network calls. |
|
|
146
|
+
| `modelContextLimit` | *(auto)* | Override the context limit (in tokens). Defaults to the model's `contextWindow`. |
|
|
147
|
+
| `compressModel` | *(session model)* | `provider:modelId` used for `/compact` model-summarized compaction (e.g. `"zhipuai:glm-5.2"`). Defaults to the current session model when omitted. |
|
|
148
|
+
| `toolBashDefaultTimeout` | `60` | Seconds injected into the `bash` tool when the model omits `timeout`. Without this a forgotten timeout can hang for thousands of seconds. `0` restores unbounded behavior. |
|
|
149
|
+
| `toolOutputMaxBytes` | `200000` | Hard byte cap on tool result text (applied via the `tool_result` hook). Stops runaway output that omp's own caps can't catch. When it fires the model is told where the full output lives; set lower (e.g. `8192`) for a tighter context budget, or `0` to disable. |
|
|
150
|
+
| `compress.maxContextLimit` | `"75%"` | Context usage threshold that triggers **forced compression** nudges (bypasses growth-gate + cadence). Accepts a ratio (`0.75`) or percent string (`"75%"`). Lower = compress earlier / more aggressively. |
|
|
151
|
+
| `compress.emergencyThresholdPercent` | `"95%"` | Context usage threshold that triggers **emergency truncation** of large tool outputs to keep the session alive. Must be ≥ `maxContextLimit`. |
|
|
152
|
+
| `compress.nudgeGrowthTokens` | `50000` | Token growth step for soft compression nudges. A nudge fires roughly every time this many tokens become compressible; if the model ignores it, it re-fires after the same amount of further growth. Lower = compress more often. |
|
|
153
|
+
| `prompts` | *(kernel defaults)* | Override acp-kernel's 4 load-bearing compression prompt rules (`compressPhilosophy`, `howToCompressRules`, `tier2DistillRules`, `tier3CondenseRules`). Each set field replaces the default verbatim; omitted fields are inherited. Requires `acknowledgePromptsRisk: true`. |
|
|
154
|
+
| `acknowledgePromptsRisk` | `false` | Safety gate for `prompts` overrides. Set `true` to acknowledge that replacing the tuned compression rules may reduce summary quality, and to make overrides take effect. |
|
|
155
|
+
|
|
156
|
+
The three nudge thresholds (`maxContextLimit`, `emergencyThresholdPercent`, `nudgeGrowthTokens`) form a three-tier escalation: growth-driven soft nudges → forced nudges at `maxContextLimit` → emergency truncation at `emergencyThresholdPercent`.
|
|
157
|
+
|
|
158
|
+
### Environment variables
|
|
159
|
+
|
|
160
|
+
| Variable | Effect |
|
|
161
|
+
|----------|--------|
|
|
162
|
+
| `ACP_AUTO_UPDATE` | Set to `0` / `false` / `no` / `off` (case-insensitive) to disable auto-update, overriding the config. |
|
|
163
|
+
| `ACP_MODEL_CONTEXT_LIMIT` | Override the context limit. Takes precedence over the config value. |
|
|
164
|
+
| `ACP_DEBUG` | Set to `1` or `true` to enable debug-level logging (always-on events are written regardless). |
|
|
165
|
+
| `ACP_LOG_FILE` | Override the log file path (default `~/.omp/acp-omp.log`). |
|
|
166
|
+
|
|
167
|
+
### Logging
|
|
168
|
+
|
|
169
|
+
billion-context-omp writes a structured, always-on log to `~/.omp/acp-omp.log` (override with `ACP_LOG_FILE`). It covers the model's whole working session and is useful for diagnosing problems:
|
|
170
|
+
|
|
171
|
+
- **Always written** (even with `debug: false`): `error`, `warn`, `info` levels — session start, every context turn (token usage / nudge decision), compress/decompress, and **all errors and warnings**. Error lines include the message and stack trace.
|
|
172
|
+
- **Written only when `debug: true`**: verbose `debug`-level diagnostics (full field dumps, per-turn internals, fold/replay events).
|
|
173
|
+
|
|
174
|
+
Each line: `<ISO timestamp> [<level>] [<scope>] key=value key=value`. The file rotates to `~/.omp/acp-omp.log.old` at 10 MB.
|
|
175
|
+
|
|
176
|
+
```sh
|
|
177
|
+
tail -f ~/.omp/acp-omp.log # watch the session live
|
|
178
|
+
grep '\[error\]' ~/.omp/acp-omp.log # surface every recorded failure
|
|
179
|
+
```
|
|
42
180
|
|
|
43
|
-
|
|
44
|
-
| ---------- | -------- | ---------------------------------------- |
|
|
45
|
-
| `endpoint` | `string` | Origin of a running billion-context proxy. |
|
|
181
|
+
### Compression philosophy
|
|
46
182
|
|
|
47
|
-
|
|
183
|
+
The model receives detailed guidance (in its system prompt) on **when** to compress, **what** to keep verbatim (paths, signatures, errors, decisions, user intent), and **what** to drop (verbose logs, duplicates, consumed exploration). This guidance is injected on every turn so it stays in the model's attention.
|
|
48
184
|
|
|
49
|
-
|
|
185
|
+
### What gets protected
|
|
50
186
|
|
|
51
|
-
|
|
187
|
+
billion-context protects three categories of content from compression:
|
|
52
188
|
|
|
53
|
-
|
|
189
|
+
1. **Always-protected tools** — `compress` calls are hard-protected (they're load-bearing metadata; compressing them breaks decompress and the "summary is historical" contract).
|
|
190
|
+
2. **Soft recent-zone** — the last N messages (default 5) and last ~5K tokens are soft-protected so the model keeps its working set. Tool results from `decompress`, `search_context`, `read`, and `bash` are **excluded** from this zone: they're large and meant to be compressible once consumed.
|
|
191
|
+
3. **Last user message** — always protected (user intent must survive).
|
|
54
192
|
|
|
55
|
-
|
|
193
|
+
## Built on acp-kernel
|
|
56
194
|
|
|
57
|
-
|
|
195
|
+
The compression engine is [`acp-kernel`](https://github.com/ranxianglei/acp-kernel) — a platform-agnostic, MIT-licensed library. It's bundled inline into `dist/index.js`, so there are zero runtime dependencies.
|
|
58
196
|
|
|
59
197
|
## License
|
|
60
198
|
|
|
61
|
-
MIT ©
|
|
199
|
+
MIT © ranxianglei
|
package/README.zh-CN.md
CHANGED
|
@@ -2,60 +2,198 @@
|
|
|
2
2
|
|
|
3
3
|
# billion-context-omp
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
面向 <a href="https://github.com/can1357/oh-my-pi">omp (oh-my-pi)</a> 的 <strong>Billion-Context</strong>
|
|
7
|
+
<br />
|
|
8
|
+
由模型决定<em>何时</em>压缩、<em>压缩什么</em> —— 而不是硬截断。
|
|
9
|
+
</p>
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
---
|
|
8
12
|
|
|
9
|
-
>
|
|
10
|
-
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="https://www.npmjs.com/package/billion-context-omp"><img src="https://img.shields.io/npm/v/billion-context-omp.svg?style=flat-square" alt="npm"></a>
|
|
15
|
+
<a href="https://github.com/ranxianglei/billion-context-omp/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/billion-context-omp.svg?style=flat-square" alt="license"></a>
|
|
16
|
+
<a href="https://github.com/ranxianglei/billion-context-omp"><img src="https://img.shields.io/badge/GitHub-ranxianglei%2Fbillion--context--omp-181717?style=flat-square&logo=github" alt="GitHub"></a>
|
|
17
|
+
</p>
|
|
11
18
|
|
|
12
|
-
|
|
19
|
+
<p align="center">
|
|
20
|
+
<code>omp install billion-context-omp</code>
|
|
21
|
+
</p>
|
|
13
22
|
|
|
14
|
-
|
|
23
|
+
---
|
|
15
24
|
|
|
16
|
-
|
|
25
|
+
## 为什么?
|
|
26
|
+
|
|
27
|
+
会话变长后,模型的上下文会耗尽。多数工具采用硬截断——悄悄丢弃早期消息。**billion-context** 给模型一个 `compress` 工具:由 LLM 自己决定**何时**压缩、**压缩什么**,生成高保真摘要,保留关键细节(文件路径、决策、报错原文)的同时回收上下文空间。
|
|
28
|
+
|
|
29
|
+
与 omp 内置的自动 compaction(把一切都换成一条摘要)不同,billion-context:
|
|
30
|
+
- **保留结构** —— 被压缩的区间变成带标签的块,之后可以解压还原
|
|
31
|
+
- **多层蒸馏** —— 摘要可随会话增长继续蒸馏(T1 → T2 → T3)
|
|
32
|
+
- **可搜索** —— `search_context` 不解压即可在压缩块摘要中检索信息
|
|
33
|
+
- **有选择性** —— 受保护工具、用户消息、近期工作集永不被压缩
|
|
34
|
+
|
|
35
|
+
这意味着:
|
|
36
|
+
|
|
37
|
+
1. **单个会话可以承载巨大的工作量。** 三层架构的模拟测试(见 [opencode-acp](https://github.com/ranxianglei/opencode-acp))显示,一个会话可处理 100~600 亿累计 token——同时保持对早期关键信息(路径、决策、签名)的长期记忆。你可以在**同一个会话里工作数月**而不会撑爆上下文。
|
|
38
|
+
2. **上下文长期保持精瘦。** 实际运行中上下文通常保持在 ~150K token 以下(opencode-acp 控制在 ~200K 以下)。相比放任上下文膨胀到 1M 的传统 compaction,**单个会话的 token 成本约低 5 倍**。
|
|
17
39
|
|
|
18
40
|
## 安装
|
|
19
41
|
|
|
20
42
|
```bash
|
|
21
|
-
|
|
43
|
+
omp install billion-context-omp
|
|
22
44
|
```
|
|
23
45
|
|
|
24
|
-
|
|
46
|
+
就这一步。扩展在下次 omp 启动时自动加载,无需任何配置——它自动读取模型的上下文窗口。
|
|
25
47
|
|
|
26
|
-
|
|
27
|
-
import { BillionContextOmp } from 'billion-context-omp';
|
|
48
|
+
或加入 omp 设置(`~/.omp/agent/settings.json` 或项目级 `.omp/settings.json`):
|
|
28
49
|
|
|
29
|
-
|
|
50
|
+
```jsonc
|
|
51
|
+
{
|
|
52
|
+
"extensions": ["billion-context-omp"]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
30
55
|
|
|
31
|
-
|
|
32
|
-
omp.buildBaseUrl('https://api.openai.com/v1');
|
|
33
|
-
// => 'http://localhost:8787/bili/https://api.openai.com/v1'
|
|
56
|
+
## 工作原理
|
|
34
57
|
|
|
35
|
-
|
|
36
|
-
|
|
58
|
+
billion-context 拦截 omp 的 `context` 事件(每次 LLM 调用前触发)并运行 acp-kernel 管线:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
分配 ref → 折叠流内 compress 调用 → 剪枝 → 提醒 → 紧急截断
|
|
37
62
|
```
|
|
38
63
|
|
|
39
|
-
|
|
64
|
+
每条消息获得一个模型可见、用户不可见的 `<acp>` ref 标签(`m00001`、`m00002`、...)。模型用这些 ref 指定压缩区间。
|
|
65
|
+
|
|
66
|
+
**会话流是唯一真相源。** compress 调用本身就存在于流中:每次 compress 工具调用的参数(区间 + 摘要)在每次 LLM 调用、重启、resume 时被确定性重放——没有会漂移失步的独立状态文件。位置 id(`p1..pN`)和面向模型的 ref(`m00001..`)每轮从流重新推导;前缀改写(retry、rewind、宿主 compaction)会被检测并安全重折叠,指纹守卫防止把调用重放到错误的消息上。
|
|
67
|
+
|
|
68
|
+
omp 内置的 `/compact` 被拦截,替换为 ACP 模型摘要式 compaction,它同时保留之前的 compress 调用摘要——摘要与保留条目之间的空隙不会丢任何东西。
|
|
69
|
+
|
|
70
|
+
## 插件兼容性
|
|
71
|
+
|
|
72
|
+
**只安装一个上下文压缩插件。** 若两个压缩扩展都改写消息列表,它们会互相破坏对方的工作——被压缩的区间可能被重新展开或损坏。omp 自己的 `/compact` 已被 billion-context-omp 自动拦截,但任何*第三方*压缩/compaction 扩展都应卸载。
|
|
73
|
+
|
|
74
|
+
## 面向模型的工具
|
|
75
|
+
|
|
76
|
+
| 工具 | 作用 |
|
|
77
|
+
|------|------|
|
|
78
|
+
| `compress` | 把一段连续消息区间替换为详细摘要 |
|
|
79
|
+
| `decompress` | 恢复之前压缩的块内容(默认写文件;单条消息可 `inline:true`) |
|
|
80
|
+
| `search_context` | 按关键字搜索压缩块摘要(及可见消息) |
|
|
81
|
+
| `acp_status` | 显示上下文用量、压缩块、可压缩区间 |
|
|
82
|
+
|
|
83
|
+
> Pi 版中的 `acp_delegate` 子代理系统在此**有意不注册**——omp 自带多代理编排,重复的委派工具会冲突。
|
|
84
|
+
|
|
85
|
+
## `/acp` 命令
|
|
86
|
+
|
|
87
|
+
面向用户的富状态面板:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
╭─────────────────────────────────────────────╮
|
|
91
|
+
│ ACP Context Analysis │
|
|
92
|
+
╰─────────────────────────────────────────────╯
|
|
93
|
+
billion-context-omp@0.1.1
|
|
40
94
|
|
|
41
|
-
|
|
95
|
+
Context: 6% (57k / 1.0M)
|
|
96
|
+
|
|
97
|
+
Token Breakdown:
|
|
98
|
+
SysPrompt ██░░░░░░░░░░░░░░░░░░ 10% 5.9k
|
|
99
|
+
Framework ██████████████████░░ 90% 51k
|
|
100
|
+
|
|
101
|
+
Nudge: idle — max compressible 0 < threshold 20000; growth 0 < floor 20000
|
|
102
|
+
|
|
103
|
+
Blocks: 2 active / 2 total (21k tokens compressed)
|
|
104
|
+
[b1] T1 5.1k→1.0k: Fold architecture port
|
|
105
|
+
[b2] T1 15k→799: Replay guard hardening
|
|
106
|
+
|
|
107
|
+
Tag visibility: tags injected to LLM only (deep copy), not persisted in session, not shown in terminal.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 配置
|
|
111
|
+
|
|
112
|
+
billion-context-omp 开箱即用,无需配置。可选键写入 JSON 配置文件。
|
|
113
|
+
|
|
114
|
+
### 配置文件
|
|
115
|
+
|
|
116
|
+
创建 `~/.omp/acp-omp.json`(全局)和/或 `<项目>/.omp/acp-omp.json`(项目级覆盖全局):
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"debug": false,
|
|
121
|
+
"autoUpdate": true,
|
|
122
|
+
"modelContextLimit": 200000,
|
|
123
|
+
"compressModel": "zhipuai:glm-5.2",
|
|
124
|
+
"toolBashDefaultTimeout": 60,
|
|
125
|
+
"toolOutputMaxBytes": 200000,
|
|
126
|
+
"compress": {
|
|
127
|
+
"maxContextLimit": "75%",
|
|
128
|
+
"emergencyThresholdPercent": "95%",
|
|
129
|
+
"nudgeGrowthTokens": 50000
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
"prompts": {
|
|
133
|
+
"compressPhilosophy": "覆盖压缩哲学...",
|
|
134
|
+
"howToCompressRules": "覆盖 tier-1 规则...",
|
|
135
|
+
"tier2DistillRules": "覆盖 tier-2 蒸馏规则...",
|
|
136
|
+
"tier3CondenseRules": "覆盖 tier-3 凝缩规则..."
|
|
137
|
+
},
|
|
138
|
+
"acknowledgePromptsRisk": true
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
| 键 | 默认 | 说明 |
|
|
143
|
+
|-----|------|------|
|
|
144
|
+
| `debug` | `false` | 开启**debug 级**详细日志事件。常开日志(生命周期事件、错误、警告)无论如何都会写;`debug` 只增加诊断信息。也可用环境变量 `ACP_DEBUG=1` 开启。 |
|
|
145
|
+
| `autoUpdate` | `true` | 会话启动时(节流为每 3 分钟最多一次)检查 npm 是否有新版本并自动安装。关闭可避免所有启动期网络请求。 |
|
|
146
|
+
| `modelContextLimit` | *(自动)* | 覆盖上下文上限(token 数)。默认取模型的 `contextWindow`。 |
|
|
147
|
+
| `compressModel` | *(会话模型)* | `/compact` 模型摘要式压缩使用的 `provider:modelId`(如 `"zhipuai:glm-5.2"`)。缺省用当前会话模型。 |
|
|
148
|
+
| `toolBashDefaultTimeout` | `60` | 模型省略 `timeout` 时注入 `bash` 工具的秒数。没有它,一次忘记的 timeout 可能挂起数千秒。`0` 恢复无限制。 |
|
|
149
|
+
| `toolOutputMaxBytes` | `200000` | 工具结果文本的硬字节上限(经 `tool_result` 钩子实施)。拦截 omp 自身上限管不住的失控输出。触发时模型会被告知完整输出在哪;调低(如 `8192`)可更省上下文,`0` 禁用。 |
|
|
150
|
+
| `compress.maxContextLimit` | `"75%"` | 触发**强制压缩**提醒的上下文用量阈值(绕过增长门控与节拍)。接受比例(`0.75`)或百分比字符串(`"75%"`)。越低 = 越早/越激进压缩。 |
|
|
151
|
+
| `compress.emergencyThresholdPercent` | `"95%"` | 触发**紧急截断**(截断失控工具输出以保住会话)的上下文用量阈值。必须 ≥ `maxContextLimit`。 |
|
|
152
|
+
| `compress.nudgeGrowthTokens` | `50000` | 软压缩提醒的 token 增长步长。每积累约这么多可压缩 token 就提醒一次;模型无视则再增长同等数量后重新提醒。越低 = 越常压缩。 |
|
|
153
|
+
| `prompts` | *(kernel 默认)* | 覆盖 acp-kernel 的 4 条承重压缩提示规则(`compressPhilosophy`、`howToCompressRules`、`tier2DistillRules`、`tier3CondenseRules`)。每个设置的字段逐字替换默认值;未设置的字段继承默认。需要 `acknowledgePromptsRisk: true`。 |
|
|
154
|
+
| `acknowledgePromptsRisk` | `false` | `prompts` 覆盖的安全门。设 `true` 表示知悉替换调优过的压缩规则可能降低摘要质量,并使覆盖生效。 |
|
|
155
|
+
|
|
156
|
+
三个提醒阈值(`maxContextLimit`、`emergencyThresholdPercent`、`nudgeGrowthTokens`)构成三级升级:增长驱动的软提醒 → `maxContextLimit` 处的强制提醒 → `emergencyThresholdPercent` 处的紧急截断。
|
|
157
|
+
|
|
158
|
+
### 环境变量
|
|
159
|
+
|
|
160
|
+
| 变量 | 效果 |
|
|
161
|
+
|------|------|
|
|
162
|
+
| `ACP_AUTO_UPDATE` | 设为 `0` / `false` / `no` / `off`(不区分大小写)禁用自动更新,覆盖配置。 |
|
|
163
|
+
| `ACP_MODEL_CONTEXT_LIMIT` | 覆盖上下文上限。优先于配置值。 |
|
|
164
|
+
| `ACP_DEBUG` | 设为 `1` 或 `true` 开启 debug 级日志(常开事件无论如何都写)。 |
|
|
165
|
+
| `ACP_LOG_FILE` | 覆盖日志文件路径(默认 `~/.omp/acp-omp.log`)。 |
|
|
166
|
+
|
|
167
|
+
### 日志
|
|
168
|
+
|
|
169
|
+
billion-context-omp 向 `~/.omp/acp-omp.log`(可用 `ACP_LOG_FILE` 覆盖)写入结构化的常开日志,覆盖模型整个工作会话,适合诊断问题:
|
|
170
|
+
|
|
171
|
+
- **始终写入**(即使 `debug: false`):`error`、`warn`、`info` 级——会话启动、每个 context 轮次(token 用量/提醒决策)、压缩/解压,以及**全部错误和警告**。错误行含消息与堆栈。
|
|
172
|
+
- **仅在 `debug: true` 时写入**:冗长的 `debug` 级诊断(完整字段转储、每轮内部状态、折叠/重放事件)。
|
|
173
|
+
|
|
174
|
+
每行格式:`<ISO 时间戳> [<级别>] [<作用域>] key=value key=value`。文件在 10 MB 时轮转为 `~/.omp/acp-omp.log.old`。
|
|
175
|
+
|
|
176
|
+
```sh
|
|
177
|
+
tail -f ~/.omp/acp-omp.log # 实时观察会话
|
|
178
|
+
grep '\[error\]' ~/.omp/acp-omp.log # 列出所有已记录的失败
|
|
179
|
+
```
|
|
42
180
|
|
|
43
|
-
|
|
44
|
-
| ---------- | -------- | --------------------------------- |
|
|
45
|
-
| `endpoint` | `string` | 运行中的 billion-context 代理地址。 |
|
|
181
|
+
### 压缩哲学
|
|
46
182
|
|
|
47
|
-
|
|
183
|
+
模型(在其系统提示中)收到详细指引:**何时**压缩、**什么**必须逐字保留(路径、签名、报错、决策、用户意图)、**什么**该丢弃(冗长日志、重复内容、已消费的探索)。该指引每轮注入,保持在模型注意力内。
|
|
48
184
|
|
|
49
|
-
|
|
185
|
+
### 受保护的内容
|
|
50
186
|
|
|
51
|
-
|
|
187
|
+
billion-context 保护三类内容不被压缩:
|
|
52
188
|
|
|
53
|
-
|
|
189
|
+
1. **永久保护的工具** —— `compress` 调用被硬保护(它们是承重元数据;压缩它们会破坏 decompress 与"摘要属于历史"的契约)。
|
|
190
|
+
2. **软性近期区** —— 最后 N 条消息(默认 5 条)与最后约 5K token 被软保护,模型保持工作集。`decompress`、`search_context`、`read`、`bash` 的工具结果**排除**在该区之外:它们体量大、消费后本就该可压缩。
|
|
191
|
+
3. **最后一条用户消息** —— 永久保护(用户意图必须存活)。
|
|
54
192
|
|
|
55
|
-
|
|
193
|
+
## 基于 acp-kernel
|
|
56
194
|
|
|
57
|
-
|
|
195
|
+
压缩引擎是 [`acp-kernel`](https://github.com/ranxianglei/acp-kernel)——平台无关的 MIT 库。它被内联打包进 `dist/index.js`,因此零运行时依赖。
|
|
58
196
|
|
|
59
|
-
##
|
|
197
|
+
## 许可
|
|
60
198
|
|
|
61
|
-
MIT ©
|
|
199
|
+
MIT © ranxianglei
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { complete } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import type { ExtensionContext } from "@oh-my-pi/pi-coding-agent";
|
|
3
|
+
import { type CoreMessage, type CompressionState, type CompressibleRange, type Prompts } from "acp-kernel";
|
|
4
|
+
import { type AgentMessage } from "./messages.js";
|
|
5
|
+
/** Reads `compressModel` from `~/.<CONFIG_DIR_NAME>/acp-omp.json as `provider:modelId`. */
|
|
6
|
+
export declare function readCompressModel(): string | null;
|
|
7
|
+
export declare function resolveCompressModel<T extends {
|
|
8
|
+
provider: string;
|
|
9
|
+
id: string;
|
|
10
|
+
}>(registry: {
|
|
11
|
+
find(provider: string, modelId: string): T | undefined;
|
|
12
|
+
}, currentModel: T | undefined, configured: string | null): {
|
|
13
|
+
model: T;
|
|
14
|
+
label: string;
|
|
15
|
+
} | null;
|
|
16
|
+
export declare function sliceRange(messages: CoreMessage[], state: CompressionState, startRef: string, endRef: string): CoreMessage[];
|
|
17
|
+
/** Pick the compressible span to compress. The kernel's recommended ranges are
|
|
18
|
+
* small groups (split at user boundaries and protected gaps) that routinely
|
|
19
|
+
* fall below `minCompressRange`, which the kernel would reject. Seed on the
|
|
20
|
+
* largest range and expand to adjacent ranges (smallest gap first) until the
|
|
21
|
+
* span covers enough text — counting every message in the span, matching the
|
|
22
|
+
* kernel's own validation. Returns null when even the whole compressible set
|
|
23
|
+
* is below the threshold. */
|
|
24
|
+
export declare function selectRangeSpan(ranges: CompressibleRange[], messages: CoreMessage[], state: CompressionState, minChars: number): {
|
|
25
|
+
startRef: string;
|
|
26
|
+
endRef: string;
|
|
27
|
+
tokens: number;
|
|
28
|
+
} | null;
|
|
29
|
+
export declare function formatSlice(slice: CoreMessage[], state: CompressionState): string;
|
|
30
|
+
export declare function parseSummary(text: string): string | null;
|
|
31
|
+
/** Build the summary-generation system prompt FROM the kernel's load-bearing
|
|
32
|
+
* compression rules (the same `Prompts` the compress tool and tier-1
|
|
33
|
+
* compression use), so /compact honors `acp-omp.json` prompt overrides and stays
|
|
34
|
+
* consistent with the rest of the ACP pipeline. `/compact` compresses an old
|
|
35
|
+
* contiguous range, so the tier-1 `howToCompressRules` are the right rule
|
|
36
|
+
* set (not tier-2/tier-3 distillation rules). */
|
|
37
|
+
export declare function buildSummaryPrompt(prompts: Prompts): string;
|
|
38
|
+
/** Generate ONE summary covering the FULL set of messages omp is about to
|
|
39
|
+
* discard on /compact (messagesToSummarize + turnPrefixMessages), matching
|
|
40
|
+
* native compaction semantics — the compaction entry omp stores afterwards
|
|
41
|
+
* is the durable record, and it truncates everything before firstKeptEntryId
|
|
42
|
+
* from the LLM view, so the summary must cover all of it. Kernel blocks are
|
|
43
|
+
* deliberately NOT used here: fold blocks only replay from in-stream
|
|
44
|
+
* compress tool calls, which the truncation removes. `previousSummary` (an
|
|
45
|
+
* earlier compaction's summary) is folded in so iterative compactions never
|
|
46
|
+
* drop it. Returns null on any failure so the caller falls back to Pi's
|
|
47
|
+
* native compaction. */
|
|
48
|
+
export declare function summarizeMessages(ctx: ExtensionContext, messages: AgentMessage[], prompts: Prompts, configuredModel?: string | null, opts?: {
|
|
49
|
+
previousSummary?: string;
|
|
50
|
+
customInstructions?: string;
|
|
51
|
+
signal?: AbortSignal;
|
|
52
|
+
completeFn?: typeof complete;
|
|
53
|
+
}): Promise<{
|
|
54
|
+
summary: string;
|
|
55
|
+
model: string;
|
|
56
|
+
} | null>;
|
|
57
|
+
/** Generate a summary for a message range using the compression model. Shared
|
|
58
|
+
* entry point for the `/compact` handler. Returns null when no model is
|
|
59
|
+
* usable, the slice is empty, the model is unauthenticated, or the response
|
|
60
|
+
* is unparseable — the caller then returns `undefined` so Pi falls back to
|
|
61
|
+
* its native compaction. */
|
|
62
|
+
export declare function summarizeRange(ctx: ExtensionContext, messages: CoreMessage[], state: CompressionState, startRef: string, endRef: string, prompts: Prompts, configuredModel?: string | null): Promise<{
|
|
63
|
+
summary: string;
|
|
64
|
+
model: string;
|
|
65
|
+
} | null>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RegisteredCommand } from "@oh-my-pi/pi-coding-agent";
|
|
2
|
+
import type { AcpRuntime } from "./runtime.js";
|
|
3
|
+
type CommandOptions = Omit<RegisteredCommand, "name" | "sourceInfo">;
|
|
4
|
+
export declare function makeCommands(runtime: AcpRuntime): Array<{
|
|
5
|
+
name: string;
|
|
6
|
+
options: CommandOptions;
|
|
7
|
+
}>;
|
|
8
|
+
export {};
|
package/dist/compat.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ExtensionContext } from "@oh-my-pi/pi-coding-agent";
|
|
2
|
+
/**
|
|
3
|
+
* Host compatibility layer for pi vs omp (oh-my-pi) API differences.
|
|
4
|
+
*
|
|
5
|
+
* pi: systemPrompt is string, getSystemPrompt() returns string
|
|
6
|
+
* omp: systemPrompt is string[], getSystemPrompt() returns string[]
|
|
7
|
+
*
|
|
8
|
+
* These helpers normalize the differences so the rest of the codebase
|
|
9
|
+
* can work with a consistent string interface.
|
|
10
|
+
*/
|
|
11
|
+
/** Normalize systemPrompt to a single string (join with newlines if array). */
|
|
12
|
+
export declare function normalizeSystemPrompt(input: string | string[] | undefined): string;
|
|
13
|
+
/**
|
|
14
|
+
* Format systemPrompt for the before_agent_start event handler.
|
|
15
|
+
* omp's BeforeAgentStartEventResult.systemPrompt is string[]: each entry is a
|
|
16
|
+
* prompt segment. We normalize the incoming base (string | string[]) to one
|
|
17
|
+
* string, append the ACP block, and return it as a single-element array.
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatSystemPromptForEvent(base: string | string[], append: string): string[];
|
|
20
|
+
/**
|
|
21
|
+
* Get the system prompt as a single string, regardless of host type.
|
|
22
|
+
* Handles both pi (string) and omp (string[]) return types.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getSystemPromptText(ctx: ExtensionContext): string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ToolDefinition } from "@oh-my-pi/pi-coding-agent";
|
|
2
|
+
import type { AcpRuntime } from "./runtime.js";
|
|
3
|
+
/** Label shown for a block when the model did not pass a topic: first
|
|
4
|
+
* sentence-ish slice of the summary (≤30 chars). Decorative only — never
|
|
5
|
+
* blocks compression. */
|
|
6
|
+
export declare function topicFallback(summary: string): string;
|
|
7
|
+
declare const CompressParams: import("@oh-my-pi/omptype").FluentType<{
|
|
8
|
+
content: {
|
|
9
|
+
endId: string;
|
|
10
|
+
startId: string;
|
|
11
|
+
summary: string;
|
|
12
|
+
topic?: string | undefined;
|
|
13
|
+
}[];
|
|
14
|
+
summaryMaxChars?: number | undefined;
|
|
15
|
+
topic?: string | undefined;
|
|
16
|
+
}, {
|
|
17
|
+
content: {
|
|
18
|
+
endId: string;
|
|
19
|
+
startId: string;
|
|
20
|
+
summary: string;
|
|
21
|
+
topic?: string | undefined;
|
|
22
|
+
}[];
|
|
23
|
+
summaryMaxChars?: number | undefined;
|
|
24
|
+
topic?: string | undefined;
|
|
25
|
+
}>;
|
|
26
|
+
export declare function makeCompressTool(runtime: AcpRuntime): ToolDefinition<typeof CompressParams>;
|
|
27
|
+
export {};
|