@bermudi/pi-delegate 0.1.11 → 0.1.13

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/tickets.ts CHANGED
@@ -169,6 +169,7 @@ export function cancelTicketForShutdown(ticket: AsyncTicket): void {
169
169
  total_cost: totalCost,
170
170
  },
171
171
  ticket.telemetryGeneration,
172
+ ticket.telemetryConfig,
172
173
  );
173
174
  }
174
175
  }
@@ -238,6 +239,9 @@ export function formatCompletedTicket(
238
239
  parts.push(
239
240
  `${statusTag}${succeeded}/${ticket.results.length} ${completionLabel} · ${fmtDuration(elapsedTotal)} wall time\n`,
240
241
  );
242
+ if (ticket.dispatchWarning) {
243
+ parts.push(`WARNING: ${ticket.dispatchWarning}`);
244
+ }
241
245
 
242
246
  const pendingLabelFor = (index: number): string => {
243
247
  if (ticket.status !== "cancelled") {
@@ -258,7 +262,7 @@ export function formatCompletedTicket(
258
262
  parts.push(`[${pendingLabelFor(i)}]`);
259
263
  continue;
260
264
  }
261
- parts.push(...formatCompletedTask(t, r));
265
+ parts.push(...formatCompletedTask(t, r, ticket.config));
262
266
  }
263
267
 
264
268
  const completedResults = ticket.results.filter(
@@ -294,6 +298,7 @@ export function formatCompletedTicket(
294
298
  ticketId: ticket.id,
295
299
  status: ticket.status,
296
300
  overlapWarning: overlapWarning || undefined,
301
+ dispatchWarning: ticket.dispatchWarning,
297
302
  },
298
303
  };
299
304
  }
@@ -336,9 +341,21 @@ function buildWaitDetails(ticket: AsyncTicket): DelegateDetails {
336
341
  ticketId: ticket.id,
337
342
  status: ticket.status,
338
343
  overlapWarning: overlapWarning || undefined,
344
+ dispatchWarning: ticket.dispatchWarning,
339
345
  };
340
346
  }
341
347
 
