billion-context-pi 0.1.25 → 0.1.26
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 +10 -6
- package/README.zh-CN.md +10 -6
- package/dist/delegate-tool.d.ts +19 -2
- package/dist/index.js +34 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -86,17 +86,21 @@ This has two practical implications:
|
|
|
86
86
|
|
|
87
87
|
### acp_delegate — clean-context delegation
|
|
88
88
|
|
|
89
|
-
Hand a self-contained task to a fresh pi process running in a clean context. Five built-in roles, each with a
|
|
89
|
+
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**:
|
|
90
90
|
|
|
91
91
|
| Role | Tools | Best for |
|
|
92
92
|
|------|-------|----------|
|
|
93
|
-
| `reviewer` | read, bash | Read-only code review (bugs, risks, file:line) |
|
|
94
|
-
| `researcher` | read, bash | Read-only codebase investigation |
|
|
93
|
+
| `reviewer` | read, bash, grep, find, ls + ACP | Read-only code review (bugs, risks, file:line) |
|
|
94
|
+
| `researcher` | read, bash, grep, find, ls + ACP | Read-only codebase investigation |
|
|
95
95
|
| `worker` | read, edit, write, bash | Make code changes |
|
|
96
|
-
| `planner` | read, bash | Analyze + propose a step-by-step plan |
|
|
97
|
-
| `oracle` | read, bash | Answer questions / advise |
|
|
96
|
+
| `planner` | read, bash, grep, find, ls + ACP | Analyze + propose a step-by-step plan |
|
|
97
|
+
| `oracle` | read, bash, grep, find, ls + ACP | Answer questions / advise |
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
Read-only roles (reviewer, researcher, planner, oracle) receive a restricted tool allowlist (`read, bash, grep, find, ls`) plus ACP context tools (`compress, decompress, search_context, acp_status`) so they can manage their own context. This prevents accidental file modifications, but `bash` can bypass it - **it is a guardrail, not a security boundary**.
|
|
100
|
+
|
|
101
|
+
Worker runs on Pi's full default toolset - no `--tools` allowlist is applied, so any loaded extension or custom tools (e.g. ACP, LSP, MCP) remain available. This keeps primary-task delegation fully capable. The `read, edit, write, bash` listing above reflects core tools only.
|
|
102
|
+
|
|
103
|
+
The full delegate result is saved to a file (`/tmp/acp-delegate/<runId>.out`); the tool result and injected notification carry only the **task title + file path** (no preview) - use `read` for the details. This keeps the parent context lean.
|
|
100
104
|
|
|
101
105
|
- **Interactive (TUI) & RPC modes**: `async:true` (default) runs the child in the background; a short completion notification is injected into the chat when it finishes.
|
|
102
106
|
- **Print / JSON modes** (`pi -p`, SDK): `async:true` auto-downgrades to **synchronous** — the result returns as the tool result in the same turn (the parent exits after one turn, so background injection would be lost).
|
package/README.zh-CN.md
CHANGED
|
@@ -85,17 +85,21 @@ billion-context 通过拦截 Pi 的 `context` 事件接管上下文管理。**Pi
|
|
|
85
85
|
|
|
86
86
|
### acp_delegate — 干净上下文委派
|
|
87
87
|
|
|
88
|
-
把一个自包含的任务交给一个运行在干净上下文中的新 pi
|
|
88
|
+
把一个自包含的任务交给一个运行在干净上下文中的新 pi 进程。五个内置角色,各自有系统提示和**软工具护栏**:
|
|
89
89
|
|
|
90
90
|
| 角色 | 工具 | 适用场景 |
|
|
91
91
|
|------|------|----------|
|
|
92
|
-
| `reviewer` | read, bash | 只读代码审查(bug、风险、file:line) |
|
|
93
|
-
| `researcher` | read, bash | 只读代码库调研 |
|
|
92
|
+
| `reviewer` | read, bash, grep, find, ls + ACP | 只读代码审查(bug、风险、file:line) |
|
|
93
|
+
| `researcher` | read, bash, grep, find, ls + ACP | 只读代码库调研 |
|
|
94
94
|
| `worker` | read, edit, write, bash | 修改代码 |
|
|
95
|
-
| `planner` | read, bash | 分析 + 提出分步计划 |
|
|
96
|
-
| `oracle` | read, bash | 回答问题 / 建议 |
|
|
95
|
+
| `planner` | read, bash, grep, find, ls + ACP | 分析 + 提出分步计划 |
|
|
96
|
+
| `oracle` | read, bash, grep, find, ls + ACP | 回答问题 / 建议 |
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
只读角色(reviewer、researcher、planner、oracle)获得受限工具白名单(`read, bash, grep, find, ls`)+ ACP 上下文工具(`compress, decompress, search_context, acp_status`),以便管理自己的上下文。这能防止意外修改文件,但 `bash` 可绕过 - **这是护栏,不是安全边界**。
|
|
99
|
+
|
|
100
|
+
Worker 运行在 Pi 的完整默认工具集上 - 不应用 `--tools` 白名单,因此任何已加载的扩展或自定义工具(如 ACP、LSP、MCP)保持可用。这确保主任务委派能力完整。上表中的 `read, edit, write, bash` 仅反映核心工具。
|
|
101
|
+
|
|
102
|
+
委派的完整结果保存到文件(`/tmp/acp-delegate/<runId>.out`);工具结果和注入通知只携带**任务标题 + 文件路径**(无预览)- 需要细节时用 `read` 读取。这让父上下文保持精简。
|
|
99
103
|
|
|
100
104
|
- **交互(TUI)与 RPC 模式**:`async:true`(默认)在后台运行子进程;完成时一条简短通知注入到聊天框。
|
|
101
105
|
- **Print / JSON 模式**(`pi -p`、SDK):`async:true` 自动降级为**同步** — 结果在同一轮作为工具结果返回(父进程一轮后即退出,后台注入会丢失)。
|
package/dist/delegate-tool.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Type } from "typebox";
|
|
2
|
-
import type { ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
1
|
+
import { Type, type Static } from "typebox";
|
|
2
|
+
import type { ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
/** Snapshot of currently-running delegate runs, for the TUI status widget. */
|
|
4
4
|
export declare function runningRunsSnapshot(): {
|
|
5
5
|
runId: string;
|
|
@@ -14,6 +14,7 @@ declare const DelegateParams: Type.TObject<{
|
|
|
14
14
|
model: Type.TOptional<Type.TString>;
|
|
15
15
|
async: Type.TOptional<Type.TBoolean>;
|
|
16
16
|
}>;
|
|
17
|
+
type DelegateArgs = Static<typeof DelegateParams>;
|
|
17
18
|
declare const CancelParams: Type.TObject<{
|
|
18
19
|
runId: Type.TString;
|
|
19
20
|
}>;
|
|
@@ -22,6 +23,22 @@ declare const WaitParams: Type.TObject<{
|
|
|
22
23
|
timeout: Type.TOptional<Type.TInteger>;
|
|
23
24
|
}>;
|
|
24
25
|
export declare function makeDelegateTool(pi: ExtensionAPI): ToolDefinition<typeof DelegateParams>;
|
|
26
|
+
/** If the delegate already delivered its result via a system notification
|
|
27
|
+
* (the close handler injected before this wait was called), return a short
|
|
28
|
+
* "already delivered" message pointing at the result file, so the model
|
|
29
|
+
* never sees the same result twice (once via the injected notification,
|
|
30
|
+
* once via this tool result). Returns null when the run was NOT injected,
|
|
31
|
+
* in which case the caller delivers the full payload via formatRunResult(). */
|
|
32
|
+
export declare function injectedWaitMessage(run: {
|
|
33
|
+
injected?: boolean;
|
|
34
|
+
result?: {
|
|
35
|
+
file: string;
|
|
36
|
+
};
|
|
37
|
+
}, runId: string, remainingLine: string): string | null;
|
|
25
38
|
export declare function makeDelegateWaitTool(_pi: ExtensionAPI): ToolDefinition<typeof WaitParams>;
|
|
26
39
|
export declare function makeDelegateCancelTool(_pi: ExtensionAPI): ToolDefinition<typeof CancelParams>;
|
|
40
|
+
export declare function buildChildArgs(args: DelegateArgs, rolePrompt: string, ctx: ExtensionContext): Promise<{
|
|
41
|
+
cliArgs: string[];
|
|
42
|
+
tmpDir: string;
|
|
43
|
+
}>;
|
|
27
44
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -7649,15 +7649,19 @@ var MAX_DEPTH = 2;
|
|
|
7649
7649
|
var SYNC_TIMEOUT_MS = 5 * 6e4;
|
|
7650
7650
|
var RESULT_SUMMARY_CHARS = 500;
|
|
7651
7651
|
var OUT_DIR = join4(tmpdir2(), "acp-delegate");
|
|
7652
|
+
var ACP_TOOLS = ["compress", "decompress", "search_context", "acp_status"];
|
|
7653
|
+
var RESTRICTED_TOOLS = "read,bash,grep,find,ls";
|
|
7652
7654
|
var AGENTS = {
|
|
7653
7655
|
reviewer: {
|
|
7654
|
-
tools:
|
|
7656
|
+
tools: RESTRICTED_TOOLS,
|
|
7657
|
+
restricted: true,
|
|
7655
7658
|
prompt: `You are a senior code reviewer with read-only access.
|
|
7656
7659
|
Read the given code and report: bugs, security/safety risks, correctness issues, and concrete improvement suggestions.
|
|
7657
7660
|
Be specific \u2014 cite file:line for every finding. Do NOT modify any files; only read and report.`
|
|
7658
7661
|
},
|
|
7659
7662
|
researcher: {
|
|
7660
|
-
tools:
|
|
7663
|
+
tools: RESTRICTED_TOOLS,
|
|
7664
|
+
restricted: true,
|
|
7661
7665
|
prompt: `You are a code researcher with read-only access.
|
|
7662
7666
|
Investigate the codebase to answer the question thoroughly. Report findings with exact file:line references, function/type signatures, and relevant code snippets.
|
|
7663
7667
|
Do NOT modify any files; only read and report.`
|
|
@@ -7669,13 +7673,15 @@ Make exactly the requested code changes \u2014 minimal, focused, following exist
|
|
|
7669
7673
|
After editing, briefly summarize what you changed and why. Do not expand scope.`
|
|
7670
7674
|
},
|
|
7671
7675
|
planner: {
|
|
7672
|
-
tools:
|
|
7676
|
+
tools: RESTRICTED_TOOLS,
|
|
7677
|
+
restricted: true,
|
|
7673
7678
|
prompt: `You are a technical planner with read-only access.
|
|
7674
7679
|
Analyze the task and produce a concrete, ordered step-by-step implementation plan with rationale for each step.
|
|
7675
7680
|
Cite file:line for code you reference. Do NOT modify any files; only read and propose.`
|
|
7676
7681
|
},
|
|
7677
7682
|
oracle: {
|
|
7678
|
-
tools:
|
|
7683
|
+
tools: RESTRICTED_TOOLS,
|
|
7684
|
+
restricted: true,
|
|
7679
7685
|
prompt: `You are an expert advisor with read-only access.
|
|
7680
7686
|
Answer the question concisely with clear reasoning. Cite file:line when referencing code. Do NOT modify any files.`
|
|
7681
7687
|
}
|
|
@@ -7731,7 +7737,7 @@ var agentListLine = (name) => {
|
|
|
7731
7737
|
planner: "analyze + propose step-by-step plan (read-only)",
|
|
7732
7738
|
oracle: "answer questions / advise (read-only)"
|
|
7733
7739
|
};
|
|
7734
|
-
return ` \u2022 ${name}
|
|
7740
|
+
return ` \u2022 ${name} - ${blurb[name]} [tools: ${def.tools}${def.restricted ? " + ACP context tools" : ""}]`;
|
|
7735
7741
|
};
|
|
7736
7742
|
function makeDelegateTool(pi) {
|
|
7737
7743
|
return {
|
|
@@ -7772,6 +7778,12 @@ function remainingLineForWait(selfRunId) {
|
|
|
7772
7778
|
const remaining = Array.from(runs.values()).filter((r) => r.status === "running" && r.runId !== selfRunId).length;
|
|
7773
7779
|
return remaining > 0 ? ` ${remaining} delegate${remaining === 1 ? " is" : "s are"} still running.` : "";
|
|
7774
7780
|
}
|
|
7781
|
+
function injectedWaitMessage(run, runId, remainingLine) {
|
|
7782
|
+
if (!run.injected) return null;
|
|
7783
|
+
const file = run.result?.file;
|
|
7784
|
+
const fileLine = file ? ` If you need details, read the result file: \`${file}\`.` : "";
|
|
7785
|
+
return `Delegate \`${runId}\` already delivered its result via a system notification when it finished \u2014 no need to wait on it again.${remainingLine}${fileLine}`;
|
|
7786
|
+
}
|
|
7775
7787
|
function makeDelegateWaitTool(_pi) {
|
|
7776
7788
|
return {
|
|
7777
7789
|
name: "acp_delegate_wait",
|
|
@@ -7794,6 +7806,11 @@ function makeDelegateWaitTool(_pi) {
|
|
|
7794
7806
|
return { details: void 0, content: [{ type: "text", text: `Delegate \`${args.runId}\` was cancelled (no result).${remainingLineForWait(args.runId)}` }] };
|
|
7795
7807
|
}
|
|
7796
7808
|
if (run.status !== "running") {
|
|
7809
|
+
const dedup = injectedWaitMessage(run, args.runId, remainingLineForWait(args.runId));
|
|
7810
|
+
if (dedup) {
|
|
7811
|
+
run.consumed = true;
|
|
7812
|
+
return { details: void 0, content: [{ type: "text", text: dedup }] };
|
|
7813
|
+
}
|
|
7797
7814
|
run.consumed = true;
|
|
7798
7815
|
if (!run.result) {
|
|
7799
7816
|
return { details: void 0, content: [{ type: "text", text: `Delegate \`${args.runId}\` finished but no result is available (persist error).` }] };
|
|
@@ -7958,6 +7975,7 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
7958
7975
|
return;
|
|
7959
7976
|
}
|
|
7960
7977
|
const injected = injectResult(pi, args.agent, runId, args.task, code, file2);
|
|
7978
|
+
run.injected = injected;
|
|
7961
7979
|
debug.event("delegate-done", { runId, code, status: run.status, injected, outLen: output.length, file: file2 });
|
|
7962
7980
|
delegateStatusWidget.poke();
|
|
7963
7981
|
}).catch((err) => {
|
|
@@ -8003,6 +8021,11 @@ async function buildChildArgs(args, rolePrompt, ctx) {
|
|
|
8003
8021
|
|
|
8004
8022
|
Complete the task below.`, "utf8");
|
|
8005
8023
|
const cliArgs = ["-p", "--no-session", "--append-system-prompt", promptFile];
|
|
8024
|
+
const agentDef = AGENTS[args.agent];
|
|
8025
|
+
if (agentDef?.restricted) {
|
|
8026
|
+
const merged = [.../* @__PURE__ */ new Set([...agentDef.tools.split(",").map((s) => s.trim()), ...ACP_TOOLS])];
|
|
8027
|
+
cliArgs.push("--tools", merged.join(","));
|
|
8028
|
+
}
|
|
8006
8029
|
if (args.model && args.model.includes("/")) {
|
|
8007
8030
|
const [providerId, ...rest] = args.model.split("/");
|
|
8008
8031
|
const modelId = rest.join("/");
|
|
@@ -8209,7 +8232,7 @@ async function statusReport(runtime, ctx) {
|
|
|
8209
8232
|
const activeBlocksList = state.blocks.filter((b) => b.active);
|
|
8210
8233
|
const totalBlocksList = state.blocks;
|
|
8211
8234
|
const lines = [];
|
|
8212
|
-
const versionStr = "0.1.
|
|
8235
|
+
const versionStr = "0.1.26" ? `billion-context-pi@${"0.1.26"}` : "";
|
|
8213
8236
|
lines.push("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E");
|
|
8214
8237
|
lines.push("\u2502 ACP Context Analysis \u2502");
|
|
8215
8238
|
lines.push("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F");
|
|
@@ -8567,7 +8590,7 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
8567
8590
|
const data = await res.json();
|
|
8568
8591
|
const latest = data.version;
|
|
8569
8592
|
if (!latest) return;
|
|
8570
|
-
const current = runtimeVersion ?? "0.1.
|
|
8593
|
+
const current = runtimeVersion ?? "0.1.26";
|
|
8571
8594
|
debug.event("update-check", {
|
|
8572
8595
|
current,
|
|
8573
8596
|
latest,
|
|
@@ -8602,7 +8625,7 @@ import { readFile as readFile2, writeFile as writeFile4, stat, copyFile, rename
|
|
|
8602
8625
|
import { existsSync } from "fs";
|
|
8603
8626
|
import { homedir as homedir4 } from "os";
|
|
8604
8627
|
import { join as join6 } from "path";
|
|
8605
|
-
var
|
|
8628
|
+
var ACP_TOOLS2 = ["compress", "decompress", "search_context", "acp_status"];
|
|
8606
8629
|
var BUILTIN_DEFAULT_TOOLS = {
|
|
8607
8630
|
advisor: ["read", "grep", "find", "ls", "bash", "intercom"],
|
|
8608
8631
|
"context-builder": ["read", "grep", "find", "ls", "bash", "write", "web_search", "intercom"],
|
|
@@ -8622,9 +8645,9 @@ function resolveAgentDir() {
|
|
|
8622
8645
|
}
|
|
8623
8646
|
function desiredTools(existing, name) {
|
|
8624
8647
|
const base = Array.isArray(existing?.tools) && existing.tools.length > 0 ? [...existing.tools] : [...BUILTIN_DEFAULT_TOOLS[name] ?? []];
|
|
8625
|
-
const hasAll =
|
|
8648
|
+
const hasAll = ACP_TOOLS2.every((t) => base.includes(t));
|
|
8626
8649
|
if (hasAll) return { tools: base, changed: false };
|
|
8627
|
-
for (const t of
|
|
8650
|
+
for (const t of ACP_TOOLS2) if (!base.includes(t)) base.push(t);
|
|
8628
8651
|
return { tools: base, changed: true };
|
|
8629
8652
|
}
|
|
8630
8653
|
async function ensureSubagentAcpTools(settingsPath) {
|
|
@@ -8695,7 +8718,7 @@ async function ensureSubagentAcpTools(settingsPath) {
|
|
|
8695
8718
|
if (typeof v !== "object" || v === null) throw new Error("agentOverrides missing after write");
|
|
8696
8719
|
for (const name of Object.keys(BUILTIN_DEFAULT_TOOLS)) {
|
|
8697
8720
|
const tools = v[name]?.tools;
|
|
8698
|
-
if (!Array.isArray(tools) || !
|
|
8721
|
+
if (!Array.isArray(tools) || !ACP_TOOLS2.every((t) => tools.includes(t))) {
|
|
8699
8722
|
throw new Error(`${name} missing ACP tools after write`);
|
|
8700
8723
|
}
|
|
8701
8724
|
}
|