billion-context-pi 0.1.68 → 0.1.69-pr.416.231

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 CHANGED
@@ -10,6 +10,16 @@ The model decides <em>when</em> and <em>what</em> to compress — not a hard lim
10
10
 
11
11
  ---
12
12
 
13
+ ## 📄 Paper / Preprint
14
+
15
+ - **[Model-Driven Incremental Hierarchical Compression: Training-Free Multi-Generational Context Management for Long-Lived Coding Agents](./paper/model-driven-incremental-hierarchical-compression-training-free-multi-generational-context-management-for-long-lived-coding-agents.md)** (English, v0.2)
16
+
17
+ > 📝 **The paper itself is open-sourced under the MIT License as part of the codebase (`paper/`). It is a living document — anyone may edit it; improvements are welcome via pull request.**
18
+
19
+ A production-scale longitudinal study: 4.5 months, three hosts, 174,327 model calls, 18.76B cumulative input tokens (~24.7B across all hosts), zero window violations on 204,800-token models, marathon sessions of 8,584–12,049 calls.
20
+
21
+ ---
22
+
13
23
  <p align="center">
14
24
  <a href="https://www.npmjs.com/package/billion-context-pi"><img src="https://img.shields.io/npm/v/billion-context-pi.svg?style=flat-square" alt="npm"></a>
15
25
  <a href="https://github.com/ranxianglei/billion-context-pi/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/billion-context-pi.svg?style=flat-square" alt="license"></a>
@@ -66,10 +76,11 @@ pi install npm:billion-context-pi
66
76
 
67
77
  That's it. The extension auto-loads on next Pi startup. No configuration needed — it reads your model's context window automatically.
68
78
 
69
- > **Uninstall `pi-subagents` first (optional, recommended).** billion-context-pi ships its own `acp_delegate` sub-agent tool (see below) that replaces pi-subagents at a fraction of the context cost (~600 tok vs ~7K tok/turn). If you have pi-subagents installed, remove it to avoid duplicate delegation tools:
70
- > ```bash
71
- > pi remove npm:pi-subagents
72
- > ```
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
+ > - **Use ACP's delegate** — remove the other extension: `pi remove npm:pi-subagents`
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.
73
84
 
74
85
  ## How it works
75
86
 