348
+ function appendDispatchWarnings(
349
+ base: string,
350
+ details: DelegateDetails,
351
+ ): string {
352
+ const warnings = [
353
+ details.dispatchWarning ? `WARNING: ${details.dispatchWarning}` : undefined,
354
+ details.overlapWarning,
355
+ ].filter((warning): warning is string => warning !== undefined);
356
+ return warnings.length ? `${base}\n\n${warnings.join("\n\n")}` : base;
357
+ }
358
+
342
359
  function buildWaitRunningUpdate(
343
360
  ticket: AsyncTicket,
344
361
  ): AgentToolResult<DelegateDetails> {
@@ -358,9 +375,7 @@ function buildWaitRunningUpdate(
358
375
  if (pending > 0) parts.push(`${pending} queued`);
359
376
 
360
377
  const details = buildWaitDetails(ticket);
361
- const text =
362
- parts.join(" · ") +
363
- (details.overlapWarning ? `\n\n${details.overlapWarning}` : "");
378
+ const text = appendDispatchWarnings(parts.join(" · "), details);
364
379
  return {
365
380
  content: [{ type: "text", text }],
366
381
  details,
@@ -398,8 +413,7 @@ function buildWaitAbortResult(
398
413
  ): AgentToolResult<DelegateDetails> {
399
414
  const details = buildWaitDetails(ticket);
400
415
  const base = `Wait for ticket ${ticket.id} aborted · ticket continues ${ticket.status} in the background`;
401
- const text =
402
- base + (details.overlapWarning ? `\n\n${details.overlapWarning}` : "");
416
+ const text = appendDispatchWarnings(base, details);
403
417
  return {
404
418
  content: [{ type: "text", text }],
405
419
  details,
@@ -613,6 +627,7 @@ export function handlePoll(
613
627
  ticketId: ticket.id,
614
628
  status: ticket.status,
615
629
  overlapWarning: snapshot.overlapWarning || undefined,
630
+ dispatchWarning: ticket.dispatchWarning,
616
631
  },
617
632
  };
618
633
  }
@@ -656,9 +671,7 @@ export function handleCancel(params: {
656
671
  }
657
672
  if (!params.force) {
658
673
  const details = buildWaitDetails(ticket);
659
- const text =
660
- formatCancelPreview(ticket) +
661
- (details.overlapWarning ? `\n\n${details.overlapWarning}` : "");
674
+ const text = appendDispatchWarnings(formatCancelPreview(ticket), details);
662
675
  return {
663
676
  content: [{ type: "text", text }],
664
677
  details,
@@ -667,8 +680,7 @@ export function handleCancel(params: {
667
680
  requestTicketCancel(ticket);
668
681
  const details = buildWaitDetails(ticket);
669
682
  const base = `Ticket '${ticketId}' is cancelling; workers are settling. Poll for final status.`;
670
- const text =
671
- base + (details.overlapWarning ? `\n\n${details.overlapWarning}` : "");
683
+ const text = appendDispatchWarnings(base, details);
672
684
  return {
673
685
  content: [{ type: "text", text }],
674
686
  details,
package/types.ts CHANGED
@@ -99,8 +99,19 @@ export interface AsyncTicket {
99
99
  callRecord?: CallRecord;
100
100
  /** Runtime generation for rejecting shutdown writes from stale tickets. */
101
101
  telemetryGeneration?: number;
102
+ /** Telemetry config captured at dispatch; binds shutdown aggregate rows to the
103
+ * same backend the call span wrote to. */
104
+ telemetryConfig?: import("./config.ts").TelemetryConfig;
102
105
  /** Resolves after every async worker has settled, including shutdown aborts. */
103
106
  completion?: Promise<void>;
107
+ /** False from admission until every worker has quiesced. Unlike `status`,
108
+ * this remains false during shutdown's early terminal transition. */
109
+ workersSettled?: boolean;
110
+ /** Batch-level warning attached to this dispatch, not to any one task. */
111
+ dispatchWarning?: string;
112
+ /** Immutable dispatch-scoped delegate.json snapshot used by async workers and
113
+ * later result formatting. */
114
+ config?: import("./config.ts").DelegateConfig;
104
115
  }
105
116
 
106
117
  /** Live parent settings captured when a delegate call starts. The built-in
@@ -138,6 +149,11 @@ export interface ResolvedTask {
138
149
  warnings: string[];
139
150
  /** Explicit settings that must match a live pooled session on reuse. */
140
151
  reuseIntent?: ReuseIntent;
152
+ /** Stable signature of the provider-scoped extension allowlist for this task's
153
+ * model provider. Pool reuse compares this to the frozen session value so a
154
+ * revoked or reconfigured extension cannot continue executing in a reused
155
+ * session. */
156
+ providerExtensionSources?: string;
141
157
  }
142
158
 
143
159
  export interface ToolActivity {
@@ -195,6 +211,8 @@ export interface DelegateDetails {
195
211
  /** Global overlap warning derived from result.attributedFiles, surfaced in both
196
212
  * the textual content and the custom TUI. */
197
213
  overlapWarning?: string;
214
+ /** Warning that applies to the whole dispatch rather than an individual task. */
215
+ dispatchWarning?: string;
198
216
  }
199
217
 
200
218
  export interface TaskResult {
@@ -227,8 +245,58 @@ export interface TaskResult {
227
245
  * for overlap detection so concurrent tasks in the same repo do not
228
246
  * fabricate false conflicts from shared git snapshots. */
229
247
  attributedFiles?: string[];
248
+ /** Git-native proposal/reconciliation outcome for workspace:"isolated". */
249
+ integration?: TaskIntegration;
230
250
  }
231
251
 
252
+ export type TaskIntegrationStatus =
253
+ | "applied_unverified"
254
+ | "no_changes"
255
+ | "conflict"
256
+ | "discarded"
257
+ | "apply_failed";
258
+
259
+ interface TaskIntegrationFiles {
260
+ proposedFiles: string[];
261
+ appliedFiles: string[];
262
+ }
263
+
264
+ interface TaskIntegrationWithoutRecovery extends TaskIntegrationFiles {
265
+ conflicts?: never;
266
+ baselineRef?: never;
267
+ proposalRef?: never;
268
+ patchPath?: never;
269
+ worktreePath?: never;
270
+ }
271
+
272
+ export type TaskIntegration =
273
+ | (TaskIntegrationWithoutRecovery & {
274
+ status: "applied_unverified";
275
+ })
276
+ | (TaskIntegrationWithoutRecovery & {
277
+ status: "no_changes";
278
+ })
279
+ | (TaskIntegrationWithoutRecovery & {
280
+ status: "discarded";
281
+ })
282
+ | (TaskIntegrationFiles & {
283
+ status: "conflict";
284
+ conflicts: Array<{ path: string; reason: string }>;
285
+ baselineRef: string;
286
+ proposalRef: string;
287
+ patchPath: string;
288
+ worktreePath: string;
289
+ })
290
+ | (TaskIntegrationFiles & {
291
+ status: "apply_failed";
292
+ conflicts: Array<{ path: string; reason: string }>;
293
+ /** Recovery metadata exists when reconciliation reached a proposal. */
294
+ baselineRef?: string;
295
+ proposalRef?: string;
296
+ patchPath?: string;
297
+ worktreePath?: string;
298
+ });
299
+
232
300
  /** Single source of truth for a subagent's runtime configuration.
233
301
  * Passed to `createAgentSession` as `model` / `thinkingLevel` / `tools` / `cwd`. */
234
302
  export interface AgentRunConfig {
@@ -265,8 +333,15 @@ export interface TaskRunEnv {
265
333
  telemetryCallId?: string;
266
334
  /** Runtime generation for rejecting writes from a stale shutdown worker. */
267
335
  telemetryGeneration?: number;
336
+ /** Telemetry config captured at dispatch; binds task rows to the same backend
337
+ * as the call span. */
338
+ telemetryConfig?: import("./config.ts").TelemetryConfig;
268
339
  /** Whether this task is part of an async ticket. */
269
340
  async?: boolean;
341
+ /** Immutable dispatch-scoped delegate.json snapshot. Long-lived async workers
342
+ * use this instead of the live singleton so retry/stall/output/provider
343
+ * settings stay stable for the ticket's lifetime. */
344
+ config?: import("./config.ts").DelegateConfig;
270
345
  }
271
346
 
272
347
  /** Structural subset of Pi's `ExtensionContext` used by delegate's
@@ -288,6 +363,10 @@ export interface DelegateToolCtx {
288
363
  | undefined;
289
364
  /** Optional hook Pi exposes for extensions to read the live system prompt. */
290
365
  getSystemPrompt?: () => string | undefined;
366
+ /** Optional TUI notice boundary used for migration warnings. */
367
+ ui?: {
368
+ notify(message: string, level?: "info" | "warning" | "error"): void;
369
+ };
291
370
  }
292
371
 
293
372
  /** Shape returned by the delegate tool's `execute`. Mirrors Pi's