@bermudi/pi-delegate 0.1.18 → 0.1.20
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 +64 -15
- package/agents.ts +1 -1
- package/assistant-preview.ts +31 -0
- package/browser-state.ts +250 -0
- package/browser.ts +334 -0
- package/concurrency.ts +7 -0
- package/delegate.ts +8 -0
- package/dispatch.ts +512 -163
- package/extension.ts +65 -28
- package/format.ts +27 -9
- package/host.ts +1 -1
- package/isolated-workspace.ts +154 -8
- package/lifecycle.ts +34 -20
- package/manual.ts +21 -8
- package/package.json +2 -1
- package/parent-context.ts +1 -1
- package/pause.ts +81 -0
- package/pool.ts +492 -428
- package/render-branches.ts +19 -5
- package/render-result.ts +7 -0
- package/runner.ts +55 -1
- package/runtime.ts +36 -0
- package/schema.ts +29 -18
- package/status.ts +38 -11
- package/task-resolution.ts +12 -9
- package/test-harness.ts +81 -0
- package/ticket-format.ts +29 -7
- package/tickets.ts +724 -576
- package/types.ts +33 -0
- package/workspace.ts +58 -27
package/ticket-format.ts
CHANGED
|
@@ -50,12 +50,18 @@ export function formatTicketAgentRoster(progress: TaskProgress[]): string {
|
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Copy-pasteable poll/cancel controls for a live ticket. Cancelling tickets
|
|
53
|
-
* keep poll (to watch unwind) but drop cancel (already requested).
|
|
53
|
+
* keep poll (to watch unwind) but drop cancel (already requested). Pause/
|
|
54
|
+
* resume needs the ticket's pause controller: without one, handlePause
|
|
55
|
+
* rejects the call, so no snippet is advertised.
|
|
54
56
|
*/
|
|
55
57
|
export function formatTicketControlSnippets(ticket: AsyncTicket): string {
|
|
56
58
|
if (ticket.status !== "running" && ticket.status !== "cancelling") return "";
|
|
57
59
|
let snippets = `\n poll: delegate({ ticketAction: "poll", ticket: "${ticket.id}" })`;
|
|
58
60
|
if (ticket.status === "running") {
|
|
61
|
+
if (ticket.pause) {
|
|
62
|
+
const action = ticket.pause.state !== "running" ? "resume" : "pause";
|
|
63
|
+
snippets += `\n ${action}: delegate({ ticketAction: "${action}", ticket: "${ticket.id}" })`;
|
|
64
|
+
}
|
|
59
65
|
snippets += `\n cancel: delegate({ ticketAction: "cancel", ticket: "${ticket.id}", force: true })`;
|
|
60
66
|
}
|
|
61
67
|
return snippets;
|
|
@@ -71,7 +77,11 @@ export function formatTicketRosterLine(
|
|
|
71
77
|
(p) => p.status === "done" || p.status === "failed",
|
|
72
78
|
).length;
|
|
73
79
|
const age = fmtDuration(now - ticket.created);
|
|
74
|
-
|
|
80
|
+
const state =
|
|
81
|
+
ticket.status === "running"
|
|
82
|
+
? (ticket.pause?.state ?? ticket.status)
|
|
83
|
+
: ticket.status;
|
|
84
|
+
return `${icon} ${ticket.id}${formatTicketAgentRoster(ticket.progress)} · ${finalized}/${ticket.progress.length} finalized · ${state} · ${age}${formatTicketControlSnippets(ticket)}`;
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
/** Full roster listing when poll is called without a ticket id. */
|
|
@@ -88,6 +98,8 @@ export function missingTicketPollText(ticketId: string): string {
|
|
|
88
98
|
|
|
89
99
|
/** Running-task line shared by poll snapshots and cancel previews. */
|
|
90
100
|
export function formatInFlightTaskLine(p: TaskProgress): string {
|
|
101
|
+
if (p.paused)
|
|
102
|
+
return `Ⅱ ${p.agent}${resumeMarker(p)}${formatTaskId(p.id)} · paused between turns`;
|
|
91
103
|
const parts: string[] = [formatActivityLabel(p)];
|
|
92
104
|
if (p.toolUses > 0)
|
|
93
105
|
parts.push(`${p.toolUses} tool${p.toolUses === 1 ? "" : "s"}`);
|
|
@@ -183,7 +195,10 @@ export function formatLiveTicketHeader(
|
|
|
183
195
|
).length;
|
|
184
196
|
const totalCount = ticket.progress.length;
|
|
185
197
|
const runningCount = ticket.progress.filter(
|
|
186
|
-
(p) => p.status === "running",
|
|
198
|
+
(p) => p.status === "running" && !p.paused,
|
|
199
|
+
).length;
|
|
200
|
+
const pausedCount = ticket.progress.filter(
|
|
201
|
+
(p) => p.status === "running" && p.paused,
|
|
187
202
|
).length;
|
|
188
203
|
const pendingCount = ticket.progress.filter(
|
|
189
204
|
(p) => p.status === "pending",
|
|
@@ -191,12 +206,15 @@ export function formatLiveTicketHeader(
|
|
|
191
206
|
const totalTools = ticket.progress.reduce((sum, p) => sum + p.toolUses, 0);
|
|
192
207
|
const totalTokens = ticket.progress.reduce((sum, p) => sum + p.tokens, 0);
|
|
193
208
|
const headerStatus =
|
|
194
|
-
ticket.status === "cancelling"
|
|
209
|
+
ticket.status === "cancelling"
|
|
210
|
+
? "CANCELLING"
|
|
211
|
+
: (ticket.pause?.state ?? "running").toUpperCase();
|
|
195
212
|
const headerParts: string[] = [
|
|
196
213
|
`Ticket ${ticket.id}: ${headerStatus}`,
|
|
197
214
|
`${settledCount}/${totalCount} finalized`,
|
|
198
215
|
];
|
|
199
216
|
if (runningCount > 0) headerParts.push(`${runningCount} active`);
|
|
217
|
+
if (pausedCount > 0) headerParts.push(`${pausedCount} paused`);
|
|
200
218
|
if (pendingCount > 0) headerParts.push(`${pendingCount} queued`);
|
|
201
219
|
if (failedCount > 0) headerParts.push(`${failedCount} failed`);
|
|
202
220
|
headerParts.push(`${totalTools} tool${totalTools === 1 ? "" : "s"}`);
|
|
@@ -209,6 +227,9 @@ export function liveTicketGuidance(ticket: AsyncTicket): string {
|
|
|
209
227
|
if (ticket.status === "cancelling") {
|
|
210
228
|
return "Cancellation requested. Active subagents are aborting and returning partial results. Wait without timeoutMs for final status; do not repeatedly poll.";
|
|
211
229
|
}
|
|
230
|
+
if (ticket.pause && ticket.pause.state !== "running") {
|
|
231
|
+
return `Pause requested: current turns may finish, then further turns and queued tasks stay blocked. Resume with delegate({ ticketAction: "resume", ticket: "${ticket.id}" }). Wait does not resume a paused ticket.`;
|
|
232
|
+
}
|
|
212
233
|
const settledCount = ticket.progress.filter(
|
|
213
234
|
(p) => p.status === "done" || p.status === "failed",
|
|
214
235
|
).length;
|
|
@@ -246,15 +267,16 @@ export function formatLiveTicketPoll(
|
|
|
246
267
|
findTouchedOverlaps(completedForOverlap),
|
|
247
268
|
);
|
|
248
269
|
const guidance = liveTicketGuidance(ticket);
|
|
270
|
+
const serializedNotice = ticket.serializedNotice ?? "";
|
|
249
271
|
const dispatchWarning = ticket.dispatchWarning
|
|
250
272
|
? `WARNING: ${ticket.dispatchWarning}`
|
|
251
273
|
: "";
|
|
252
274
|
return {
|
|
253
275
|
text: `${formatLiveTicketHeader(ticket, now)}\n${lines.join("\n")}${
|
|
254
276
|
guidance ? `\n\n${guidance}` : ""
|
|
255
|
-
}${
|
|
256
|
-
|
|
257
|
-
}`,
|
|
277
|
+
}${serializedNotice ? `\n\n${serializedNotice}` : ""}${
|
|
278
|
+
dispatchWarning ? `\n\n${dispatchWarning}` : ""
|
|
279
|
+
}${overlapWarning ? `\n\n${overlapWarning}` : ""}`,
|
|
258
280
|
completedResults,
|
|
259
281
|
overlapWarning,
|
|
260
282
|
};
|