billion-context-pi 0.1.57-pr.284.92 → 0.1.57
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 +1 -1
- package/dist/config.d.ts +38 -0
- package/dist/delegate-tool.d.ts +71 -1
- package/dist/fleet-inspector.d.ts +42 -0
- package/dist/index.js +4716 -546
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -133,7 +133,7 @@ Worker runs on Pi's full default toolset - no `--tools` allowlist is applied, so
|
|
|
133
133
|
|
|
134
134
|
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.
|
|
135
135
|
|
|
136
|
-
- **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.
|
|
136
|
+
- **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 — **unless the model already read the result file after the run finished** (detected via the `read` tool or a bash command referencing the file), in which case the notification is skipped: the model already has the result, so re-injecting it would only waste context. Set `delegate: { notifyIfRead: "always" }` in `acp.json` to restore the always-inject behavior.
|
|
137
137
|
- **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).
|
|
138
138
|
- **Failures are loud, never silent.** A run that fails (nonzero exit, spawn error, watchdog timeout) injects a `FAILED ⚠️` notification carrying a short error excerpt, so a failed delegate cannot hide among sibling completions. If a notification cannot be delivered at all, a recovery notice is attached to the next delegate notification or the next `acp_delegate` / `acp_delegate_wait` / `acp_delegate_cancel` tool result — a dispatched run's failure always reaches the model before it wraps up.
|
|
139
139
|
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import { type Config, type Prompts } from "acp-kernel";
|
|
2
2
|
import type { ThrottleRetryConfig } from "./throttle-retry.js";
|
|
3
|
+
/** Per-role delegate defaults. Lets long-lived automation pin a cheaper or
|
|
4
|
+
* more capable model and a thinking level per delegate role, so the main
|
|
5
|
+
* agent doesn't have to fill them in on every `acp_delegate()` call. */
|
|
6
|
+
export interface DelegateRoleConfig {
|
|
7
|
+
/** Default model for this role, as `"provider/id"`. Resolution priority:
|
|
8
|
+
* per-call `model` > this role default > parent agent's current model. A
|
|
9
|
+
* value that isn't a valid `"provider/id"` is ignored (treated as unset).
|
|
10
|
+
* If the configured model doesn't exist in the live registry, the child
|
|
11
|
+
* falls back to the parent model and a warning is logged — it never fails. */
|
|
12
|
+
model?: string;
|
|
13
|
+
/** Default thinking level for this role: one of off|minimal|low|medium|
|
|
14
|
+
* high|xhigh|max. Resolution priority: per-call `thinkingLevel` > this role
|
|
15
|
+
* default > global `delegate.thinkingLevel` > Pi's own default. An invalid
|
|
16
|
+
* value is ignored with a warning (never fails). */
|
|
17
|
+
thinkingLevel?: string;
|
|
18
|
+
}
|
|
3
19
|
/** Delegate sub-agent configuration. */
|
|
4
20
|
export interface DelegateConfig {
|
|
5
21
|
/** Enable acp_delegate tools (delegate/wait/cancel) and their system-prompt
|
|
@@ -37,6 +53,21 @@ export interface DelegateConfig {
|
|
|
37
53
|
* back to unlimited with a warning. Env `PI_ACP_DELEGATE_MAX_CONCURRENT`
|
|
38
54
|
* overrides this. See #294. */
|
|
39
55
|
maxConcurrent?: number;
|
|
56
|
+
/** Global default thinking level applied to every delegate when neither the
|
|
57
|
+
* per-call `thinkingLevel` nor the role's own `thinkingLevel` is set. One of
|
|
58
|
+
* off|minimal|low|medium|high|xhigh|max. When unset at all levels, no
|
|
59
|
+
* `--thinking` flag is passed and each child uses Pi's own default. */
|
|
60
|
+
thinkingLevel?: string;
|
|
61
|
+
/** Per-role defaults keyed by role name (reviewer/researcher/worker/planner/
|
|
62
|
+
* oracle, or any custom role). See DelegateRoleConfig. Only affects roles
|
|
63
|
+
* that are named here; other roles inherit the parent model + Pi defaults. */
|
|
64
|
+
agents?: Record<string, DelegateRoleConfig>;
|
|
65
|
+
/** What happens to the completion notification when the model has already
|
|
66
|
+
* read the delegate's result file after the run finished.
|
|
67
|
+
* "skip" (default) — the notification is not injected; the model already
|
|
68
|
+
* saw the result, so re-injecting it would only waste context.
|
|
69
|
+
* "always" — always inject the notification (previous behavior). */
|
|
70
|
+
notifyIfRead?: "skip" | "always";
|
|
40
71
|
}
|
|
41
72
|
/** Resolved delegate policy: what actually takes effect after merging acp.json,
|
|
42
73
|
* env overrides and defaults. Timeout fields are milliseconds; null means the
|
|
@@ -50,6 +81,13 @@ export interface DelegatePolicy {
|
|
|
50
81
|
asyncTimeoutMs: number | null;
|
|
51
82
|
/** Resolved cap on concurrent background delegates; Infinity = unlimited. */
|
|
52
83
|
maxConcurrent: number;
|
|
84
|
+
/** Global default thinking level (undefined when unset). */
|
|
85
|
+
thinkingLevel?: string;
|
|
86
|
+
/** Per-role defaults keyed by role name (undefined when unset). */
|
|
87
|
+
agents?: Record<string, DelegateRoleConfig>;
|
|
88
|
+
/** Whether to suppress the completion notification when the model already
|
|
89
|
+
* read the result file after the run finished. Always resolved ("skip" default). */
|
|
90
|
+
notifyIfRead: "skip" | "always";
|
|
53
91
|
}
|
|
54
92
|
export declare const DEFAULT_DELEGATE_POLICY: DelegatePolicy;
|
|
55
93
|
/** Compression tuning fields, shared by all three levels (global, provider,
|
package/dist/delegate-tool.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type ChildProcess, type SpawnOptions } from "node:child_process";
|
|
2
2
|
import { Type, type Static } from "typebox";
|
|
3
3
|
import type { AgentToolResult, ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
import { type DelegatePolicy } from "./config.js";
|
|
4
|
+
import { type DelegatePolicy, type DelegateRoleConfig } from "./config.js";
|
|
5
5
|
import { type Usage } from "./delegate-events.js";
|
|
6
|
+
export declare const OUT_DIR: string;
|
|
6
7
|
export declare function delegateStdinText(resumeFrom: boolean, task: string | undefined): string;
|
|
7
8
|
export declare function delegateSpawnOptions(cwd: string, env: NodeJS.ProcessEnv): SpawnOptions;
|
|
8
9
|
/** Child process env for a nested delegate: depth increments by one, and the
|
|
@@ -54,6 +55,15 @@ interface DelegateRun {
|
|
|
54
55
|
/** True while the run sits in the coalescing notification queue (scheduled
|
|
55
56
|
* for the next batched flush, not yet delivered). */
|
|
56
57
|
notifyQueued?: boolean;
|
|
58
|
+
/** When the model successfully read this run's result file (read tool, or a
|
|
59
|
+
* bash command referencing it). A read at/after finishedAt means the model
|
|
60
|
+
* already saw the final result — the completion notification is then
|
|
61
|
+
* suppressed (notifyIfRead: "skip"). */
|
|
62
|
+
readAt?: number;
|
|
63
|
+
/** True when the completion notification was suppressed because the model
|
|
64
|
+
* had already read the result file. Treated as delivered (injected=true)
|
|
65
|
+
* so wait/recovery never re-surface the result. */
|
|
66
|
+
readSuppressed?: boolean;
|
|
57
67
|
}
|
|
58
68
|
export declare function addDelegateUsage(u: Usage): void;
|
|
59
69
|
export declare function getDelegateUsage(): Usage | undefined;
|
|
@@ -77,6 +87,23 @@ export declare class ConcurrencyGate {
|
|
|
77
87
|
* launches FIFO (skipping any cancelled while queued). */
|
|
78
88
|
release(): void;
|
|
79
89
|
}
|
|
90
|
+
export declare function setDelegateDefaults(d: {
|
|
91
|
+
thinkingLevel?: string;
|
|
92
|
+
agents?: Record<string, DelegateRoleConfig>;
|
|
93
|
+
} | undefined): void;
|
|
94
|
+
export declare function resetDelegateDefaults(): void;
|
|
95
|
+
declare const VALID_THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
96
|
+
export declare function isValidThinkingLevel(v: unknown): v is (typeof VALID_THINKING_LEVELS)[number];
|
|
97
|
+
export declare function setDelegateNotifyIfRead(mode: "skip" | "always"): void;
|
|
98
|
+
/** Mark the run whose result file the model just read (via the `read` tool).
|
|
99
|
+
* Returns true when a run matched. A read of the final result file after the
|
|
100
|
+
* run finished means the model already saw the result — the completion
|
|
101
|
+
* notification is then suppressed (notifyIfRead: "skip"). */
|
|
102
|
+
export declare function markDelegateResultRead(filePath: string): boolean;
|
|
103
|
+
/** Mark runs referenced by a bash command (e.g. `cat <result file>`).
|
|
104
|
+
* Matches runIds appearing anywhere in the command string; only existing
|
|
105
|
+
* runs are affected, so task text that merely contains "del_..." is inert. */
|
|
106
|
+
export declare function markDelegateRunReadByCommand(command: string): boolean;
|
|
80
107
|
/** Snapshot of currently-running delegate runs, for the TUI status widget. */
|
|
81
108
|
export declare function runningRunsSnapshot(): {
|
|
82
109
|
runId: string;
|
|
@@ -84,6 +111,31 @@ export declare function runningRunsSnapshot(): {
|
|
|
84
111
|
task: string;
|
|
85
112
|
startedAt: number;
|
|
86
113
|
}[];
|
|
114
|
+
export interface FleetRunView {
|
|
115
|
+
runId: string;
|
|
116
|
+
agent: string;
|
|
117
|
+
task: string;
|
|
118
|
+
cwd: string;
|
|
119
|
+
startedAt: number;
|
|
120
|
+
finishedAt?: number;
|
|
121
|
+
status: RunStatus;
|
|
122
|
+
exitLabel: string;
|
|
123
|
+
timedOut?: string;
|
|
124
|
+
resumedFrom?: string;
|
|
125
|
+
/** Streamed reply text (always retained, even for cancelled runs). */
|
|
126
|
+
replyFile: string;
|
|
127
|
+
/** Live tool-activity log (async json-stream runs only). */
|
|
128
|
+
activityFile?: string;
|
|
129
|
+
sessionFile?: string;
|
|
130
|
+
usage?: Usage;
|
|
131
|
+
}
|
|
132
|
+
/** Running first (oldest spawn on top), then recently finished (newest first,
|
|
133
|
+
* capped) — the order the fleet inspector list shows. */
|
|
134
|
+
export declare function orderRunsForFleet(all: DelegateRun[]): DelegateRun[];
|
|
135
|
+
/** Display-safe snapshot of every delegate run known this session, for the
|
|
136
|
+
* fleet inspector (/acp-fleet). In-memory only: runs from previous pi
|
|
137
|
+
* processes are not listed (their files remain under OUT_DIR). */
|
|
138
|
+
export declare function fleetRunsSnapshot(): FleetRunView[];
|
|
87
139
|
/** Minimal writable surface accepted by makeEventApplier — real WriteStreams
|
|
88
140
|
* in production, in-memory collectors in tests. */
|
|
89
141
|
export interface EventApplierWriters {
|
|
@@ -125,6 +177,7 @@ declare const DelegateParams: Type.TObject<{
|
|
|
125
177
|
resumeFrom: Type.TOptional<Type.TString>;
|
|
126
178
|
cwd: Type.TOptional<Type.TString>;
|
|
127
179
|
model: Type.TOptional<Type.TString>;
|
|
180
|
+
thinkingLevel: Type.TOptional<Type.TString>;
|
|
128
181
|
async: Type.TOptional<Type.TBoolean>;
|
|
129
182
|
showThinking: Type.TOptional<Type.TBoolean>;
|
|
130
183
|
}>;
|
|
@@ -187,6 +240,7 @@ export declare function formatBatchRunSection(run: DelegateRun): string;
|
|
|
187
240
|
* in which case the caller delivers the full payload via formatRunResult(). */
|
|
188
241
|
export declare function injectedWaitMessage(run: {
|
|
189
242
|
injected?: boolean;
|
|
243
|
+
readSuppressed?: boolean;
|
|
190
244
|
result?: {
|
|
191
245
|
file: string;
|
|
192
246
|
};
|
|
@@ -227,6 +281,22 @@ export declare function asyncWatchdogDescription(): string;
|
|
|
227
281
|
* never exited). If a result was delivered (non-empty reply or stderr), the
|
|
228
282
|
* run counts as completed (0); otherwise it stays null = genuine failure. */
|
|
229
283
|
export declare function effectiveExitCode(code: number | null, output: string, stderr: string): number | null;
|
|
284
|
+
/** Pure read-after-finish predicate: should the completion notification be
|
|
285
|
+
* suppressed because the model already read the final result file? Only a
|
|
286
|
+
* read at/after finishedAt counts — a read while the run was still in flight
|
|
287
|
+
* (readAt < finishedAt) saw partial output, so the notification still goes
|
|
288
|
+
* out. Callers additionally gate on run.status === "completed": a FAILED
|
|
289
|
+
* run's file holds only partial output with no failure marker, so the model
|
|
290
|
+
* cannot tell it failed from the file — failure notifications are never
|
|
291
|
+
* suppressed (failures are loud). */
|
|
292
|
+
export declare function shouldSuppressRead(run: {
|
|
293
|
+
readAt?: number;
|
|
294
|
+
finishedAt?: number;
|
|
295
|
+
}, mode: "skip" | "always"): boolean;
|
|
296
|
+
/** Suppress the completion notification for a run the model already read:
|
|
297
|
+
* mark it delivered (so wait/recovery/flush never re-surface the result),
|
|
298
|
+
* account its usage in separate mode, and log the skip. Idempotent. */
|
|
299
|
+
export declare function applyReadSuppression(run: DelegateRun, runId: string): void;
|
|
230
300
|
/** status (set by finalize from the effective exit code) is the authority for
|
|
231
301
|
* the FAILED/completed decision; the raw code is diagnostic display only
|
|
232
302
|
* ("exit ?"), so the notification can never disagree with run.status. */
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { type FleetRunView } from "./delegate-tool.js";
|
|
3
|
+
export interface InspectorTheme {
|
|
4
|
+
fg(color: string, text: string): string;
|
|
5
|
+
bold(text: string): string;
|
|
6
|
+
bg(color: string, text: string): string;
|
|
7
|
+
italic?(text: string): string;
|
|
8
|
+
underline?(text: string): string;
|
|
9
|
+
strikethrough?(text: string): string;
|
|
10
|
+
}
|
|
11
|
+
export declare function formatDuration(ms: number): string;
|
|
12
|
+
export declare function statusIcon(status: FleetRunView["status"]): string;
|
|
13
|
+
export declare function usageSummary(usage: FleetRunView["usage"]): string | undefined;
|
|
14
|
+
export interface ListRow {
|
|
15
|
+
run: FleetRunView;
|
|
16
|
+
label: string;
|
|
17
|
+
detail: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function buildListRows(runs: FleetRunView[], now: number): ListRow[];
|
|
20
|
+
/** Last maxBytes of a file as utf8; a partial leading line is dropped so the
|
|
21
|
+
* tail always starts on a line boundary. Missing/unreadable → "". */
|
|
22
|
+
export declare function readTailSync(file: string | undefined, maxBytes: number): string;
|
|
23
|
+
/** First maxBytes of a file as utf8. Missing/unreadable → "". */
|
|
24
|
+
export declare function readHeadSync(file: string | undefined, maxBytes: number): string;
|
|
25
|
+
export interface TranscriptBlock {
|
|
26
|
+
kind: "user" | "thinking" | "text" | "toolCall" | "toolResult" | "meta";
|
|
27
|
+
name?: string;
|
|
28
|
+
text: string;
|
|
29
|
+
isError?: boolean;
|
|
30
|
+
args?: unknown;
|
|
31
|
+
}
|
|
32
|
+
/** Pi-style one-line summary of a tool call (mirrors pi's formatToolCall). */
|
|
33
|
+
export declare function formatToolLabel(name: string, args: unknown): string;
|
|
34
|
+
/** Parse a pi session .jsonl into display blocks (conversation + thinking + tools). */
|
|
35
|
+
export declare function parseSessionJsonl(raw: string): TranscriptBlock[];
|
|
36
|
+
export declare function renderListBody(rows: ListRow[], selIdx: number, theme: InspectorTheme, innerW: number): string[];
|
|
37
|
+
export declare function renderTranscriptBlocks(blocks: TranscriptBlock[], theme: InspectorTheme, innerW: number): string[];
|
|
38
|
+
/** Plain-text snapshot for non-TUI hosts (rpc/print/json). */
|
|
39
|
+
export declare function buildSnapshotText(runs: FleetRunView[], now: number): string;
|
|
40
|
+
/** Open the live fleet inspector: bordered TUI overlay in interactive mode,
|
|
41
|
+
* plain-text snapshot notification elsewhere. Resolves when the user closes it. */
|
|
42
|
+
export declare function openFleetInspector(ctx: ExtensionContext): Promise<void>;
|