billion-context-pi 0.1.69 → 0.1.70-pr.243.243
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 +19 -1
- package/README.zh-CN.md +19 -1
- package/dist/absorb-tool.d.ts +9 -0
- package/dist/compress-tool.d.ts +4 -3
- package/dist/config.d.ts +34 -0
- package/dist/index.js +622 -53
- package/dist/index.js.map +1 -1
- package/dist/rollover.d.ts +54 -0
- package/dist/runtime.d.ts +14 -0
- package/dist/setup-subagent-tools.d.ts +11 -0
- package/dist/state.d.ts +3 -0
- package/dist/system-prompt.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,6 +79,8 @@ That's it. The extension auto-loads on next Pi startup. No configuration needed
|
|
|
79
79
|
> **Using another sub-agent extension?** billion-context-pi ships its own `acp_delegate` sub-agent tool (see below) at a fraction of the context cost (~600 tok vs ~7K tok/turn). Two delegation tools in one session only make the model's choice noisier, so pick one:
|
|
80
80
|
> - **Use ACP's delegate** — remove the other extension: `pi remove npm:pi-subagents`
|
|
81
81
|
> - **Keep your own sub-agent** — turn ACP's delegate off in `acp.json`: `{ "delegate": false }` (see *Using your own sub-agent instead* below)
|
|
82
|
+
>
|
|
83
|
+
> If you keep `pi-subagents` installed, billion-context-pi detects it at session start: a **project-level** install (`<cwd>/.pi/npm` or the project extensions dir) automatically stands `acp_delegate` down for that project — a reminder then tells you how to give pi-subagents' agents ACP compression via `/acp-subagents`. A **user-level-only** install (`~/.pi/npm`, user extensions dir) leaves `acp_delegate` active and logs a warning instead. Set `"delegate": { "forceEnable": true }` in `acp.json` to keep `acp_delegate` active regardless of detection.
|
|
82
84
|
|
|
83
85
|
## How it works
|
|
84
86
|
|
|
@@ -92,6 +94,19 @@ Each message gets an invisible `<acp>` ref tag (`m00001`, `m00002`, ...) visible
|
|
|
92
94
|
|
|
93
95
|
Pi's built-in auto-compaction is cancelled — billion-context is the sole context manager.
|
|
94
96
|
|
|
97
|
+
## Batch rollover — Prompt Cache stability
|
|
98
|
+
|
|
99
|
+
The dominant cost of in-place compression is not the summary's output tokens — it is the **prompt-cache invalidation**: rewriting history mid-stream evicts the entire suffix after the compression point from the provider's cache prefix, and every later round re-pays full price for it.
|
|
100
|
+
|
|
101
|
+
Batch rollover mode (on by default) makes the model-visible history **append-only within a phase**:
|
|
102
|
+
|
|
103
|
+
- `compress` validates its ranges immediately but only **records** them as pending — the range stays visible.
|
|
104
|
+
- `absorb` distills a large tool result into a summary you write; the original stays visible until the batch applies.
|
|
105
|
+
- When context usage crosses the rollover threshold (default **70%**, below the 75% forced-nudge band), all pending work is applied in **one** rewrite — one cache invalidation, amortized over the whole phase — and a one-shot `▣ ACP rollover | ...` report is appended.
|
|
106
|
+
- `decompress` / `search_context` results land at the tail of the history; the prefix is never touched.
|
|
107
|
+
|
|
108
|
+
Pending work shows up in `acp_status` and survives restarts; `/acp-rollover` forces the batch early. Set `"rollover": false` in `acp.json` to restore the legacy immediate-compression behavior. See [CONFIGURATION.md](./CONFIGURATION.md#rollover-prompt-cache-stability) for the trade-off and thresholds.
|
|
109
|
+
|
|
95
110
|
## Plugin compatibility & ordering
|
|
96
111
|
|
|
97
112
|
billion-context takes over context management by intercepting Pi's `context` event. **Pi has no plugin priority mechanism** — when multiple extensions register handlers for the same event, they run in a fixed sequence (load order), with no `priority`/`weight` field and no way for the user to control the order. The `context` event specifically is a *pipeline*: every handler receives the previous handler's output, there is no short-circuit, and the **last** handler has the final say over what reaches the model.
|
|
@@ -124,7 +139,8 @@ billion-context-pi is built for the **Pi** coding agent (`@earendil-works/pi-cod
|
|
|
124
139
|
|
|
125
140
|
| Tool | What it does |
|
|
126
141
|
|------|-------------|
|
|
127
|
-
| `compress` | Replace a contiguous message range with a detailed summary |
|
|
142
|
+
| `compress` | Replace a contiguous message range with a detailed summary (deferred to the next rollover in batch mode) |
|
|
143
|
+
| `absorb` | Distill a large tool result into a compact summary; the original is dropped at the next rollover |
|
|
128
144
|
| `decompress` | Restore a previously compressed block's content |
|
|
129
145
|
| `search_context` | Search compressed block summaries (and visible messages) by keyword |
|
|
130
146
|
| `acp_status` | Show context usage, compressed blocks, compressible ranges |
|
|
@@ -198,6 +214,8 @@ Blocks: 3 active (3.7K summary, 15.2K original compressed)
|
|
|
198
214
|
b3 (T2) 3.3K→1.0K age=1m "Architecture review"
|
|
199
215
|
```
|
|
200
216
|
|
|
217
|
+
In batch rollover mode the status also shows pending work (`Rollover: N pending compression(s) + M absorb(s) — ~X tokens pending (threshold 70%, current Y%)`), and `/acp-rollover` applies the pending batch immediately instead of waiting for the threshold.
|
|
218
|
+
|
|
201
219
|
## `/acp-subagents` command
|
|
202
220
|
|
|
203
221
|
**Optional, one-time setup — only if you also use [pi-subagents](https://github.com/nicobailon/pi-subagents).**
|
package/README.zh-CN.md
CHANGED
|
@@ -78,6 +78,8 @@ pi install npm:billion-context-pi
|
|
|
78
78
|
> **你另有子代理扩展?** billion-context-pi 自带 `acp_delegate` 子代理工具(见下文),上下文成本极低(~600 tok vs ~7K tok/轮)。同一会话里两套委派工具只会让模型的选择更混乱,二选一:
|
|
79
79
|
> - **用 ACP 的 delegate** —— 卸载另一个扩展:`pi remove npm:pi-subagents`
|
|
80
80
|
> - **保留你自己的子代理** —— 在 `acp.json` 里关掉 ACP 的 delegate:`{ "delegate": false }`(见下文*改用你自己的子代理*)
|
|
81
|
+
>
|
|
82
|
+
> 若保留已安装的 `pi-subagents`,billion-context-pi 会在会话启动时检测:**项目级**安装(`<cwd>/.pi/npm` 或项目内 extensions 目录)会自动停用该项目的 `acp_delegate`,并提醒你运行 `/acp-subagents` 让 pi-subagents 的子代理获得 ACP 压缩;仅**用户级**(全局)安装时只记一条警告日志,`acp_delegate` 保持启用。在 `acp.json` 中设置 `"delegate": { "forceEnable": true }` 可在检测到第三方子代理时仍强制保留 `acp_delegate`。
|
|
81
83
|
|
|
82
84
|
## 工作原理
|
|
83
85
|
|
|
@@ -91,6 +93,19 @@ assign refs → sync blocks → prune → filter → hide calls → recommend
|
|
|
91
93
|
|
|
92
94
|
Pi 内置的自动压缩会被取消 —— billion-context 是唯一的上下文管理者。
|
|
93
95
|
|
|
96
|
+
## 批量 rollover —— Prompt Cache 稳定性
|
|
97
|
+
|
|
98
|
+
就地压缩的主要成本不是摘要的 output tokens,而是 **Prompt Cache 失效**:在历史中间改写会把压缩点之后的整个后缀踢出 provider 的缓存前缀,之后每一轮都要按全价重算这段 input。
|
|
99
|
+
|
|
100
|
+
批量 rollover 模式(默认开启)让 model-visible history 在阶段内 **append-only**:
|
|
101
|
+
|
|
102
|
+
- `compress` 立即校验范围(坏范围仍然当场报错),但只把范围**记录**为 pending —— 原文保持可见。
|
|
103
|
+
- `absorb` 把大型工具输出蒸馏成你写的摘要;原文保持可见,直到批量生效。
|
|
104
|
+
- 当上下文用量越过 rollover 阈值(默认 **70%**,低于 75% 强制 nudge 带)时,所有 pending 工作**一次性**应用 —— 一次缓存失效,摊薄到整个阶段 —— 并追加一条一次性的 `▣ ACP rollover | ...` 报告。
|
|
105
|
+
- `decompress` / `search_context` 的结果落在历史尾部,前缀永不被触碰。
|
|
106
|
+
|
|
107
|
+
pending 工作会显示在 `acp_status` 中,并跨重启持久化;`/acp-rollover` 可立即强制批量生效。在 `acp.json` 中设置 `"rollover": false` 可恢复旧的就地立即压缩行为。权衡与阈值详见 [CONFIGURATION.zh-CN.md](./CONFIGURATION.zh-CN.md#rollover-prompt-cache-稳定性)。
|
|
108
|
+
|
|
94
109
|
## 插件兼容性与排序
|
|
95
110
|
|
|
96
111
|
billion-context 通过拦截 Pi 的 `context` 事件接管上下文管理。**Pi 没有插件优先级机制** —— 当多个扩展为同一个事件注册 handler 时,它们按固定顺序(加载顺序)执行,没有 `priority`/`weight` 字段,用户也无法控制顺序。`context` 事件尤其是一个*管线*:每个 handler 都接收上一个 handler 的输出,没有短路,**最后一个** handler 对发给模型的内容拥有最终决定权。
|
|
@@ -123,7 +138,8 @@ billion-context-pi 面向 **Pi** 编码代理(`@earendil-works/pi-coding-agent`)
|
|
|
123
138
|
|
|
124
139
|
| 工具 | 作用 |
|
|
125
140
|
|------|------|
|
|
126
|
-
| `compress` | 用详细摘要替换连续的消息范围 |
|
|
141
|
+
| `compress` | 用详细摘要替换连续的消息范围(批量模式下延迟到下一次 rollover 生效) |
|
|
142
|
+
| `absorb` | 把大型工具输出蒸馏成你写的紧凑摘要;原文在下一次 rollover 时移除 |
|
|
127
143
|
| `decompress` | 恢复之前压缩的块内容 |
|
|
128
144
|
| `search_context` | 按关键词搜索已压缩块摘要(及可见消息) |
|
|
129
145
|
| `acp_status` | 显示上下文用量、已压缩块、可压缩范围 |
|
|
@@ -196,6 +212,8 @@ Blocks: 3 active (3.7K summary, 15.2K original compressed)
|
|
|
196
212
|
b3 (T2) 3.3K→1.0K age=1m "Architecture review"
|
|
197
213
|
```
|
|
198
214
|
|
|
215
|
+
批量 rollover 模式下,状态面板还会显示 pending 工作(`Rollover: N pending compression(s) + M absorb(s) — ~X tokens pending (threshold 70%, current Y%)`),`/acp-rollover` 可立即应用 pending 批量,而不必等待阈值。
|
|
216
|
+
|
|
199
217
|
## `/acp-subagents` 命令
|
|
200
218
|
|
|
201
219
|
**可选、一次性设置——仅当你同时使用 [pi-subagents](https://github.com/nicobailon/pi-subagents) 时需要。**
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import type { AcpRuntime } from "./runtime.js";
|
|
4
|
+
declare const AbsorbParams: Type.TObject<{
|
|
5
|
+
ref: Type.TString;
|
|
6
|
+
summary: Type.TString;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function makeAbsorbTool(runtime: AcpRuntime): ToolDefinition<typeof AbsorbParams>;
|
|
9
|
+
export {};
|
package/dist/compress-tool.d.ts
CHANGED
|
@@ -29,9 +29,10 @@ export declare function tailRepair(s: string): string | undefined;
|
|
|
29
29
|
* index/floor-stale) and the #376 "… blocks: b3=m00044–m00097*, …" form. */
|
|
30
30
|
export declare function compressPanelBlocks(text: string): number;
|
|
31
31
|
/** Success = completed run that created >= 1 block (partial range errors
|
|
32
|
-
* still count: progress was made)
|
|
33
|
-
*
|
|
34
|
-
*
|
|
32
|
+
* still count: progress was made), OR a rollover-mode panel that recorded
|
|
33
|
+
* ranges as pending (work was accepted — the retry counter resets). A
|
|
34
|
+
* 0-block panel must NOT be success — it would reset the retry counter
|
|
35
|
+
* while the emergency nudge re-fires, looping no-op compressions (issue #6). */
|
|
35
36
|
export declare function isCompressSuccessText(text: string): boolean;
|
|
36
37
|
/** No-op = completed run that compressed nothing (0-block panel: every
|
|
37
38
|
* range skipped). Counted as a FAILED attempt by noteCompressOutcomes so
|
package/dist/config.d.ts
CHANGED
|
@@ -29,6 +29,13 @@ export interface DelegateConfig {
|
|
|
29
29
|
/** Enable acp_delegate tools (delegate/wait/cancel) and their system-prompt
|
|
30
30
|
* section. Default: true. Set `enabled: false` to skip registering them. */
|
|
31
31
|
enabled?: boolean;
|
|
32
|
+
/** Keep acp_delegate active even when a third-party subagent extension
|
|
33
|
+
* (pi-subagents) is installed. Default: false — when pi-subagents is
|
|
34
|
+
* detected at session start, acp_delegate stands down (tools, fleet
|
|
35
|
+
* shortcut and system-prompt section skipped) to avoid two overlapping
|
|
36
|
+
* sub-agent systems, and a reminder points at /acp-subagents so the
|
|
37
|
+
* third-party agents can still get ACP compression tools (#415). */
|
|
38
|
+
forceEnable?: boolean;
|
|
32
39
|
/** How delegate usage is reported back to the main session.
|
|
33
40
|
* "separate" (default) — delegate tokens tracked in a separate accumulator;
|
|
34
41
|
* main session totals stay clean, delegate usage shows as its own block in
|
|
@@ -89,6 +96,9 @@ export interface DelegateConfig {
|
|
|
89
96
|
* corresponding timeout/watchdog is disabled. */
|
|
90
97
|
export interface DelegatePolicy {
|
|
91
98
|
enabled: boolean;
|
|
99
|
+
/** Resolved delegate.forceEnable (default false): keep acp_delegate even
|
|
100
|
+
* when a third-party subagent extension (pi-subagents) is installed (#415). */
|
|
101
|
+
forceEnable: boolean;
|
|
92
102
|
displayUsage: "merged" | "separate";
|
|
93
103
|
maxDepth: number;
|
|
94
104
|
syncTimeoutMs: number | null;
|
|
@@ -143,6 +153,20 @@ export interface CompressSettings {
|
|
|
143
153
|
* definitions freeze at extension load, before the model is known). */
|
|
144
154
|
promptPack?: string;
|
|
145
155
|
}
|
|
156
|
+
/** Batch rollover tuning (Prompt Cache stability, #241). Deferred compress /
|
|
157
|
+
* absorb work is applied in one batch when the calibrated sent-view usage
|
|
158
|
+
* crosses `threshold` (or via `/acp rollover`), so the model-visible history
|
|
159
|
+
* stays append-only within a phase and the cache prefix is rewritten once
|
|
160
|
+
* per rollover instead of once per compression. */
|
|
161
|
+
export interface RolloverConfig {
|
|
162
|
+
/** Enable batch rollover mode. Default: true. Set `false` (or
|
|
163
|
+
* `rollover: false`) to restore the legacy immediate-compression behavior. */
|
|
164
|
+
enabled?: boolean;
|
|
165
|
+
/** Context usage percentage that triggers a rollover. Accepts a ratio (0.7)
|
|
166
|
+
* or percent string ("70%"). Default: 0.70 — below the 0.75 forced-nudge
|
|
167
|
+
* band so pending work is reclaimed before nudges start. */
|
|
168
|
+
threshold?: number | string;
|
|
169
|
+
}
|
|
146
170
|
/** Per-provider compression overrides. Carries the same tuning fields as the
|
|
147
171
|
* global level, plus an optional per-model map keyed by model id. */
|
|
148
172
|
export interface ProviderCompress extends CompressSettings {
|
|
@@ -274,6 +298,10 @@ export interface AdapterConfig {
|
|
|
274
298
|
* replacing the kernel's tuned compression rules may reduce summary quality
|
|
275
299
|
* (lost paths/signatures/decisions → worse retrieval). */
|
|
276
300
|
acknowledgePromptsRisk?: boolean;
|
|
301
|
+
/** Batch rollover mode (Prompt Cache stability, #241). Accepts a boolean
|
|
302
|
+
* shorthand (`false` disables) or a RolloverConfig object. Default: enabled
|
|
303
|
+
* at a 0.70 usage threshold. */
|
|
304
|
+
rollover?: boolean | RolloverConfig;
|
|
277
305
|
/** Override structural sections of the ACP system prompt (ACP TAGS, TOOLS,
|
|
278
306
|
* WHEN TO COMPRESS, ...). Tri-state per section: string = replace, null =
|
|
279
307
|
* remove, omitted = default. Not risk-gated — these are documentation
|
|
@@ -327,6 +355,12 @@ export interface ResolvedHostSession {
|
|
|
327
355
|
* fall back to the pi-native default (off) with a logged warning — they never
|
|
328
356
|
* fail the session. */
|
|
329
357
|
export declare function resolveHostSession(adapter: AdapterConfig): ResolvedHostSession;
|
|
358
|
+
/** Resolve rollover config from the adapter, handling the boolean shorthand.
|
|
359
|
+
* Default: enabled at a 0.70 usage threshold. */
|
|
360
|
+
export declare function resolveRollover(adapter: AdapterConfig): {
|
|
361
|
+
enabled: boolean;
|
|
362
|
+
threshold: number;
|
|
363
|
+
};
|
|
330
364
|
/** Per-field deepest-wins merge of the three compression levels (global →
|
|
331
365
|
* provider → model). An undefined field at a deeper level does NOT clear a
|
|
332
366
|
* value set at a shallower level — only a defined value overrides. */
|