@ian-pascoe/pi-minimal-subagents 0.11.0 → 0.13.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/README.md +70 -8
- package/package.json +6 -6
- package/src/minimal-subagents-capabilities.ts +12 -1
- package/src/minimal-subagents-child-resources.ts +14 -17
- package/src/minimal-subagents-context.ts +180 -4
- package/src/minimal-subagents-coordinator.ts +115 -24
- package/src/minimal-subagents-extension.ts +3 -0
- package/src/minimal-subagents-registry.ts +3 -1
- package/src/minimal-subagents-render-contract.ts +30 -2
- package/src/minimal-subagents-rendering.ts +318 -52
- package/src/minimal-subagents-status-panel.ts +26 -203
- package/src/minimal-subagents-tool-schemas.ts +12 -3
- package/src/minimal-subagents-tools.ts +174 -42
- package/src/minimal-subagents-transcript.ts +296 -0
- package/src/minimal-subagents-types.ts +22 -5
- package/src/minimal-subagents-ui.ts +1 -1
- package/src/minimal-subagents-usage.ts +13 -2
|
@@ -2,10 +2,14 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import {
|
|
3
3
|
assembleImportedContext,
|
|
4
4
|
boundRecentAgentText,
|
|
5
|
+
buildActiveTurnProgress,
|
|
6
|
+
buildInheritedContextTaskPrompt,
|
|
5
7
|
buildRecentAgentActivity,
|
|
6
8
|
contextContainsImages,
|
|
9
|
+
selectActiveTurnTranscript,
|
|
7
10
|
selectChildAgentTranscript,
|
|
8
11
|
} from "./minimal-subagents-context.js";
|
|
12
|
+
|
|
9
13
|
import {
|
|
10
14
|
canAgentContractSpawn,
|
|
11
15
|
DEFAULT_MAX_SUBAGENT_DEPTH,
|
|
@@ -39,6 +43,7 @@ import { addCoordinatorMessageEnvelope } from "./minimal-subagents-message-envel
|
|
|
39
43
|
import { unavailableAgent } from "./minimal-subagents-sessions.js";
|
|
40
44
|
import { createRegistryEvent } from "./minimal-subagents-registry.js";
|
|
41
45
|
import type {
|
|
46
|
+
ActiveTurnProgress,
|
|
42
47
|
AgentDetail,
|
|
43
48
|
AgentMessageDisposition,
|
|
44
49
|
AgentMessageResult,
|
|
@@ -70,6 +75,16 @@ const RESERVED_AGENT_IDS = new Set(["root", "parent"]);
|
|
|
70
75
|
const RECENT_MESSAGE_LIMIT = 20;
|
|
71
76
|
const DEFAULT_AUTOMATIC_DELIVERY_GRACE_MS = 1_000;
|
|
72
77
|
|
|
78
|
+
/** Assistant messages a waiting parent's live view renders from the child's running turn. */
|
|
79
|
+
const ACTIVE_TURN_TRANSCRIPT_ASSISTANT_MESSAGES = 3;
|
|
80
|
+
|
|
81
|
+
/** A direct child's running turn as its waiting parent may observe it. */
|
|
82
|
+
interface ObservedActiveTurn {
|
|
83
|
+
turnId: string;
|
|
84
|
+
startedAtMs: number;
|
|
85
|
+
runtime: ChildAgentRuntime;
|
|
86
|
+
}
|
|
87
|
+
|
|
73
88
|
interface MessageParameters {
|
|
74
89
|
agent_id?: string;
|
|
75
90
|
message: string;
|
|
@@ -197,13 +212,15 @@ export class MinimalSubagentsCoordinator {
|
|
|
197
212
|
this.validateFriendlyId(friendlyId);
|
|
198
213
|
const agentId = this.buildChildAgentId(callerId, friendlyId);
|
|
199
214
|
if (this.tombstones.has(agentId)) {
|
|
200
|
-
throw new Error(
|
|
215
|
+
throw new Error(
|
|
216
|
+
`Minimal subagents agent ID ${agentId} belonged to a deleted agent and cannot be reused; choose a different agent_id`,
|
|
217
|
+
);
|
|
201
218
|
}
|
|
202
219
|
if (this.agents.has(agentId) || this.pendingAgentIds.has(agentId)) {
|
|
203
220
|
throw new Error(`Minimal subagents duplicate agent ID: ${agentId}`);
|
|
204
221
|
}
|
|
205
222
|
|
|
206
|
-
const sessionContext = parameters.session_context ?? "
|
|
223
|
+
const sessionContext = parameters.session_context ?? "omit";
|
|
207
224
|
const projectContext = parameters.project_context ?? "inherit";
|
|
208
225
|
const model = parameters.model ?? caller.model;
|
|
209
226
|
const requestedThinking = parameters.thinking_level ?? caller.thinkingLevel;
|
|
@@ -218,7 +235,7 @@ export class MinimalSubagentsCoordinator {
|
|
|
218
235
|
toolsets: this.dependencies.toolsets,
|
|
219
236
|
});
|
|
220
237
|
const committedMessages = structuredClone(caller.messages);
|
|
221
|
-
const imported = assembleImportedContext(sessionContext, committedMessages);
|
|
238
|
+
const imported = assembleImportedContext(sessionContext, committedMessages, callerId);
|
|
222
239
|
if (
|
|
223
240
|
contextContainsImages(imported.messages) &&
|
|
224
241
|
!this.dependencies.sessions.modelSupportsImages(model)
|
|
@@ -296,11 +313,12 @@ export class MinimalSubagentsCoordinator {
|
|
|
296
313
|
createRegistryEvent(this.dependencies.registry.rootSessionId, "agent-created", { agent }),
|
|
297
314
|
);
|
|
298
315
|
const turnId = this.beginTurn(agent);
|
|
299
|
-
|
|
316
|
+
const warnings = [...new Set(toolWarnings)];
|
|
317
|
+
if (warnings.length > 0) {
|
|
300
318
|
this.dependencies.notify?.({
|
|
301
319
|
type: "tool-warning",
|
|
302
320
|
agentId,
|
|
303
|
-
message: `Minimal subagents tool warnings for ${agentId}:\n- ${
|
|
321
|
+
message: `Minimal subagents tool warnings for ${agentId}:\n- ${warnings.join("\n- ")}`,
|
|
304
322
|
});
|
|
305
323
|
}
|
|
306
324
|
this.dependencies.notify?.({
|
|
@@ -313,13 +331,25 @@ export class MinimalSubagentsCoordinator {
|
|
|
313
331
|
this.initializeAndRunPrompt(
|
|
314
332
|
agentId,
|
|
315
333
|
turnId,
|
|
316
|
-
|
|
334
|
+
imported.messages.length > 0
|
|
335
|
+
? buildInheritedContextTaskPrompt(parameters.task, agentId, callerId)
|
|
336
|
+
: parameters.task,
|
|
317
337
|
imported.compact,
|
|
318
338
|
caller.model,
|
|
319
339
|
caller.thinkingLevel,
|
|
320
340
|
),
|
|
321
341
|
);
|
|
322
|
-
|
|
342
|
+
const result: SpawnResult = {
|
|
343
|
+
agent_id: agentId,
|
|
344
|
+
turn_id: turnId,
|
|
345
|
+
status: "running",
|
|
346
|
+
model: agent.launch_contract.model,
|
|
347
|
+
thinking_level: agent.launch_contract.thinking_level,
|
|
348
|
+
tools: [...agent.launch_contract.ordinary_tools],
|
|
349
|
+
delegation: agent.launch_contract.delegation ?? "none",
|
|
350
|
+
};
|
|
351
|
+
if (warnings.length > 0) result.warnings = warnings;
|
|
352
|
+
return result;
|
|
323
353
|
}
|
|
324
354
|
|
|
325
355
|
/** Capture immutable launch defaults for a nested caller from its active child runtime. */
|
|
@@ -365,10 +395,12 @@ export class MinimalSubagentsCoordinator {
|
|
|
365
395
|
this.queuePendingParentMessage(targetId, message, delivery);
|
|
366
396
|
return { agent_id: targetId, message_id: messageId, disposition: "queued" };
|
|
367
397
|
}
|
|
368
|
-
const disposition = await this.enqueueRecipientDelivery(targetId, async () =>
|
|
398
|
+
const { disposition, turnId } = await this.enqueueRecipientDelivery(targetId, async () =>
|
|
369
399
|
this.deliverExplicitMessage(message, targetId, delivery),
|
|
370
400
|
);
|
|
371
|
-
|
|
401
|
+
const result: AgentMessageResult = { agent_id: targetId, message_id: messageId, disposition };
|
|
402
|
+
if (turnId) result.turn_id = turnId;
|
|
403
|
+
return result;
|
|
372
404
|
} catch (error) {
|
|
373
405
|
const deliveryError = error instanceof Error ? error.message : String(error);
|
|
374
406
|
if (this.isCoordinationDeliveryCurrent(delivery)) {
|
|
@@ -423,7 +455,9 @@ export class MinimalSubagentsCoordinator {
|
|
|
423
455
|
if (pendingMessage) return Promise.resolve(pendingMessage);
|
|
424
456
|
if (agent.active_turn_id !== turnId) {
|
|
425
457
|
return Promise.reject(
|
|
426
|
-
new Error(
|
|
458
|
+
new Error(
|
|
459
|
+
`Minimal subagents wait: turn ${turnId} is unknown or no longer retained for ${agentId}; omit turn_id to wait for its oldest observable turn`,
|
|
460
|
+
),
|
|
427
461
|
);
|
|
428
462
|
}
|
|
429
463
|
|
|
@@ -460,11 +494,11 @@ export class MinimalSubagentsCoordinator {
|
|
|
460
494
|
});
|
|
461
495
|
}
|
|
462
496
|
|
|
463
|
-
/** Return direct-child status
|
|
497
|
+
/** Return direct-child status for a child caller; the root may inspect any descendant. */
|
|
464
498
|
status(callerId: string, agentId?: string): StatusResult {
|
|
465
499
|
this.assertCallerExists(callerId);
|
|
466
500
|
if (agentId !== undefined) {
|
|
467
|
-
this.assertCallerTargetsDirectChild(callerId, agentId, "status");
|
|
501
|
+
if (callerId !== "root") this.assertCallerTargetsDirectChild(callerId, agentId, "status");
|
|
468
502
|
return { agent: this.buildAgentDetail(this.requireAgent(agentId), false) };
|
|
469
503
|
}
|
|
470
504
|
return {
|
|
@@ -482,6 +516,56 @@ export class MinimalSubagentsCoordinator {
|
|
|
482
516
|
};
|
|
483
517
|
}
|
|
484
518
|
|
|
519
|
+
/**
|
|
520
|
+
* Find a direct child's running turn for its parent's live wait view. Only the direct parent
|
|
521
|
+
* observes it, and a requested `turnId` must be the active turn.
|
|
522
|
+
*/
|
|
523
|
+
private observeActiveTurn(
|
|
524
|
+
callerId: string,
|
|
525
|
+
agentId: string,
|
|
526
|
+
turnId: string | undefined,
|
|
527
|
+
): ObservedActiveTurn | undefined {
|
|
528
|
+
const agent = this.agents.get(agentId);
|
|
529
|
+
if (!agent || agent.parent_id !== callerId) return undefined;
|
|
530
|
+
const activeTurnId = agent.active_turn_id;
|
|
531
|
+
const startedAt = agent.active_turn_started_at;
|
|
532
|
+
if (!activeTurnId || !startedAt || (turnId !== undefined && turnId !== activeTurnId)) {
|
|
533
|
+
return undefined;
|
|
534
|
+
}
|
|
535
|
+
const runtime = this.runtimes.get(agentId);
|
|
536
|
+
if (!runtime) return undefined;
|
|
537
|
+
return { turnId: activeTurnId, startedAtMs: Date.parse(startedAt), runtime };
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/** Count a direct child's running-turn tool calls for its waiting parent. */
|
|
541
|
+
previewActiveTurn(
|
|
542
|
+
callerId: string,
|
|
543
|
+
agentId: string,
|
|
544
|
+
turnId?: string,
|
|
545
|
+
): ActiveTurnProgress | undefined {
|
|
546
|
+
const turn = this.observeActiveTurn(callerId, agentId, turnId);
|
|
547
|
+
if (!turn) return undefined;
|
|
548
|
+
return {
|
|
549
|
+
turn_id: turn.turnId,
|
|
550
|
+
...buildActiveTurnProgress(turn.runtime.snapshotActivityMessages(), turn.startedAtMs),
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/** Return a direct child's Active Turn Tail, with its tool definitions, for its waiting parent. */
|
|
555
|
+
inspectActiveTurnTranscript(
|
|
556
|
+
callerId: string,
|
|
557
|
+
agentId: string,
|
|
558
|
+
turnId?: string,
|
|
559
|
+
): ChildAgentTranscriptSnapshot | undefined {
|
|
560
|
+
const turn = this.observeActiveTurn(callerId, agentId, turnId);
|
|
561
|
+
if (!turn) return undefined;
|
|
562
|
+
return selectActiveTurnTranscript(
|
|
563
|
+
this.inspectTranscript(agentId),
|
|
564
|
+
turn.startedAtMs,
|
|
565
|
+
ACTIVE_TURN_TRANSCRIPT_ASSISTANT_MESSAGES,
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
|
|
485
569
|
/** Lazily inspect one Child Session Transcript without restoring a missing runtime. */
|
|
486
570
|
inspectTranscript(agentId: string): ChildAgentTranscriptSnapshot {
|
|
487
571
|
const agent = this.requireAgent(agentId);
|
|
@@ -528,15 +612,18 @@ export class MinimalSubagentsCoordinator {
|
|
|
528
612
|
this.assertCallerCanManageAgent(callerId, agentId, "cancel");
|
|
529
613
|
const target = this.requireUsableAgent(agentId, "cancel");
|
|
530
614
|
const affected = recursive ? [target, ...this.descendantsOf(agentId)] : [target];
|
|
615
|
+
const affectedAgentIds: string[] = [];
|
|
531
616
|
const cancelledTurnIds: string[] = [];
|
|
532
617
|
for (const agent of affected) {
|
|
533
618
|
const cancelledTurnId = await this.cancelActiveTurn(agent);
|
|
534
|
-
if (cancelledTurnId)
|
|
619
|
+
if (!cancelledTurnId) continue;
|
|
620
|
+
affectedAgentIds.push(agent.agent_id);
|
|
621
|
+
cancelledTurnIds.push(cancelledTurnId);
|
|
535
622
|
}
|
|
536
623
|
return {
|
|
537
624
|
agent_id: agentId,
|
|
538
625
|
recursive,
|
|
539
|
-
affected_agent_ids:
|
|
626
|
+
affected_agent_ids: affectedAgentIds,
|
|
540
627
|
cancelled_turn_ids: cancelledTurnIds,
|
|
541
628
|
};
|
|
542
629
|
}
|
|
@@ -1315,24 +1402,27 @@ export class MinimalSubagentsCoordinator {
|
|
|
1315
1402
|
message: CoordinatorMessage,
|
|
1316
1403
|
targetId: string,
|
|
1317
1404
|
delivery: PersistedCoordinationDelivery,
|
|
1318
|
-
): Promise<AgentMessageDisposition> {
|
|
1405
|
+
): Promise<{ disposition: AgentMessageDisposition; turnId?: string }> {
|
|
1319
1406
|
this.waitHandedDeliveryIds.add(delivery.delivery_id);
|
|
1320
1407
|
try {
|
|
1321
|
-
await this.deliverToRecipient(targetId, message, () =>
|
|
1408
|
+
const startedTurnId = await this.deliverToRecipient(targetId, message, () =>
|
|
1322
1409
|
this.isCoordinationDeliveryCurrent(delivery),
|
|
1323
1410
|
);
|
|
1324
|
-
return
|
|
1411
|
+
return startedTurnId
|
|
1412
|
+
? { disposition: "started-turn", turnId: startedTurnId }
|
|
1413
|
+
: { disposition: "queued" };
|
|
1325
1414
|
} catch (error) {
|
|
1326
1415
|
this.waitHandedDeliveryIds.delete(delivery.delivery_id);
|
|
1327
1416
|
throw error;
|
|
1328
1417
|
}
|
|
1329
1418
|
}
|
|
1330
1419
|
|
|
1420
|
+
/** Deliver one message, returning the turn ID when it starts a new turn on an idle child. */
|
|
1331
1421
|
private async deliverToRecipient(
|
|
1332
1422
|
targetId: string,
|
|
1333
1423
|
message: CoordinatorMessage,
|
|
1334
1424
|
isCurrentDelivery: () => boolean = () => true,
|
|
1335
|
-
): Promise<
|
|
1425
|
+
): Promise<string | undefined> {
|
|
1336
1426
|
if (!isCurrentDelivery()) {
|
|
1337
1427
|
throw new Error("Minimal subagents delivery abandoned after session branch change");
|
|
1338
1428
|
}
|
|
@@ -1352,7 +1442,7 @@ export class MinimalSubagentsCoordinator {
|
|
|
1352
1442
|
const visibleMessage = addCoordinatorMessageEnvelope(message);
|
|
1353
1443
|
if (target.active_turn_id || runtime.isRunning) {
|
|
1354
1444
|
await runtime.queueCoordinatorMessage(visibleMessage);
|
|
1355
|
-
return;
|
|
1445
|
+
return undefined;
|
|
1356
1446
|
}
|
|
1357
1447
|
const turnId = this.beginTurn(target);
|
|
1358
1448
|
const runMessage = runtime
|
|
@@ -1374,6 +1464,7 @@ export class MinimalSubagentsCoordinator {
|
|
|
1374
1464
|
}
|
|
1375
1465
|
});
|
|
1376
1466
|
this.trackBackgroundOperation(runMessage);
|
|
1467
|
+
return turnId;
|
|
1377
1468
|
}
|
|
1378
1469
|
|
|
1379
1470
|
private trackBackgroundOperation(operation: Promise<void>): void {
|
|
@@ -1527,9 +1618,6 @@ export class MinimalSubagentsCoordinator {
|
|
|
1527
1618
|
|
|
1528
1619
|
private buildAgentSummary(agent: PersistedAgent, includeDescendants = true): AgentSummary {
|
|
1529
1620
|
const directChildren = this.childrenOf(agent.agent_id);
|
|
1530
|
-
const children = includeDescendants
|
|
1531
|
-
? directChildren.map((child) => this.buildAgentSummary(child))
|
|
1532
|
-
: [];
|
|
1533
1621
|
const elapsed = agent.active_turn_started_at
|
|
1534
1622
|
? Math.max(0, this.now().getTime() - new Date(agent.active_turn_started_at).getTime())
|
|
1535
1623
|
: undefined;
|
|
@@ -1538,7 +1626,7 @@ export class MinimalSubagentsCoordinator {
|
|
|
1538
1626
|
model: agent.launch_contract.model,
|
|
1539
1627
|
thinking_level: agent.launch_contract.thinking_level,
|
|
1540
1628
|
};
|
|
1541
|
-
|
|
1629
|
+
const summary: AgentSummary = {
|
|
1542
1630
|
agent_id: agent.agent_id,
|
|
1543
1631
|
parent_id: agent.parent_id,
|
|
1544
1632
|
state: agent.active_turn_id ? "running" : "idle",
|
|
@@ -1553,8 +1641,11 @@ export class MinimalSubagentsCoordinator {
|
|
|
1553
1641
|
latest_activity_at: agent.latest_activity_at ?? agent.created_at,
|
|
1554
1642
|
task: agent.task,
|
|
1555
1643
|
child_count: directChildren.length,
|
|
1556
|
-
children,
|
|
1557
1644
|
};
|
|
1645
|
+
if (includeDescendants) {
|
|
1646
|
+
summary.children = directChildren.map((child) => this.buildAgentSummary(child));
|
|
1647
|
+
}
|
|
1648
|
+
return summary;
|
|
1558
1649
|
}
|
|
1559
1650
|
|
|
1560
1651
|
private buildAgentDetail(agent: PersistedAgent, includeDescendants = true): AgentDetail {
|
|
@@ -505,6 +505,9 @@ export class MinimalSubagentsLifecycleController {
|
|
|
505
505
|
private readonly coordinatorOperations: CoordinatorToolOperations = {
|
|
506
506
|
spawn: (...args) => this.requireCoordinator().spawn(...args),
|
|
507
507
|
inspectStatus: (...args) => this.requireCoordinator().inspectStatus(...args),
|
|
508
|
+
previewActiveTurn: (...args) => this.requireCoordinator().previewActiveTurn(...args),
|
|
509
|
+
inspectActiveTurnTranscript: (...args) =>
|
|
510
|
+
this.requireCoordinator().inspectActiveTurnTranscript(...args),
|
|
508
511
|
sendAgentMessage: (...args) => this.requireCoordinator().sendAgentMessage(...args),
|
|
509
512
|
wait: (...args) => this.requireCoordinator().wait(...args),
|
|
510
513
|
status: (...args) => this.requireCoordinator().status(...args),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { JsonValue } from "@earendil-works/pi-ai";
|
|
2
2
|
import { Value } from "typebox/value";
|
|
3
3
|
import { COORDINATOR_TOOL_NAMES } from "./minimal-subagents-capabilities.js";
|
|
4
|
+
import { normalizeMinimalSubagentsUsage } from "./minimal-subagents-usage.js";
|
|
4
5
|
import {
|
|
5
6
|
createDeliveryLedger,
|
|
6
7
|
deliveryLedgerSnapshot,
|
|
@@ -280,7 +281,8 @@ function cloneRegistryTurnResult(value: RegistryTurnResultWire): TurnResult {
|
|
|
280
281
|
output: value.output,
|
|
281
282
|
};
|
|
282
283
|
if (value.error !== undefined) result.error = value.error;
|
|
283
|
-
|
|
284
|
+
// Records from older versions may lack optional usage counters.
|
|
285
|
+
if (value.usage !== undefined) result.usage = normalizeMinimalSubagentsUsage(value.usage);
|
|
284
286
|
if (value.elapsed_ms !== undefined) result.elapsed_ms = value.elapsed_ms;
|
|
285
287
|
return result;
|
|
286
288
|
}
|
|
@@ -90,6 +90,7 @@ const SpawnCallArgumentsSchema = Type.Object({
|
|
|
90
90
|
model: Type.Optional(Type.String()),
|
|
91
91
|
thinking_level: Type.Optional(Type.String()),
|
|
92
92
|
delegation: Type.Optional(Type.String()),
|
|
93
|
+
tools: Type.Optional(Type.Union([Type.String(), Type.Array(Type.String())])),
|
|
93
94
|
});
|
|
94
95
|
const MessageCallArgumentsSchema = Type.Object({
|
|
95
96
|
agent_id: Type.Optional(Type.String()),
|
|
@@ -113,6 +114,7 @@ const CurrentMessageDetailsSchema = Type.Object({
|
|
|
113
114
|
agent_id: Type.String(),
|
|
114
115
|
message_id: Type.Optional(Type.String()),
|
|
115
116
|
disposition: Type.String(),
|
|
117
|
+
turn_id: Type.Optional(Type.String()),
|
|
116
118
|
behavior: Type.Optional(Type.String()),
|
|
117
119
|
error: Type.Optional(Type.String()),
|
|
118
120
|
});
|
|
@@ -209,7 +211,7 @@ const CoordinatorAgentSummaryOutputSchema = Type.Object({
|
|
|
209
211
|
latest_activity_at: Type.Optional(Type.String()),
|
|
210
212
|
task: Type.Optional(Type.String()),
|
|
211
213
|
child_count: Type.Number(),
|
|
212
|
-
children: Type.Array(Type.Unknown()),
|
|
214
|
+
children: Type.Optional(Type.Array(Type.Unknown())),
|
|
213
215
|
model: Type.String(),
|
|
214
216
|
thinking_level: Type.String(),
|
|
215
217
|
});
|
|
@@ -266,7 +268,11 @@ export const CoordinatorToolOutputSchemas = {
|
|
|
266
268
|
agent_id: Type.String(),
|
|
267
269
|
turn_id: Type.String(),
|
|
268
270
|
status: Type.Literal("running"),
|
|
269
|
-
|
|
271
|
+
model: Type.String(),
|
|
272
|
+
thinking_level: Type.String(),
|
|
273
|
+
tools: Type.Array(Type.String()),
|
|
274
|
+
delegation: Type.Union([Type.Literal("none"), Type.Literal("fanout")]),
|
|
275
|
+
warnings: Type.Optional(Type.Array(Type.String())),
|
|
270
276
|
}),
|
|
271
277
|
agent_message: Type.Object({
|
|
272
278
|
agent_id: Type.String(),
|
|
@@ -274,8 +280,10 @@ export const CoordinatorToolOutputSchemas = {
|
|
|
274
280
|
disposition: Type.Union([
|
|
275
281
|
Type.Literal("delivered-via-wait"),
|
|
276
282
|
Type.Literal("queued"),
|
|
283
|
+
Type.Literal("started-turn"),
|
|
277
284
|
Type.Literal("failed"),
|
|
278
285
|
]),
|
|
286
|
+
turn_id: Type.Optional(Type.String()),
|
|
279
287
|
error: Type.Optional(Type.String()),
|
|
280
288
|
}),
|
|
281
289
|
subagent_wait: Type.Union([
|
|
@@ -319,6 +327,25 @@ const WaitRenderDetailsSchema = Type.Union([
|
|
|
319
327
|
WaitTimeoutDetailsSchema,
|
|
320
328
|
]);
|
|
321
329
|
|
|
330
|
+
/** Partial `subagent_wait` updates: elapsed wait time and, while the child runs, its progress. */
|
|
331
|
+
const WaitProgressRenderDetailsSchema = Type.Object({
|
|
332
|
+
agent_id: Type.String(),
|
|
333
|
+
status: Type.Literal("waiting"),
|
|
334
|
+
elapsed_ms: Type.Number(),
|
|
335
|
+
turn_id: Type.Optional(Type.String()),
|
|
336
|
+
tool_calls: Type.Optional(Type.Number()),
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
export type WaitProgressRenderDetails = Static<typeof WaitProgressRenderDetailsSchema>;
|
|
340
|
+
|
|
341
|
+
/** Parse one partial `subagent_wait` progress update. */
|
|
342
|
+
export function parseWaitProgressDetails(
|
|
343
|
+
// oxlint-disable-next-line anti-slop/no-unknown-parameters -- Partial tool details are unparsed until the progress schema checks them below.
|
|
344
|
+
details: unknown,
|
|
345
|
+
): WaitProgressRenderDetails | undefined {
|
|
346
|
+
return Value.Check(WaitProgressRenderDetailsSchema, details) ? details : undefined;
|
|
347
|
+
}
|
|
348
|
+
|
|
322
349
|
export type SpawnCallArguments = Static<typeof SpawnCallArgumentsSchema>;
|
|
323
350
|
export type MessageCallArguments = Static<typeof MessageCallArgumentsSchema>;
|
|
324
351
|
export type WaitCallArguments = Static<typeof WaitCallArgumentsSchema>;
|
|
@@ -331,6 +358,7 @@ export type StatusRenderDetails = Static<typeof StatusDetailsSchema>;
|
|
|
331
358
|
export type CancelRenderDetails = Static<typeof CancelDetailsSchema>;
|
|
332
359
|
export type DeleteRenderDetails = Static<typeof DeleteDetailsSchema>;
|
|
333
360
|
export type RenderStatusAgent = Static<typeof RenderStatusAgentSchema>;
|
|
361
|
+
export type RenderRecentActivity = Static<typeof RenderRecentActivitySchema>;
|
|
334
362
|
|
|
335
363
|
/** Raw tool arguments supplied by Pi's tool-rendering interface. */
|
|
336
364
|
export type CoordinatorToolCallInput = Parameters<NonNullable<ToolDefinition["renderCall"]>>[0];
|