@bermudi/pi-delegate 0.1.1 → 0.1.3
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 +3 -2
- package/agents.ts +163 -17
- package/concurrency.ts +90 -10
- package/config.ts +61 -0
- package/delegate.ts +14 -0
- package/dispatch.ts +126 -21
- package/extension.ts +309 -62
- package/file-tracking.ts +27 -5
- package/format.ts +46 -7
- package/leaf.ts +48 -0
- package/lifecycle.ts +129 -35
- package/manual.ts +38 -10
- package/package.json +4 -1
- package/patches/@marcfargas%2Fpi-test-harness@0.6.1.patch +13 -0
- package/render-branches.ts +31 -13
- package/render-result.ts +12 -0
- package/runner.ts +237 -42
- package/schema.ts +204 -47
- package/status.ts +68 -2
- package/task-resolution.ts +101 -65
- package/telemetry.ts +738 -0
- package/tickets.ts +196 -61
- package/tools.ts +16 -15
- package/types.ts +71 -13
- package/usage.ts +19 -0
package/types.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
} from "@earendil-works/pi-coding-agent";
|
|
13
13
|
import type { Static } from "@sinclair/typebox";
|
|
14
14
|
import type { delegateArgumentsSchema } from "./schema.ts";
|
|
15
|
+
import type { CallRecord } from "./telemetry.ts";
|
|
15
16
|
|
|
16
17
|
export interface AgentConfig {
|
|
17
18
|
name: string;
|
|
@@ -25,18 +26,37 @@ export interface AgentConfig {
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
// ── Tool parameter types — derived from the TypeBox schema ────────────────
|
|
28
|
-
// `delegateArgumentsSchema` in schema.ts is the
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
// The import is type-only, so the schema.ts ↔ types.ts cycle is erased
|
|
32
|
-
// compile time.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
// `delegateArgumentsSchema` in schema.ts is the canonical provider-visible
|
|
30
|
+
// shape. The public types add deprecated `action` aliases so existing TypeScript
|
|
31
|
+
// callers remain source-compatible without advertising the overloaded fields to
|
|
32
|
+
// models. The import is type-only, so the schema.ts ↔ types.ts cycle is erased
|
|
33
|
+
// at compile time.
|
|
34
|
+
|
|
35
|
+
type CanonicalDelegateArguments = Static<typeof delegateArgumentsSchema>;
|
|
36
|
+
type CanonicalTaskDef = NonNullable<
|
|
37
|
+
CanonicalDelegateArguments["tasks"]
|
|
38
|
+
>[number];
|
|
39
|
+
|
|
36
40
|
/** Top-level async ticket action: "poll" | "cancel" | "wait". */
|
|
37
|
-
export type
|
|
41
|
+
export type TicketAction = NonNullable<
|
|
42
|
+
CanonicalDelegateArguments["ticketAction"]
|
|
43
|
+
>;
|
|
38
44
|
/** Per-task session action: "prompt" | "close" | "list". */
|
|
39
|
-
export type SessionAction = NonNullable<
|
|
45
|
+
export type SessionAction = NonNullable<CanonicalTaskDef["sessionAction"]>;
|
|
46
|
+
|
|
47
|
+
export type TaskDef = CanonicalTaskDef & {
|
|
48
|
+
/** @deprecated Use `sessionAction` instead. Runtime normalization still accepts this alias. */
|
|
49
|
+
action?: SessionAction;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type DelegateArguments = Omit<CanonicalDelegateArguments, "tasks"> & {
|
|
53
|
+
/** @deprecated Use `ticketAction` instead. Runtime normalization still accepts this alias. */
|
|
54
|
+
action?: TicketAction;
|
|
55
|
+
tasks?: TaskDef[];
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/** @deprecated Use `TicketAction` instead. */
|
|
59
|
+
export type DelegateAction = TicketAction;
|
|
40
60
|
|
|
41
61
|
// ── Async Ticket Types ─────────────────────────────────────────────────────
|
|
42
62
|
|
|
@@ -61,8 +81,22 @@ export interface AsyncTicket {
|
|
|
61
81
|
controller: AbortController;
|
|
62
82
|
error?: string;
|
|
63
83
|
parentModelId?: string;
|
|
84
|
+
/** Session-tree leaf active when the ticket was spawned (see leaf.ts).
|
|
85
|
+
* `undefined` = the leaf the session opened on. Compared at delivery time
|
|
86
|
+
* so results are not used to wake the agent on a foreign branch. */
|
|
87
|
+
spawnLeafId?: string | null;
|
|
64
88
|
/** Active blocking waiters. Resolved by terminal delivery or timeout/abort. */
|
|
65
89
|
waiters?: TicketWaiter[];
|
|
90
|
+
/** Telemetry call span id attached to this async ticket. */
|
|
91
|
+
callId?: string;
|
|
92
|
+
/** Telemetry call span start timestamp for accurate wall-time on cancellation. */
|
|
93
|
+
callStartedAt?: number;
|
|
94
|
+
/** Snapshot of the call row at spawn, used to write the cancelled/settled row. */
|
|
95
|
+
callRecord?: CallRecord;
|
|
96
|
+
/** Runtime generation for rejecting shutdown writes from stale tickets. */
|
|
97
|
+
telemetryGeneration?: number;
|
|
98
|
+
/** Resolves after every async worker has settled, including shutdown aborts. */
|
|
99
|
+
completion?: Promise<void>;
|
|
66
100
|
}
|
|
67
101
|
|
|
68
102
|
/** Live parent settings captured when a delegate call starts. The built-in
|
|
@@ -81,6 +115,7 @@ export interface ReuseIntent {
|
|
|
81
115
|
}
|
|
82
116
|
|
|
83
117
|
export interface ResolvedTask {
|
|
118
|
+
id?: string;
|
|
84
119
|
prompt: string;
|
|
85
120
|
agent?: string;
|
|
86
121
|
model: Model<Api>;
|
|
@@ -90,8 +125,10 @@ export interface ResolvedTask {
|
|
|
90
125
|
cwd: string;
|
|
91
126
|
context?: "fresh" | "with-parent-transcript";
|
|
92
127
|
sessionId?: string;
|
|
93
|
-
|
|
128
|
+
sessionAction?: SessionAction;
|
|
94
129
|
resumeFrom?: string;
|
|
130
|
+
/** Hard wall-clock budget in milliseconds, measured from task start. */
|
|
131
|
+
deadlineMs?: number;
|
|
95
132
|
agentName: string;
|
|
96
133
|
warnings: string[];
|
|
97
134
|
/** Explicit settings that must match a live pooled session on reuse. */
|
|
@@ -117,10 +154,14 @@ export interface ToolActivity {
|
|
|
117
154
|
* - `model_error`: the failure is attributable to the resolved model/provider
|
|
118
155
|
* (account usage limit, quota exhausted, auth lost) — not transient for that
|
|
119
156
|
* model, so same-model retry is pointless. The parent should resume with a
|
|
120
|
-
* different `model` (see `resumeFrom` + `model`).
|
|
121
|
-
|
|
157
|
+
* different `model` (see `resumeFrom` + `model`).
|
|
158
|
+
* - `deadline_exceeded`: the task's `deadlineMs` wall-clock budget expired
|
|
159
|
+
* (measured from when the task left the concurrency queue). The prompt was
|
|
160
|
+
* cooperatively aborted; completed side effects are not rolled back. */
|
|
161
|
+
export type TaskFailureKind = "stalled" | "model_error" | "deadline_exceeded";
|
|
122
162
|
|
|
123
163
|
export interface TaskProgress {
|
|
164
|
+
id?: string;
|
|
124
165
|
index: number;
|
|
125
166
|
agent: string;
|
|
126
167
|
task: string;
|
|
@@ -146,9 +187,13 @@ export interface DelegateDetails {
|
|
|
146
187
|
ticketId?: string;
|
|
147
188
|
/** Terminal/live ticket status when this result comes from an async ticket. */
|
|
148
189
|
status?: AsyncTicket["status"];
|
|
190
|
+
/** Global overlap warning derived from result.attributedFiles, surfaced in both
|
|
191
|
+
* the textual content and the custom TUI. */
|
|
192
|
+
overlapWarning?: string;
|
|
149
193
|
}
|
|
150
194
|
|
|
151
195
|
export interface TaskResult {
|
|
196
|
+
id?: string;
|
|
152
197
|
agent: string;
|
|
153
198
|
output: string;
|
|
154
199
|
error?: string;
|
|
@@ -167,7 +212,14 @@ export interface TaskResult {
|
|
|
167
212
|
* Pi sums `cost.total` for nested usage anyway. */
|
|
168
213
|
usage: Usage;
|
|
169
214
|
sessionFile?: string;
|
|
215
|
+
/** All files the subagent is known to have touched, including bash mutations
|
|
216
|
+
* captured via git diff and other tasks' concurrent git changes. This is a
|
|
217
|
+
* best-effort, repository-wide list for display, not for attribution. */
|
|
170
218
|
touchedFiles: string[];
|
|
219
|
+
/** Files directly attributable to this task's edit/write tool calls. Used
|
|
220
|
+
* for overlap detection so concurrent tasks in the same repo do not
|
|
221
|
+
* fabricate false conflicts from shared git snapshots. */
|
|
222
|
+
attributedFiles?: string[];
|
|
171
223
|
}
|
|
172
224
|
|
|
173
225
|
/** Single source of truth for a subagent's runtime configuration.
|
|
@@ -204,6 +256,12 @@ export interface TaskRunEnv {
|
|
|
204
256
|
onProgress: (p: TaskProgress, u: AgentProgressUpdate) => void;
|
|
205
257
|
/** Called after every TaskProgress mutation (early-returns, completion). Sync uses this to fire onUpdate. */
|
|
206
258
|
onStatusChange?: () => void;
|
|
259
|
+
/** Telemetry call id for this dispatch. undefined when telemetry is disabled or not started. */
|
|
260
|
+
telemetryCallId?: string;
|
|
261
|
+
/** Runtime generation for rejecting writes from a stale shutdown worker. */
|
|
262
|
+
telemetryGeneration?: number;
|
|
263
|
+
/** Whether this task is part of an async ticket. */
|
|
264
|
+
async?: boolean;
|
|
207
265
|
}
|
|
208
266
|
|
|
209
267
|
/** Structural subset of Pi's `ExtensionContext` used by delegate's
|
package/usage.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentSession } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { Usage } from "@earendil-works/pi-ai";
|
|
3
|
+
import type { TaskResult } from "./types.ts";
|
|
3
4
|
|
|
4
5
|
/** Snapshot of the cumulative session usage fields we read for delta accounting. */
|
|
5
6
|
export interface SessionUsageSnapshot {
|
|
@@ -119,3 +120,21 @@ export function sumUsage(usages: readonly (Usage | undefined)[]): Usage {
|
|
|
119
120
|
emptyUsage(),
|
|
120
121
|
);
|
|
121
122
|
}
|
|
123
|
+
|
|
124
|
+
/** Aggregate the completed result rows used by async call telemetry. */
|
|
125
|
+
export function aggregateTaskResults(
|
|
126
|
+
results: readonly (TaskResult | undefined)[],
|
|
127
|
+
): { totalTokens: number; totalCost: number } {
|
|
128
|
+
return results
|
|
129
|
+
.filter(
|
|
130
|
+
(result): result is TaskResult =>
|
|
131
|
+
result !== undefined && "touchedFiles" in result,
|
|
132
|
+
)
|
|
133
|
+
.reduce(
|
|
134
|
+
(total, result) => ({
|
|
135
|
+
totalTokens: total.totalTokens + result.tokens,
|
|
136
|
+
totalCost: total.totalCost + (result.usage?.cost?.total ?? 0),
|
|
137
|
+
}),
|
|
138
|
+
{ totalTokens: 0, totalCost: 0 },
|
|
139
|
+
);
|
|
140
|
+
}
|