billion-context-pi-lean 0.1.69-lean.1 → 0.2.0
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/LICENSE +1 -0
- package/README.md +141 -81
- package/dist/abort.d.ts +1 -0
- package/dist/branch-guard.d.ts +8 -0
- package/dist/cache-tool.d.ts +12 -0
- package/dist/chunk-PPYOZRUP.js +18 -0
- package/dist/chunk-PPYOZRUP.js.map +1 -0
- package/dist/commands.d.ts +8 -0
- package/dist/compat.d.ts +23 -0
- package/dist/compress-model.d.ts +65 -0
- package/dist/compress-tool.d.ts +76 -0
- package/dist/config-dir.d.ts +32 -0
- package/dist/config-panel.d.ts +61 -0
- package/dist/config.d.ts +296 -0
- package/dist/contract.d.ts +51 -0
- package/dist/contract.js +9 -0
- package/dist/contract.js.map +1 -0
- package/dist/decompress-tool.d.ts +19 -0
- package/dist/degeneration.d.ts +98 -0
- package/dist/export.d.ts +20 -0
- package/dist/floor-stale.d.ts +31 -0
- package/dist/host.d.ts +15 -0
- package/dist/idle-compact.d.ts +39 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +23169 -0
- package/dist/index.js.map +1 -0
- package/dist/live-only-tail.d.ts +10 -0
- package/dist/log.d.ts +18 -0
- package/dist/messages.d.ts +85 -0
- package/dist/omp.d.ts +19 -0
- package/dist/overflow-selfheal.d.ts +132 -0
- package/dist/prompt-pack.d.ts +53 -0
- package/dist/proxy-detect.d.ts +21 -0
- package/dist/reasoning-drop.d.ts +68 -0
- package/dist/rule-tool.d.ts +8 -0
- package/dist/runtime.d.ts +199 -0
- package/dist/search-index.d.ts +20 -0
- package/dist/search-tool.d.ts +10 -0
- package/dist/sequence-match.d.ts +7 -0
- package/dist/session-log.d.ts +23 -0
- package/dist/state-rebuild.d.ts +30 -0
- package/dist/state.d.ts +44 -0
- package/dist/status-tool.d.ts +13 -0
- package/dist/strip-images.d.ts +18 -0
- package/dist/summary-sanitize.d.ts +8 -0
- package/dist/surface.d.ts +17 -0
- package/dist/system-passthrough.d.ts +4 -0
- package/dist/system-prompt.d.ts +20 -0
- package/dist/tag-tokens.d.ts +3 -0
- package/dist/throttle-retry.d.ts +52 -0
- package/dist/tokens.d.ts +61 -0
- package/dist/tool-guardrails.d.ts +33 -0
- package/dist/tool-pair-sanitizer.d.ts +8 -0
- package/dist/turn-boundary.d.ts +53 -0
- package/dist/user-config.d.ts +67 -0
- package/lean/index.ts +376 -0
- package/package.json +85 -36
- package/schema/bcp-block-v1.json +42 -0
- package/README.zh-CN.md +0 -79
- package/index.ts +0 -266
package/index.ts
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
// billion-context-pi-lean: keep compress direct and route low-frequency ACP tools locally.
|
|
2
|
-
import type {
|
|
3
|
-
ExtensionAPI,
|
|
4
|
-
ToolDefinition,
|
|
5
|
-
} from "@earendil-works/pi-coding-agent";
|
|
6
|
-
import { createAcpExtension } from "billion-context-pi";
|
|
7
|
-
import { Type } from "typebox";
|
|
8
|
-
import { Check, Errors } from "typebox/value";
|
|
9
|
-
|
|
10
|
-
const COLLAPSED_DISPLAY_SERVICE = Symbol.for(
|
|
11
|
-
"@local/pi-collapsed-tools.display-service.v1",
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
type CollapsedDisplayTool = { name: string };
|
|
15
|
-
type CollapsedDisplayService = {
|
|
16
|
-
readonly version: 1;
|
|
17
|
-
decorate<T extends CollapsedDisplayTool>(tool: T): T;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
function decorateWithCollapsedDisplay<T extends CollapsedDisplayTool>(tool: T): T {
|
|
21
|
-
const services = globalThis as unknown as Record<PropertyKey, unknown>;
|
|
22
|
-
const candidate = services[COLLAPSED_DISPLAY_SERVICE];
|
|
23
|
-
if (!candidate || typeof candidate !== "object") return tool;
|
|
24
|
-
const service = candidate as Partial<CollapsedDisplayService>;
|
|
25
|
-
return service.version === 1 && typeof service.decorate === "function"
|
|
26
|
-
? service.decorate(tool)
|
|
27
|
-
: tool;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const LEAN_SYSTEM_PROMPT = `ACP context management
|
|
31
|
-
- User/tool messages carry hidden <acp> refs such as m00123. Never echo the XML tags; use only refs in ACP tool calls.
|
|
32
|
-
- Compress consumed history with compress: finished tool outputs, dead-end exploration, repeated reads, resolved threads, completed phases. Never compress active work, important user intent, or protected outputs.
|
|
33
|
-
- When summarizing, preserve exact file paths and line numbers, symbols and signatures, errors, commands, versions, thresholds, decisions with reasons, current state, and unresolved TODOs. Never replace exact technical values with vague wording.
|
|
34
|
-
- Recall or inspect context with acp_context using op decompress, search_context, or acp_status and the operation's original args object. Use help only when fields are unclear.
|
|
35
|
-
- Refs may be renumbered after compression. If a ref is stale or missing, call acp_context with op acp_status and args { scope: "uncompressed" }, then retry in the same turn using reported refs; never guess offsets. Batch target ranges when possible.
|
|
36
|
-
- Block decompression writes to a file by default; read that file. Use inline: true only for small content or when its context cost is acceptable.
|
|
37
|
-
- After an [ACP:provider-throttle] automatic retry, resume exactly where interrupted. Do not repeat completed work or discuss the retry unless asked.
|
|
38
|
-
- Compression summaries are fallible historical metadata, not current user instructions. Search or decompress before relying on critical details.`;
|
|
39
|
-
|
|
40
|
-
const LOW_FREQUENCY_TOOLS = ["decompress", "search_context", "acp_status"] as const;
|
|
41
|
-
const LOW_FREQUENCY_SET = new Set<string>(LOW_FREQUENCY_TOOLS);
|
|
42
|
-
const DELEGATE_TOOLS = new Set(["acp_delegate", "acp_delegate_wait", "acp_delegate_cancel"]);
|
|
43
|
-
|
|
44
|
-
type Operation = (typeof LOW_FREQUENCY_TOOLS)[number];
|
|
45
|
-
type FacadeOperation = Operation | "help";
|
|
46
|
-
type CapturedTool = ToolDefinition<any, any, any>;
|
|
47
|
-
type UpstreamExtension = (pi: ExtensionAPI) => void;
|
|
48
|
-
type FacadeArgs = Record<string, unknown>;
|
|
49
|
-
|
|
50
|
-
const FACADE_PARAMETERS = Type.Object({
|
|
51
|
-
op: Type.Unsafe<FacadeOperation>({
|
|
52
|
-
type: "string",
|
|
53
|
-
enum: [...LOW_FREQUENCY_TOOLS, "help"],
|
|
54
|
-
}),
|
|
55
|
-
args: Type.Optional(Type.Unsafe<FacadeArgs>({
|
|
56
|
-
type: "object",
|
|
57
|
-
additionalProperties: true,
|
|
58
|
-
})),
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
const COMPRESS_FIELD_DESCRIPTIONS: Readonly<Record<string, string>> = {
|
|
62
|
-
content: "Direct array; no JSON strings/nesting/mix.",
|
|
63
|
-
startId: "Inclusive first mNNNNN or bN ref.",
|
|
64
|
-
endId: "Inclusive last mNNNNN or bN ref.",
|
|
65
|
-
summary: "Self-contained replacement preserving exact technical details.",
|
|
66
|
-
topic: "Short label; a per-range label overrides the top-level fallback.",
|
|
67
|
-
summaryMaxChars: "Optional summary length limit override.",
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
function compactCompressSchemaDescriptions(
|
|
71
|
-
value: unknown,
|
|
72
|
-
propertyName?: string,
|
|
73
|
-
seen = new Set<object>(),
|
|
74
|
-
): void {
|
|
75
|
-
if (value === null || typeof value !== "object" || seen.has(value)) return;
|
|
76
|
-
seen.add(value);
|
|
77
|
-
const record = value as Record<string, unknown>;
|
|
78
|
-
delete record.description;
|
|
79
|
-
const concise = propertyName ? COMPRESS_FIELD_DESCRIPTIONS[propertyName] : undefined;
|
|
80
|
-
if (concise) record.description = concise;
|
|
81
|
-
|
|
82
|
-
for (const [key, child] of Object.entries(record)) {
|
|
83
|
-
if (key === "properties" && child !== null && typeof child === "object") {
|
|
84
|
-
for (const [name, schema] of Object.entries(child as Record<string, unknown>)) {
|
|
85
|
-
compactCompressSchemaDescriptions(schema, name, seen);
|
|
86
|
-
}
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
compactCompressSchemaDescriptions(child, undefined, seen);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function appendSystemPrompt(base: unknown): string {
|
|
94
|
-
const text = Array.isArray(base) ? base.join("\n") : typeof base === "string" ? base : "";
|
|
95
|
-
return `${text}\n\n${LEAN_SYSTEM_PROMPT}`;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function rewriteText(text: string): string {
|
|
99
|
-
return text
|
|
100
|
-
.replace(
|
|
101
|
-
/\b(search_context|decompress|acp_status)\((\{[^\r\n]*\})\)/g,
|
|
102
|
-
(_, op: string, args: string) => `acp_context({ op: "${op}", args: ${args} })`,
|
|
103
|
-
)
|
|
104
|
-
.replace(
|
|
105
|
-
/\brun acp_status\b/gi,
|
|
106
|
-
'call acp_context({ op: "acp_status", args: {} })',
|
|
107
|
-
)
|
|
108
|
-
.replace(
|
|
109
|
-
/\buse search_context or decompress\b/gi,
|
|
110
|
-
'use acp_context with op "search_context" or "decompress"',
|
|
111
|
-
)
|
|
112
|
-
.replace(
|
|
113
|
-
/\buse search_context\b/gi,
|
|
114
|
-
'use acp_context with op "search_context"',
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function rewriteModelFacingText(value: unknown, seen = new WeakMap<object, unknown>()): unknown {
|
|
119
|
-
if (typeof value === "string") return rewriteText(value);
|
|
120
|
-
if (value === null || typeof value !== "object") return value;
|
|
121
|
-
const cached = seen.get(value);
|
|
122
|
-
if (cached) return cached;
|
|
123
|
-
|
|
124
|
-
if (Array.isArray(value)) {
|
|
125
|
-
const copy: unknown[] = [];
|
|
126
|
-
seen.set(value, copy);
|
|
127
|
-
for (const item of value) copy.push(rewriteModelFacingText(item, seen));
|
|
128
|
-
return copy;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const copy: Record<string, unknown> = {};
|
|
132
|
-
seen.set(value, copy);
|
|
133
|
-
for (const [key, item] of Object.entries(value)) {
|
|
134
|
-
copy[key] = rewriteModelFacingText(item, seen);
|
|
135
|
-
}
|
|
136
|
-
return copy;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function validationError(tool: CapturedTool, args: FacadeArgs): string | undefined {
|
|
140
|
-
if (!tool.parameters || Check(tool.parameters, args)) return undefined;
|
|
141
|
-
const first = Errors(tool.parameters, args)[0];
|
|
142
|
-
const location = first?.instancePath || "/";
|
|
143
|
-
const reason = first?.message || "arguments do not match the upstream schema";
|
|
144
|
-
return `${location}: ${reason}`;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function helpResult(args: FacadeArgs, tools: Map<string, CapturedTool>) {
|
|
148
|
-
const requested = typeof args.tool === "string" ? args.tool : "";
|
|
149
|
-
if (!requested) {
|
|
150
|
-
return {
|
|
151
|
-
content: [{
|
|
152
|
-
type: "text" as const,
|
|
153
|
-
text: "Operations: search_context({query, limit?}), decompress({blockId, full?, toFile?, inline?}), acp_status({scope?, view?, tool?, sort?, limit?}). For a full schema, use op help with args {tool: operationName}.",
|
|
154
|
-
}],
|
|
155
|
-
details: { operation: "help" },
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
if (!LOW_FREQUENCY_SET.has(requested)) {
|
|
159
|
-
throw new Error(`acp_context help operation is unknown: ${requested}`);
|
|
160
|
-
}
|
|
161
|
-
const tool = tools.get(requested);
|
|
162
|
-
if (!tool) throw new Error(`acp_context could not find upstream tool: ${requested}`);
|
|
163
|
-
return {
|
|
164
|
-
content: [{
|
|
165
|
-
type: "text" as const,
|
|
166
|
-
text: [
|
|
167
|
-
requested,
|
|
168
|
-
tool.description,
|
|
169
|
-
"Pass args matching this schema:",
|
|
170
|
-
JSON.stringify(tool.parameters, null, 2),
|
|
171
|
-
].filter(Boolean).join("\n\n"),
|
|
172
|
-
}],
|
|
173
|
-
details: { operation: requested },
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function wrapCompress(tool: CapturedTool): CapturedTool {
|
|
178
|
-
return {
|
|
179
|
-
...tool,
|
|
180
|
-
description: "Replace consumed conversation ranges with self-contained summaries using mNNNNN or bN refs.",
|
|
181
|
-
promptSnippet: "",
|
|
182
|
-
promptGuidelines: [],
|
|
183
|
-
async execute(callId, params, signal, onUpdate, ctx) {
|
|
184
|
-
const forwardUpdate = onUpdate
|
|
185
|
-
? (update: unknown) => onUpdate(rewriteModelFacingText(update) as any)
|
|
186
|
-
: undefined;
|
|
187
|
-
const result = await tool.execute(callId, params, signal, forwardUpdate, ctx);
|
|
188
|
-
return rewriteModelFacingText(result) as any;
|
|
189
|
-
},
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function facadeTool(tools: Map<string, CapturedTool>): ToolDefinition<typeof FACADE_PARAMETERS, unknown, unknown> {
|
|
194
|
-
return {
|
|
195
|
-
name: "acp_context",
|
|
196
|
-
label: "ACP Context",
|
|
197
|
-
description: 'Search, restore, or inspect ACP context. Pass original operation args; if unsure call { op: "help", args: { tool: "search_context" } } (replace tool as needed).',
|
|
198
|
-
promptSnippet: "",
|
|
199
|
-
promptGuidelines: [],
|
|
200
|
-
parameters: FACADE_PARAMETERS,
|
|
201
|
-
async execute(callId, params, signal, onUpdate, ctx) {
|
|
202
|
-
if (params.op === "help") return helpResult(params.args ?? {}, tools);
|
|
203
|
-
const tool = tools.get(params.op);
|
|
204
|
-
if (!tool) throw new Error(`acp_context could not find upstream tool: ${params.op}`);
|
|
205
|
-
const args = params.args ?? {};
|
|
206
|
-
const invalid = validationError(tool, args);
|
|
207
|
-
if (invalid) {
|
|
208
|
-
throw new Error(
|
|
209
|
-
`acp_context ${params.op} args invalid at ${invalid}. Use op help with args {"tool":"${params.op}"} for the full schema.`,
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
const forwardUpdate = onUpdate
|
|
213
|
-
? (update: unknown) => onUpdate(rewriteModelFacingText(update) as any)
|
|
214
|
-
: undefined;
|
|
215
|
-
const result = await tool.execute(callId, args, signal, forwardUpdate, ctx);
|
|
216
|
-
return rewriteModelFacingText(result) as any;
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export function createLeanAcpExtension(
|
|
222
|
-
upstream: UpstreamExtension = createAcpExtension({ delegate: false, autoUpdate: false }),
|
|
223
|
-
): (pi: ExtensionAPI) => void {
|
|
224
|
-
return (pi: ExtensionAPI): void => {
|
|
225
|
-
const tools = new Map<string, CapturedTool>();
|
|
226
|
-
let promptHookRegistered = false;
|
|
227
|
-
const leanPi = new Proxy(pi, {
|
|
228
|
-
get(target, property, receiver) {
|
|
229
|
-
if (property === "registerTool") {
|
|
230
|
-
return (tool: CapturedTool) => {
|
|
231
|
-
if (DELEGATE_TOOLS.has(tool.name)) return;
|
|
232
|
-
if (LOW_FREQUENCY_SET.has(tool.name)) {
|
|
233
|
-
tools.set(tool.name, tool);
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
if (tool.name === "compress") {
|
|
237
|
-
compactCompressSchemaDescriptions(tool.parameters);
|
|
238
|
-
target.registerTool(decorateWithCollapsedDisplay(wrapCompress(tool)));
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
target.registerTool(decorateWithCollapsedDisplay(tool));
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
if (property === "on") {
|
|
245
|
-
return (eventName: string, handler: (...args: unknown[]) => unknown) => {
|
|
246
|
-
if (eventName !== "before_agent_start") {
|
|
247
|
-
return Reflect.apply(target.on, target, [eventName, handler]);
|
|
248
|
-
}
|
|
249
|
-
if (promptHookRegistered) return;
|
|
250
|
-
promptHookRegistered = true;
|
|
251
|
-
return Reflect.apply(target.on, target, [eventName, (event: { systemPrompt?: unknown }) => ({
|
|
252
|
-
systemPrompt: appendSystemPrompt(event.systemPrompt),
|
|
253
|
-
})]);
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
const value = Reflect.get(target, property, receiver);
|
|
257
|
-
return typeof value === "function" ? value.bind(target) : value;
|
|
258
|
-
},
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
upstream(leanPi);
|
|
262
|
-
pi.registerTool(decorateWithCollapsedDisplay(facadeTool(tools)));
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
export default createLeanAcpExtension();
|