@@ -123,6 +134,8 @@ billion-context-pi is built for the **Pi** coding agent (`@earendil-works/pi-cod
123
134
  | `acp_delegate_wait` | Block until a delegate run finishes (returns its result; times out otherwise) |
124
135
  | `acp_delegate_cancel` | Cancel a running delegate by runId |
125
136
 
137
+ The four `acp_delegate*` tools are optional: if you bring your own sub-agent extension, disable them with one `acp.json` key — see *Using your own sub-agent instead* below.
138
+
126
139
  ### acp_delegate — clean-context delegation
127
140
 
128
141
  Hand a self-contained task to a fresh pi process running in a clean context. Five built-in roles, each with a system prompt and a **soft tool guardrail**:
@@ -147,6 +160,20 @@ The full delegate result is saved to a file (`/tmp/acp-delegate/<runId>.out`); t
147
160
 
148
161
  In the **interactive TUI**, async runs also show a live status widget below the editor (agent, elapsed seconds, task preview), so you always know what's running and for how long. Disabled automatically in RPC/print/JSON.
149
162
 
163
+ #### Using your own sub-agent instead
164
+
165
+ If you already run another sub-agent extension (pi-subagents, pi-lens, …), turn ACP's delegate off so the model is offered only one way to delegate. In `~/.pi/acp.json` (global) or `<project>/.pi/acp.json` (per project):
166
+
167
+ ```json
168
+ { "delegate": false }
169
+ ```
170
+
171
+ - Equivalent object form: `{ "delegate": { "enabled": false } }`.
172
+ - **What it removes:** the `acp_delegate`, `acp_delegate_wait` and `acp_delegate_cancel` tools, the `ACP_DELEGATE NOTIFICATIONS` system-prompt section, and the `ctrl+alt+f` fleet shortcut (`/acp-fleet` then reports that delegate is off). Compression is unaffected — `compress`, `decompress`, `search_context` and `acp_status` stay.
173
+ - **When it applies:** the three tools are registered at session start, so a change needs a **new session** (or a Pi restart). The system-prompt section is resolved live on every turn, so it can disappear mid-session before the tools do.
174
+ - Want to drop only the prompt section and keep the tools? Set `{ "delegatePrompt": null }`.
175
+ - Pi's `--exclude-tools acp_delegate,acp_delegate_wait,acp_delegate_cancel` is **not** a substitute: it hides the tools but the model still receives the `ACP_DELEGATE NOTIFICATIONS` section describing tools it cannot call. Use `delegate: false`.
176
+
150
177
  ## `/acp` command
151
178
 
152
179
  Rich status display for the user:
package/README.zh-CN.md CHANGED
@@ -8,6 +8,16 @@
8
8
 
9
9
  ---
10
10
 
11
+ ## 📄 论文 / 预印本
12
+
13
+ - **[模型驱动的分层增量压缩:面向长寿命编码 Agent 的免训练多代上下文管理](./paper/模型驱动的分层增量压缩-免训练多代上下文管理.md)**(中文版,v0.2)
14
+
15
+ > 📝 **论文本身与代码一同以 MIT 许可开源(位于 `paper/` 目录),是代码库的一部分 —— 这是一份活文档,任何人都可以编辑,欢迎提 PR 改进。**
16
+
17
+ 生产规模纵向研究:四个半月、三宿主、174,327 次模型调用、187.6 亿累计输入 token(三宿主合计约 247 亿),204,800-token 窗口零违规,马拉松会话 8,584–12,049 次调用。
18
+
19
+ ---
20
+
11
21
  <p align="center">
12
22
  <a href="https://www.npmjs.com/package/billion-context-pi"><img src="https://img.shields.io/npm/v/billion-context-pi.svg?style=flat-square" alt="npm"></a>
13
23
  <a href="https://github.com/ranxianglei/billion-context-pi/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/billion-context-pi.svg?style=flat-square" alt="license"></a>
@@ -65,10 +75,11 @@ pi install npm:billion-context-pi
65
75
 
66
76
  完成。扩展在下次 Pi 启动时自动加载。无需配置 —— 它会自动读取模型的上下文窗口。
67
77
 
68
- > **建议先卸载 `pi-subagents`(可选,推荐)。** billion-context-pi 自带 `acp_delegate` 子代理工具(见下文),以极低的上下文成本(~600 tok vs ~7K tok/轮)替代 pi-subagents。如果你已安装 pi-subagents,卸载它以避免重复的委派工具:
69
- > ```bash
70
- > pi remove npm:pi-subagents
71
- > ```
78
+ > **你另有子代理扩展?** billion-context-pi 自带 `acp_delegate` 子代理工具(见下文),上下文成本极低(~600 tok vs ~7K tok/轮)。同一会话里两套委派工具只会让模型的选择更混乱,二选一:
79
+ > - **用 ACP 的 delegate** —— 卸载另一个扩展:`pi remove npm:pi-subagents`
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`。
72
83
 
73
84
  ## 工作原理
74
85
 
@@ -122,6 +133,8 @@ billion-context-pi 面向 **Pi** 编码代理(`@earendil-works/pi-coding-agent`)
122
133
  | `acp_delegate_wait` | 阻塞等待委派任务完成(返回结果,否则超时) |
123
134
  | `acp_delegate_cancel` | 按 runId 取消正在运行的委派任务 |
124
135
 
136
+ `acp_delegate*` 四个工具是可选的:如果你自带子代理扩展,一个 `acp.json` 键即可关闭 —— 见下文*改用你自己的子代理*。
137
+
125
138
  ### acp_delegate — 干净上下文委派
126
139
 
127
140
  把一个自包含的任务交给一个运行在干净上下文中的新 pi 进程。五个内置角色,各自有系统提示和**软工具护栏**:
@@ -145,6 +158,20 @@ Worker 运行在 Pi 的完整默认工具集上 - 不应用 `--tools` 白名单,
145
158
 
146
159
  在**交互 TUI** 中,异步运行还会在编辑器下方显示一个实时状态 widget(角色、已运行秒数、任务预览),让你随时知道什么在跑、跑了多久。RPC/print/JSON 模式自动禁用。
147
160
 
161
+ #### 改用你自己的子代理
162
+
163
+ 如果你已经在用别的子代理扩展(pi-subagents、pi-lens 等),关掉 ACP 的 delegate,让模型只有一条委派路径。在 `~/.pi/acp.json`(全局)或 `<项目>/.pi/acp.json`(项目级):
164
+
165
+ ```json
166
+ { "delegate": false }
167
+ ```
168
+
169
+ - 等价对象写法:`{ "delegate": { "enabled": false } }`。
170
+ - **关掉的是什么:**`acp_delegate`、`acp_delegate_wait`、`acp_delegate_cancel` 三个工具,`ACP_DELEGATE NOTIFICATIONS` 系统提示段,以及 `ctrl+alt+f` 快捷键(此时 `/acp-fleet` 会提示 delegate 未启用)。压缩本身不受影响 —— `compress`、`decompress`、`search_context`、`acp_status` 全部保留。
171
+ - **生效时机:**三个工具在会话启动时注册,因此需要**新会话**(或重启 Pi)。系统提示段每回合实时解析,可能在工具之前先消失。
172
+ - 只想去掉提示段、保留工具?设 `{ "delegatePrompt": null }`。
173
+ - Pi 原生的 `--exclude-tools acp_delegate,acp_delegate_wait,acp_delegate_cancel` **不能**替代:它藏起工具,但模型仍会收到描述这些工具的 `ACP_DELEGATE NOTIFICATIONS` 段。请用 `delegate: false`。
174
+
148
175
  ## `/acp` 命令
149
176
 
150
177
  为用户提供丰富的状态显示:
@@ -1,6 +1,7 @@
1
1
  import { Type, type Static } from "typebox";
2
2
  import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
3
3
  import type { AcpRuntime } from "./runtime.js";
4
+ import { type ToolPromptOverrides } from "./surface.js";
4
5
  import { type CompressionBlock, type CompressionState } from "acp-kernel";
5
6
  declare const RangeSpec: Type.TObject<{
6
7
  startId: Type.TString;
@@ -19,7 +20,7 @@ declare const CompressParams: Type.TObject<{
19
20
  summaryMaxChars: Type.TOptional<Type.TNumber>;
20
21
  }>;
21
22
  type CompressArgs = Static<typeof CompressParams>;
22
- export declare function makeCompressTool(runtime: AcpRuntime): ToolDefinition<typeof CompressParams>;
23
+ export declare function makeCompressTool(runtime: AcpRuntime, overrides?: ToolPromptOverrides): ToolDefinition<typeof CompressParams>;
23
24
  type RangeEntry = Static<typeof RangeSpec>;
24
25
  export declare function normalizeRanges(args: CompressArgs): RangeEntry[] | string;
25
26
  export declare function tailRepair(s: string): string | undefined;
package/dist/config.d.ts CHANGED
@@ -2,6 +2,12 @@ import { type Config, type Prompts } from "acp-kernel";
2
2
  import type { CompressReasoningConfig } from "./reasoning-drop.js";
3
3
  import type { DegenerationGuardConfig } from "./degeneration.js";
4
4
  import type { ThrottleRetryConfig } from "./throttle-retry.js";
5
+ import type { PiPromptSections } from "./system-prompt.js";
6
+ import type { NudgeSectionsConfig, ToolPromptsConfig } from "./surface.js";
7
+ /** Default TUI shortcut for the acp_delegate fleet inspector. Moved off
8
+ * "ctrl+alt+f" (also claimed by pi-subagents) to avoid a cross-extension
9
+ * conflict Pi's loader only warns about — last-loaded silently wins (#412). */
10
+ export declare const DEFAULT_FLEET_SHORTCUT = "ctrl+alt+d";
5
11
  /** Per-role delegate defaults. Lets long-lived automation pin a cheaper or
6
12
  * more capable model and a thinking level per delegate role, so the main
7
13
  * agent doesn't have to fill them in on every `acp_delegate()` call. */
@@ -23,6 +29,13 @@ export interface DelegateConfig {
23
29
  /** Enable acp_delegate tools (delegate/wait/cancel) and their system-prompt
24
30
  * section. Default: true. Set `enabled: false` to skip registering them. */
25
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;
26
39
  /** How delegate usage is reported back to the main session.
27
40
  * "separate" (default) — delegate tokens tracked in a separate accumulator;
28
41
  * main session totals stay clean, delegate usage shows as its own block in
@@ -70,12 +83,22 @@ export interface DelegateConfig {
70
83
  * saw the result, so re-injecting it would only waste context.
71
84
  * "always" — always inject the notification (previous behavior). */
72
85
  notifyIfRead?: "skip" | "always";
86
+ /** Keybinding for the interactive TUI shortcut that opens the acp_delegate
87
+ * fleet inspector (live list + transcript). Default: "ctrl+alt+d". Set to
88
+ * "" (empty string) to disable keyboard registration entirely — the
89
+ * inspector stays reachable via /acp-fleet. Moved off the previous hardcoded
90
+ * "ctrl+alt+f" because pi-subagents also claims ctrl+alt+f, and Pi's loader
91
+ * only warns + last-loaded-wins on cross-extension conflicts (#412). */
92
+ fleetShortcut?: string;
73
93
  }
74
94
  /** Resolved delegate policy: what actually takes effect after merging acp.json,
75
95
  * env overrides and defaults. Timeout fields are milliseconds; null means the
76
96
  * corresponding timeout/watchdog is disabled. */
77
97
  export interface DelegatePolicy {
78
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;
79
102
  displayUsage: "merged" | "separate";
80
103
  maxDepth: number;
81
104
  syncTimeoutMs: number | null;
@@ -90,6 +113,8 @@ export interface DelegatePolicy {
90
113
  /** Whether to suppress the completion notification when the model already
91
114
  * read the result file after the run finished. Always resolved ("skip" default). */
92
115
  notifyIfRead: "skip" | "always";
116
+ /** Resolved TUI shortcut for the fleet inspector ("" = registration disabled). */
117
+ fleetShortcut: string;
93
118
  }
94
119
  export declare const DEFAULT_DELEGATE_POLICY: DelegatePolicy;
95
120
  /** Compression tuning fields, shared by all three levels (global, provider,
@@ -120,6 +145,13 @@ export interface CompressSettings {
120
145
  * tool calls — see CompressReasoningConfig in src/reasoning-drop.ts.
121
146
  * Merged field-wise (drop, threshold) across the three levels. */
122
147
  reasoning?: CompressReasoningConfig;
148
+ /** Active prompt pack name (see CONFIGURATION.md “Prompt packs”). Base
149
+ * level; override per provider/model via `providers`. "default" or unset =
150
+ * built-in defaults. Resolved per request against the live model, so
151
+ * switching models mid-session switches the pack. Packs ship text-level
152
+ * overrides only; a pack's `toolPrompts` follow the base selection (tool
153
+ * definitions freeze at extension load, before the model is known). */
154
+ promptPack?: string;
123
155
  }
124
156
  /** Per-provider compression overrides. Carries the same tuning fields as the
125
157
  * global level, plus an optional per-model map keyed by model id. */
@@ -193,13 +225,13 @@ export interface AdapterConfig {
193
225
  * unbounded behavior). */
194
226
  toolBashDefaultTimeout?: number;
195
227
  /** Hard byte cap applied to tool result text via the `tool_result` hook.
196
- * Default: 200000 (~200KB, roughly 5000 lines at ~40 bytes/line) — a
197
- * generous ceiling that stops runaway output. Pi already caps bash/read/grep
198
- * at 50KB/2000 lines (bash full output is saved to a temp file), so this
199
- * default mainly caps tools Pi doesn't cap. Set lower (e.g. 8192) for a
200
- * tighter context budget, or 0 to disable. When capped, oversized text is
201
- * head-truncated with a notice telling the model how to see the full output
202
- * (bash: read BashToolDetails.fullOutputPath). */
228
+ * Default: 50000 (~50KB) — aligned with Pi's own bash/read/grep cap so
229
+ * every tool path lands under one ceiling; the net still catches runaway
230
+ * output from tools Pi does not cap (MCP/custom). Set higher for large
231
+ * MCP outputs, lower (e.g. 8192) for a tighter context budget, or 0 to
232
+ * disable. When capped, oversized text is head-truncated with a notice
233
+ * telling the model how to see the full output (bash: read
234
+ * BashToolDetails.fullOutputPath). */
203
235
  toolOutputMaxBytes?: number;
204
236
  /** Delegate sub-agent config. Accepts a boolean shorthand (`true` →
205
237
  * `{ enabled: true }`, `false` → `{ enabled: false }`) or a DelegateConfig
@@ -252,10 +284,25 @@ export interface AdapterConfig {
252
284
  * replacing the kernel's tuned compression rules may reduce summary quality
253
285
  * (lost paths/signatures/decisions → worse retrieval). */
254
286
  acknowledgePromptsRisk?: boolean;
287
+ /** Override structural sections of the ACP system prompt (ACP TAGS, TOOLS,
288
+ * WHEN TO COMPRESS, ...). Tri-state per section: string = replace, null =
289
+ * remove, omitted = default. Not risk-gated — these are documentation
290
+ * sections, not compression rules. Set via acp.json. */
291
+ promptSections?: Partial<PiPromptSections>;
292
+ /** Override guidance-class nudge texts (efficiencyNote, emergencyHeader,
293
+ * t2Guidance, t3Guidance). Same tri-state semantics. Not risk-gated. */
294
+ nudgeSections?: NudgeSectionsConfig;
295
+ /** Override the four ACP tool definitions' LLM-facing text (description,
296
+ * paramDescriptions, promptSnippet, promptGuidelines). Read synchronously
297
+ * at extension load — tool defs are frozen at registration time. */
298
+ toolPrompts?: ToolPromptsConfig;
299
+ /** Replace (string) or remove (null) the ACP_DELEGATE_NOTIFICATIONS appendix
300
+ * injected when the delegate tool is enabled. */
301
+ delegatePrompt?: string | null;
255
302
  coreOverrides?: Partial<Config>;
256
303
  }
257
304
  export declare const DEFAULT_TOOL_BASH_TIMEOUT = 60;
258
- export declare const DEFAULT_TOOL_OUTPUT_MAX_BYTES = 200000;
305
+ export declare const DEFAULT_TOOL_OUTPUT_MAX_BYTES = 50000;
259
306
  /** Resolve delegate config from the adapter, handling the boolean shorthand
260
307
  * and the legacy flat `displayUsage` alias. Precedence: env > acp.json >
261
308
  * default (same convention as ACP_MODEL_CONTEXT_LIMIT). Invalid values fall
@@ -1,11 +1,12 @@
1
1
  import { Type } from "typebox";
2
2
  import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
3
3
  import type { AcpRuntime } from "./runtime.js";
4
+ import { type ToolPromptOverrides } from "./surface.js";
4
5
  declare const DecompressParams: Type.TObject<{
5
6
  blockId: Type.TString;
6
7
  full: Type.TOptional<Type.TBoolean>;
7
8
  toFile: Type.TOptional<Type.TString>;
8
9
  inline: Type.TOptional<Type.TBoolean>;
9
10
  }>;
10
- export declare function makeDecompressTool(runtime: AcpRuntime): ToolDefinition<typeof DecompressParams>;
11
+ export declare function makeDecompressTool(runtime: AcpRuntime, overrides?: ToolPromptOverrides): ToolDefinition<typeof DecompressParams>;
11
12
  export {};
@@ -6,8 +6,9 @@ interface WidgetRun {
6
6
  startedAt: number;
7
7
  }
8
8
  type RunsSnapshot = () => WidgetRun[];
9
+ export declare function formatShortcutLabel(shortcut: string): string;
9
10
  export declare const delegateStatusWidget: {
10
- setContext(ctx: ExtensionContext, snapshot: RunsSnapshot): void;
11
+ setContext(ctx: ExtensionContext, snapshot: RunsSnapshot, shortcut?: string): void;
11
12
  dispose(): void;
12
13
  poke(): void;
13
14
  };