billion-context-pi-lean 0.1.57-lean.1 → 0.1.69-lean.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 CHANGED
@@ -10,11 +10,11 @@ A lightweight Pi wrapper for [`billion-context-pi`](https://github.com/ranxiangl
10
10
  * Streamlined tool surface: Exposes the high-frequency `compress` tool directly, while consolidating `decompress`, `search_context`, and `acp_status` into an on-demand `acp_context` interface.
11
11
  * Focused and clean: Disables built-in delegation and auto-updates by design. For delegation workflows, pair with a dedicated subagent extension.
12
12
 
13
- Upstream dependency is pinned to `billion-context-pi@0.1.57`; delegation remains disabled in this lean wrapper.
13
+ Upstream dependency is pinned to `billion-context-pi@0.1.69`; delegation remains disabled in this lean wrapper.
14
14
 
15
15
  ## Context Savings
16
16
 
17
- The benchmark below compares the same delegation-disabled configuration against upstream `0.1.57`.
17
+ The benchmark below compares the same delegation-disabled configuration against upstream `0.1.69`.
18
18
 
19
19
  ## Installation
20
20
 
@@ -59,15 +59,16 @@ Use `help` only when you need to inspect the full upstream schema.
59
59
 
60
60
  With only this extension enabled, its recurring initialization overhead in the model context is:
61
61
 
62
- | Item | Lean | Upstream `billion-context-pi@0.1.57` |
62
+ | Item | Lean | Upstream `billion-context-pi@0.1.69` |
63
63
  | --- | ---: | ---: |
64
64
  | `compress` | 231 | 549 |
65
65
  | Context operations | `acp_context`: 90 | `decompress` + `search_context` + `acp_status`: 1,095 |
66
- | System prompt additions | 369 | 3,951 |
67
- | **Total** | **690** | **5,595** |
66
+ | System prompt additions | 369 | 4,158 |
67
+ | **Total** | **690** | **5,802** |
68
+
69
+ This saves **5,112 tokens (88.1%)** compared to the pinned upstream package.
70
+ The benchmark was measured on Pi 0.85.1 with `measure-plugin-tokens-v3.mjs` in a fresh isolated session, with delegation disabled for both packages, excluding built-in tools, skills, context files, and unrelated extensions. Token estimates use `ceil(characters / 4)`. Pure runtime UI elements and slash commands are excluded as they are not sent to the model.
68
71
 
69
- This saves **4,905 tokens (87.7%)** compared to the pinned upstream package.
70
- The benchmark was measured on Pi 0.84.4 with `pi-context-view@0.4.3` in a fresh isolated session, with delegation disabled for both packages, excluding built-in tools, skills, context files, and unrelated extensions. Context View estimates tokens as `ceil(characters / 4)`. Pure runtime UI elements and slash commands are excluded as they are not sent to the model.
71
72
  ## Development
72
73
 
73
74
  ```bash
package/README.zh-CN.md CHANGED
@@ -8,11 +8,11 @@
8
8
 
9
9
  * 完整上下文引擎:保留上游的对话历史压缩、分层摘要、主动提示(Nudge)、溢出恢复、重试机制与工具保护能力。
10
10
  * 优化工具布局:高频使用的 `compress` 工具直接对外暴露,其余 `decompress`、`search_context` 与 `acp_status` 操作整合为按需调用的 `acp_context` 入口。
11
- * 纯粹专注:主动移除了内置的 Delegation 代理分发与自动更新逻辑;如需多 Agent 协作,建议搭配独立的 Subagent 扩展使用。上游依赖版本锁定为 `billion-context-pi@0.1.57`,确保运行稳定可靠。
11
+ * 纯粹专注:主动移除了内置的 Delegation 代理分发与自动更新逻辑;如需多 Agent 协作,建议搭配独立的 Subagent 扩展使用。上游依赖版本锁定为 `billion-context-pi@0.1.69`,确保运行稳定可靠。
12
12
 
13
13
  ## 精简优化成效
14
14
 
15
- 在双方均关闭 Delegation 的配置下,与上游 `billion-context-pi@0.1.57` 本地对比:Lean 精简版常驻上下文开销为 690 tokens,上游为 5,595 tokens,减少 **4,905 tokens(87.7%)**。
15
+ 在双方均关闭 Delegation 的配置下,与上游 `billion-context-pi@0.1.69` 本地对比:Lean 精简版常驻上下文开销为 690 tokens,上游为 5,802 tokens,减少 **5,112 tokens(88.1%)**。
16
16
 
17
17
  ## 安装
18
18
 
@@ -57,15 +57,16 @@ acp_context
57
57
 
58
58
  单独启用本扩展时,注入到模型初始上下文中的 Token 占用实测如下:
59
59
 
60
- | 项目 | Lean 精简版 | 原版 `billion-context-pi@0.1.57` |
60
+ | 项目 | Lean 精简版 | 原版 `billion-context-pi@0.1.69` |
61
61
  | --- | ---: | ---: |
62
62
  | `compress` | 231 | 549 |
63
63
  | 上下文检索与操作 | `acp_context`: 90 | `decompress` + `search_context` + `acp_status`: 1,095 |
64
- | 系统提示词增量 | 369 | 3,951 |
65
- | **合计** | **690** | **5,595** |
64
+ | 系统提示词增量 | 369 | 4,158 |
65
+ | **合计** | **690** | **5,802** |
66
+
67
+ 相比当前上游扩展,初始开销减少了 **5,112 tokens(88.1%)**。
68
+ 测试时双方均关闭 Delegation,环境为 Pi 0.85.1 与 `measure-plugin-tokens-v3.mjs` 独立会话,排除了 Pi 内置工具、Skills、上下文文件与无关扩展。Token 按 `ceil(字符数 / 4)` 估算。未计入不会发送给模型的纯运行时 UI 与 Slash 命令。
66
69
 
67
- 相比当前上游扩展,初始开销减少了 **4,905 tokens(87.7%)**。
68
- 测试时双方均关闭 Delegation,环境为 Pi 0.84.4 与 `pi-context-view@0.4.3` 独立会话,排除了 Pi 内置工具、Skills、上下文文件与无关扩展。Context View 按 `ceil(字符数 / 4)` 估算。未计入不会发送给模型的纯运行时 UI 与 Slash 命令。
69
70
  ## 本地开发
70
71
 
71
72
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "billion-context-pi-lean",
3
- "version": "0.1.57-lean.1",
3
+ "version": "0.1.69-lean.1",
4
4
  "type": "module",
5
5
  "description": "Token-lean Pi facade for billion-context-pi with the full upstream context engine.",
6
6
  "license": "MIT",
@@ -12,13 +12,19 @@
12
12
  "bugs": {
13
13
  "url": "https://github.com/kunkun9527/billion-context-pi-lean/issues"
14
14
  },
15
+ "files": [
16
+ "index.ts",
17
+ "README.md",
18
+ "README.zh-CN.md",
19
+ "LICENSE"
20
+ ],
15
21
  "scripts": {
16
22
  "test": "node --test tests/*.test.mjs",
17
23
  "typecheck": "tsc -p tsconfig.json",
18
24
  "check": "npm run typecheck && npm test"
19
25
  },
20
26
  "dependencies": {
21
- "billion-context-pi": "0.1.57",
27
+ "billion-context-pi": "0.1.69",
22
28
  "typebox": "1.3.7"
23
29
  },
24
30
  "devDependencies": {
@@ -1,307 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { createJiti } from "../node_modules/@earendil-works/pi-coding-agent/node_modules/jiti/lib/jiti.mjs";
4
-
5
- const jiti = createJiti(import.meta.url, { moduleCache: false });
6
- const extensionModule = await jiti.import("../index.ts");
7
- const extension = extensionModule.default ?? extensionModule;
8
- const { createLeanAcpExtension } = extensionModule;
9
-
10
- function createPi() {
11
- const tools = [];
12
- const handlers = new Map();
13
- const noOp = () => undefined;
14
- return new Proxy({
15
- tools,
16
- handlers,
17
- registerTool(tool) {
18
- tools.push(tool);
19
- },
20
- on(event, handler) {
21
- const listeners = handlers.get(event) ?? [];
22
- listeners.push(handler);
23
- handlers.set(event, listeners);
24
- },
25
- registerCommand: noOp,
26
- registerShortcut: noOp,
27
- registerMessageRenderer: noOp,
28
- registerProvider: noOp,
29
- registerFlag: noOp,
30
- getFlag: () => undefined,
31
- getActiveTools: () => [],
32
- getAllTools: () => [],
33
- setActiveTools: noOp,
34
- appendEntry: noOp,
35
- sendMessage: noOp,
36
- events: { on: noOp, emit: noOp },
37
- }, {
38
- get(target, property) {
39
- return property in target ? target[property] : noOp;
40
- },
41
- });
42
- }
43
-
44
- const schemas = {
45
- compress: {
46
- type: "object",
47
- description: "large outer description",
48
- properties: {
49
- topic: { type: "string", description: "large top-level topic description" },
50
- content: {
51
- type: "array",
52
- description: "large nested description",
53
- items: {
54
- type: "object",
55
- properties: {
56
- startId: { type: "string", description: "large start description" },
57
- endId: { type: "string", description: "large end description" },
58
- summary: { type: "string", description: "large summary description" },
59
- topic: { type: "string", description: "large range topic description" },
60
- },
61
- },
62
- },
63
- summaryMaxChars: { type: "number", description: "large limit description" },
64
- },
65
- required: ["content"],
66
- },
67
- decompress: {
68
- type: "object",
69
- properties: {
70
- blockId: { type: "string" },
71
- full: { type: "boolean" },
72
- toFile: { type: "string" },
73
- inline: { type: "boolean" },
74
- },
75
- required: ["blockId"],
76
- },
77
- search_context: {
78
- type: "object",
79
- properties: {
80
- query: { type: "string" },
81
- limit: { type: "number" },
82
- },
83
- required: ["query"],
84
- },
85
- acp_status: {
86
- type: "object",
87
- properties: {
88
- scope: { type: "string" },
89
- view: { type: "string" },
90
- tool: { type: "string" },
91
- sort: { type: "string" },
92
- limit: { type: "number" },
93
- },
94
- },
95
- };
96
-
97
- function fakeUpstream(calls = [], executions = { count: 0 }) {
98
- return (pi) => {
99
- for (const name of ["compress", "decompress", "search_context", "acp_status"]) {
100
- pi.registerTool({
101
- name,
102
- label: name,
103
- description: `${name} full upstream description`,
104
- parameters: structuredClone(schemas[name]),
105
- async execute(...args) {
106
- executions.count += 1;
107
- calls.push([name, ...args]);
108
- return {
109
- content: [{
110
- type: "text",
111
- text: name === "search_context"
112
- ? 'result → decompress({ blockId: "b12" })'
113
- : name === "compress"
114
- ? 'Nothing to do — Run acp_status, then call compress again. Use search_context or decompress to retrieve details. Try search_context({ query: "auth token" }).'
115
- : `${name} result`,
116
- }],
117
- };
118
- },
119
- });
120
- }
121
- pi.registerTool({ name: "acp_delegate", async execute() {} });
122
- pi.on("before_agent_start", () => ({ systemPrompt: "upstream prompt must be suppressed" }));
123
- };
124
- }
125
-
126
- function getTool(pi, name) {
127
- return pi.tools.find((tool) => tool.name === name);
128
- }
129
-
130
- test("registers only compress and acp_context provider tools", () => {
131
- const pi = createPi();
132
- createLeanAcpExtension(fakeUpstream())(pi);
133
- assert.deepEqual(pi.tools.map((tool) => tool.name), ["compress", "acp_context"]);
134
- });
135
-
136
- test("cooperates with an optional collapsed-display service without a local file dependency", () => {
137
- const serviceKey = Symbol.for("@local/pi-collapsed-tools.display-service.v1");
138
- const previous = globalThis[serviceKey];
139
- const decorated = [];
140
- globalThis[serviceKey] = {
141
- version: 1,
142
- decorate(tool) {
143
- decorated.push(tool.name);
144
- return tool;
145
- },
146
- };
147
-
148
- try {
149
- const pi = createPi();
150
- createLeanAcpExtension(fakeUpstream())(pi);
151
- assert.deepEqual(decorated, ["compress", "acp_context"]);
152
- } finally {
153
- if (previous === undefined) delete globalThis[serviceKey];
154
- else globalThis[serviceKey] = previous;
155
- }
156
- });
157
-
158
- test("keeps compress direct, retains concise critical descriptions, and rewrites stale status advice", async () => {
159
- const calls = [];
160
- const pi = createPi();
161
- createLeanAcpExtension(fakeUpstream(calls))(pi);
162
- const tool = getTool(pi, "compress");
163
- const result = await tool.execute(
164
- "compress-1",
165
- { content: [{ startId: "m1", endId: "m2", summary: "done" }] },
166
- undefined,
167
- undefined,
168
- { cwd: "C:/work" },
169
- );
170
-
171
- const schema = tool.parameters;
172
- const entries = schema.properties.content.items.properties;
173
- assert.equal(schema.description, undefined);
174
- assert.match(schema.properties.content.description, /direct array/i);
175
- assert.match(schema.properties.content.description, /JSON strings|JSON-stringify/i);
176
- assert.match(schema.properties.content.description, /mix/i);
177
- assert.match(schema.properties.topic.description, /label/i);
178
- assert.match(schema.properties.summaryMaxChars.description, /length/i);
179
- assert.match(entries.startId.description, /first/i);
180
- assert.match(entries.endId.description, /last/i);
181
- assert.match(entries.summary.description, /exact technical details/i);
182
- assert.match(entries.topic.description, /label/i);
183
- assert.doesNotMatch(JSON.stringify(schema), /large .* description/);
184
- const rewritten = result.content[0].text;
185
- assert.match(rewritten, /acp_context\(\{ op: "acp_status", args: \{\} \}\)/);
186
- assert.match(rewritten, /use acp_context with op "search_context" or "decompress"/i);
187
- assert.match(rewritten, /acp_context\(\{ op: "search_context", args: \{ query: "auth token" \} \}\)/);
188
- assert.doesNotMatch(rewritten, /\b(?:search_context|decompress|acp_status)\s*\(/);
189
- assert.doesNotMatch(rewritten, /\brun acp_status\b/i);
190
- assert.doesNotMatch(rewritten, /\buse search_context\b/i);
191
- assert.equal(calls[0][0], "compress");
192
- assert.deepEqual(calls[0][2], { content: [{ startId: "m1", endId: "m2", summary: "done" }] });
193
- });
194
- test("routes all three low-frequency operations with original args and execution context", async () => {
195
- const cases = [
196
- ["search_context", { query: "architecture", limit: 8 }],
197
- ["decompress", { blockId: "b11", toFile: "R:/Temp/history.txt", full: true }],
198
- ["acp_status", { scope: "uncompressed", view: "messages", sort: "size", limit: 30 }],
199
- ];
200
-
201
- for (const [op, args] of cases) {
202
- const calls = [];
203
- const pi = createPi();
204
- createLeanAcpExtension(fakeUpstream(calls))(pi);
205
- const signal = new AbortController().signal;
206
- const context = { cwd: "C:/work" };
207
- await getTool(pi, "acp_context").execute(
208
- `call-${op}`,
209
- { op, args },
210
- signal,
211
- undefined,
212
- context,
213
- );
214
- assert.equal(calls[0][0], op);
215
- assert.equal(calls[0][1], `call-${op}`);
216
- assert.deepEqual(calls[0][2], args);
217
- assert.equal(calls[0][3], signal);
218
- assert.equal(calls[0][5], context);
219
- }
220
- });
221
-
222
- test("rewrites search results to the facade call syntax", async () => {
223
- const pi = createPi();
224
- createLeanAcpExtension(fakeUpstream())(pi);
225
- const result = await getTool(pi, "acp_context").execute(
226
- "search-1",
227
- { op: "search_context", args: { query: "needle" } },
228
- );
229
- assert.equal(
230
- result.content[0].text,
231
- 'result → acp_context({ op: "decompress", args: { blockId: "b12" } })',
232
- );
233
- });
234
-
235
- test("facade advertises help syntax and discloses an upstream schema without executing it", async () => {
236
- const executions = { count: 0 };
237
- const pi = createPi();
238
- createLeanAcpExtension(fakeUpstream([], executions))(pi);
239
- const tool = getTool(pi, "acp_context");
240
- assert.match(
241
- tool.description,
242
- /\{ op: "help", args: \{ tool: "search_context" \} \}/,
243
- );
244
- const result = await tool.execute(
245
- "help-1",
246
- { op: "help", args: { tool: "decompress" } },
247
- );
248
- assert.equal(executions.count, 0);
249
- assert.match(result.content[0].text, /blockId/);
250
- assert.match(result.content[0].text, /toFile/);
251
- });
252
-
253
- test("invalid facade args fail locally with an on-demand help hint", async () => {
254
- const executions = { count: 0 };
255
- const pi = createPi();
256
- createLeanAcpExtension(fakeUpstream([], executions))(pi);
257
- await assert.rejects(
258
- getTool(pi, "acp_context").execute(
259
- "invalid-1",
260
- { op: "decompress", args: { inline: true } },
261
- ),
262
- /args invalid.*op help.*decompress/,
263
- );
264
- assert.equal(executions.count, 0);
265
- });
266
-
267
- test("suppresses the upstream prompt and keeps concise summary-fidelity rules", async () => {
268
- const pi = createPi();
269
- createLeanAcpExtension(fakeUpstream())(pi);
270
- const hooks = pi.handlers.get("before_agent_start");
271
- assert.equal(hooks.length, 1);
272
- const result = await hooks[0]({ systemPrompt: "base prompt" });
273
- assert.match(result.systemPrompt, /^base prompt/);
274
- assert.match(result.systemPrompt, /Compress consumed history with compress/);
275
- assert.match(result.systemPrompt, /exact file paths and line numbers/i);
276
- assert.match(result.systemPrompt, /symbols and signatures/i);
277
- assert.match(result.systemPrompt, /errors, commands, versions, thresholds/i);
278
- assert.match(result.systemPrompt, /decisions with reasons, current state, and unresolved TODOs/i);
279
- assert.match(result.systemPrompt, /Refs may be renumbered after compression/i);
280
- assert.match(result.systemPrompt, /Block decompression writes to a file by default/i);
281
- assert.match(result.systemPrompt, /provider-throttle.*resume exactly where interrupted/i);
282
- assert.match(result.systemPrompt, /acp_context/);
283
- assert.doesNotMatch(result.systemPrompt, /upstream prompt must be suppressed/);
284
- });
285
-
286
- test("real upstream registration exposes the intended two-tool surface", () => {
287
- const pi = createPi();
288
- extension(pi);
289
- assert.deepEqual(pi.tools.map((tool) => tool.name), ["compress", "acp_context"]);
290
- });
291
-
292
- test("provider-facing metadata stays within the lean budget", () => {
293
- const pi = createPi();
294
- extension(pi);
295
- const metadata = pi.tools.map((tool) => ({
296
- name: tool.name,
297
- description: tool.description,
298
- parameters: tool.parameters,
299
- promptSnippet: tool.promptSnippet,
300
- promptGuidelines: tool.promptGuidelines,
301
- }));
302
- const serialized = JSON.stringify(metadata);
303
- assert.ok(
304
- serialized.length <= 1450,
305
- `lean metadata grew to ${serialized.length} characters`,
306
- );
307
- });
package/tsconfig.json DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "strict": true,
7
- "noEmit": true,
8
- "skipLibCheck": true,
9
- "allowImportingTsExtensions": true
10
- },
11
- "include": [
12
- "index.ts"
13
- ]
14
- }