@narumitw/pi-subagents 2.0.6 → 2.1.1
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 +171 -60
- package/dist/chunks/{auto-transport-SY2VHUFH.ts → auto-transport-FUUKFDIG.ts} +6 -6
- package/dist/chunks/{capability-grant-CGEWOEKE.ts → capability-grant-PR72SWWS.ts} +4 -4
- package/dist/chunks/{chunk-CBP76ARQ.ts → chunk-2LMJU25E.ts} +172 -74
- package/dist/chunks/chunk-2LMJU25E.ts.map +7 -0
- package/dist/chunks/{chunk-DPPVEQAM.ts → chunk-4AQSF7AS.ts} +1 -1
- package/dist/chunks/chunk-4AQSF7AS.ts.map +7 -0
- package/dist/chunks/chunk-6H6TBBED.ts +108 -0
- package/dist/chunks/chunk-6H6TBBED.ts.map +7 -0
- package/dist/chunks/{chunk-YBUWBRF7.ts → chunk-6NSJVPXX.ts} +6 -16
- package/dist/chunks/{chunk-YBUWBRF7.ts.map → chunk-6NSJVPXX.ts.map} +2 -2
- package/dist/chunks/{chunk-DSOOH73Y.ts → chunk-7AAJEUSL.ts} +3 -3
- package/dist/chunks/{chunk-DSOOH73Y.ts.map → chunk-7AAJEUSL.ts.map} +2 -2
- package/dist/chunks/{chunk-7QPPBBXZ.ts → chunk-D4CR7T73.ts} +21 -3
- package/dist/chunks/chunk-D4CR7T73.ts.map +7 -0
- package/dist/chunks/{chunk-NIF42QMF.ts → chunk-FEVPWRMU.ts} +7 -4
- package/dist/chunks/chunk-FEVPWRMU.ts.map +7 -0
- package/dist/chunks/{chunk-S2IWVK3J.ts → chunk-ILEQ27AL.ts} +3 -2
- package/dist/chunks/chunk-ILEQ27AL.ts.map +7 -0
- package/dist/chunks/{chunk-DQMN4OYM.ts → chunk-ITVWPNU4.ts} +12 -106
- package/dist/chunks/chunk-ITVWPNU4.ts.map +7 -0
- package/dist/chunks/{chunk-QDVGH2X7.ts → chunk-IWC32VPY.ts} +2 -1
- package/dist/chunks/{chunk-QDVGH2X7.ts.map → chunk-IWC32VPY.ts.map} +2 -2
- package/dist/chunks/{chunk-I2FAK44T.ts → chunk-JSZIP73U.ts} +48 -10
- package/dist/chunks/chunk-JSZIP73U.ts.map +7 -0
- package/dist/chunks/{chunk-ZHTNCZIA.ts → chunk-JU6LUNLP.ts} +2 -2
- package/dist/chunks/{chunk-PSK43Y6A.ts → chunk-LASD73CM.ts} +2 -2
- package/dist/chunks/{chunk-C4L6P266.ts → chunk-LEOYDZI3.ts} +1 -1
- package/dist/chunks/{chunk-C4L6P266.ts.map → chunk-LEOYDZI3.ts.map} +2 -2
- package/dist/chunks/{chunk-H3BFJ7HJ.ts → chunk-LL4LP2T7.ts} +5 -5
- package/dist/chunks/chunk-N2T5IN4X.ts +18 -0
- package/dist/chunks/chunk-N2T5IN4X.ts.map +7 -0
- package/dist/chunks/chunk-NLT67IZS.ts +322 -0
- package/dist/chunks/chunk-NLT67IZS.ts.map +7 -0
- package/dist/chunks/{chunk-G3RSMSXJ.ts → chunk-NTRPLF46.ts} +1 -1
- package/dist/chunks/chunk-NTRPLF46.ts.map +7 -0
- package/dist/chunks/{chunk-EFBPISNT.ts → chunk-PBZMBTNJ.ts} +104 -103
- package/dist/chunks/chunk-PBZMBTNJ.ts.map +7 -0
- package/dist/chunks/{chunk-SCZ33MYW.ts → chunk-PGLSFLYW.ts} +2 -2
- package/dist/chunks/{chunk-O4VO6JUJ.ts → chunk-TM2R67J3.ts} +3 -3
- package/dist/chunks/{chunk-QBORTI4W.ts → chunk-TMZRHIIK.ts} +32 -3
- package/dist/chunks/chunk-TMZRHIIK.ts.map +7 -0
- package/dist/chunks/chunk-TZ34IQ3M.ts +59 -0
- package/dist/chunks/chunk-TZ34IQ3M.ts.map +7 -0
- package/dist/chunks/{chunk-7OBINKFM.ts → chunk-VDG7LTYE.ts} +11 -11
- package/dist/chunks/chunk-VDG7LTYE.ts.map +7 -0
- package/dist/chunks/{chunk-AEUYS7JC.ts → chunk-X4NMONPE.ts} +1 -1
- package/dist/chunks/chunk-X4NMONPE.ts.map +7 -0
- package/dist/chunks/{chunk-HKC4ES4B.ts → chunk-YPJEN6NU.ts} +2 -2
- package/dist/chunks/{chunk-434NII74.ts → chunk-YU53SHA7.ts} +54 -8
- package/dist/chunks/chunk-YU53SHA7.ts.map +7 -0
- package/dist/chunks/{completion-delivery-YPOWSSV3.ts → completion-delivery-RSJU6BXL.ts} +5 -4
- package/dist/chunks/{config-status-J4GPWP46.ts → config-status-FKGDECZ3.ts} +7 -6
- package/dist/chunks/{config-ui-2YUCUEBM.ts → config-ui-ABHYNGQ7.ts} +297 -231
- package/dist/chunks/config-ui-ABHYNGQ7.ts.map +7 -0
- package/dist/chunks/{consult-IV7UBNQQ.ts → consult-LJU3IQY5.ts} +14 -13
- package/dist/chunks/consult-LJU3IQY5.ts.map +7 -0
- package/dist/chunks/{create-stateful-transport-ZP3IXNV3.ts → create-stateful-transport-JWC2EFYL.ts} +6 -6
- package/dist/chunks/{delegation-contract-WJPT4FVS.ts → delegation-contract-LA56I5DT.ts} +2 -2
- package/dist/chunks/{discovery-K25T3SH4.ts → discovery-MIFB2U4Y.ts} +3 -3
- package/dist/chunks/{execution-LA7HN5YF.ts → execution-Q2JZLKJA.ts} +19 -16
- package/dist/chunks/execution-Q2JZLKJA.ts.map +7 -0
- package/dist/chunks/{in-process-transport-4RF3J6XK.ts → in-process-transport-HJ6TZXC3.ts} +9 -9
- package/dist/chunks/{inspect-XV2QALMR.ts → inspect-UH2TKH6E.ts} +25 -10
- package/dist/chunks/inspect-UH2TKH6E.ts.map +7 -0
- package/dist/chunks/{persistence-VSGXAW4P.ts → persistence-UY3PY6E5.ts} +11 -7
- package/dist/chunks/persistence-UY3PY6E5.ts.map +7 -0
- package/dist/chunks/{registry-E6XPJB7L.ts → registry-BT54L6CY.ts} +136 -15
- package/dist/chunks/registry-BT54L6CY.ts.map +7 -0
- package/dist/chunks/{retained-semantic-state-7WXSGRJU.ts → retained-semantic-state-GM75FZGE.ts} +3 -3
- package/dist/chunks/{rpc-transport-NEHBHWX4.ts → rpc-transport-7R7DVCEB.ts} +12 -16
- package/dist/chunks/rpc-transport-7R7DVCEB.ts.map +7 -0
- package/dist/chunks/{spawn-idempotency-QGHO2WKC.ts → spawn-idempotency-BNHOSMZW.ts} +2 -2
- package/dist/chunks/{subprocess-transport-NSHOGDC4.ts → subprocess-transport-VHZJRBTW.ts} +15 -14
- package/dist/chunks/subprocess-transport-VHZJRBTW.ts.map +7 -0
- package/dist/chunks/usage-recording-store-CW3EH2SZ.ts +164 -0
- package/dist/chunks/usage-recording-store-CW3EH2SZ.ts.map +7 -0
- package/dist/index.ts +682 -82
- package/dist/index.ts.map +3 -3
- package/docs/async-runtime-protocol.md +83 -0
- package/docs/implementation-notes/pi-subagents-capability-matrix.md +62 -0
- package/docs/implementation-notes/pi-subagents-current-direction.md +99 -0
- package/docs/implementation-notes/pi-subagents-rpc-v1.md +153 -0
- package/docs/pi-subagents-diagrams.md +183 -0
- package/package.json +9 -8
- package/src/agents/types.ts +2 -0
- package/src/async-subagent-benchmark.ts +532 -0
- package/src/completion-delivery.ts +71 -4
- package/src/completion-render.ts +1 -0
- package/src/completion-requirement.ts +479 -0
- package/src/config-registration.ts +5 -5
- package/src/config-status.ts +66 -70
- package/src/config-ui.ts +244 -150
- package/src/consult-registration.ts +4 -12
- package/src/consult-resources.ts +1 -1
- package/src/consult.ts +3 -8
- package/src/delegation-contract.ts +55 -9
- package/src/execution-plan.ts +1 -1
- package/src/execution-ui.ts +40 -29
- package/src/execution.ts +2 -3
- package/src/inspect.ts +24 -1
- package/src/orchestration-metrics.ts +1 -1
- package/src/panel-execution.ts +2 -3
- package/src/panel-failure.ts +1 -1
- package/src/panel-render.ts +1 -1
- package/src/parallel-limit-ui.ts +6 -5
- package/src/params.ts +2 -1
- package/src/persistence.ts +9 -0
- package/src/process-control.ts +43 -0
- package/src/registry-types.ts +5 -0
- package/src/registry.ts +162 -18
- package/src/render.ts +2 -1
- package/src/rpc-transport.ts +1 -1
- package/src/runner-outcome.ts +1 -1
- package/src/runner-result.ts +1 -1
- package/src/runner-types.ts +102 -0
- package/src/runner.ts +11 -192
- package/src/session-guidance-contract.ts +309 -0
- package/src/settings/inspection.ts +27 -0
- package/src/settings/schema.ts +9 -0
- package/src/settings-reader.ts +7 -0
- package/src/settings.ts +20 -0
- package/src/spawn-idempotency.ts +5 -0
- package/src/stateful-agent-view.ts +15 -19
- package/src/stateful-guidance.ts +11 -18
- package/src/stateful-limit-ui.ts +23 -20
- package/src/stateful-limits.ts +10 -10
- package/src/stateful-registration.ts +126 -36
- package/src/stateful-render.ts +27 -2
- package/src/subagent-details.ts +43 -0
- package/src/subagents-extension.ts +116 -68
- package/src/subagents.ts +2 -0
- package/src/subprocess-transport.ts +2 -1
- package/src/supervision.ts +2 -1
- package/src/timeout-finalization.ts +1 -1
- package/src/tool-schema-compatibility.ts +73 -0
- package/src/transport-types.ts +6 -0
- package/src/transport-ui.ts +18 -46
- package/src/usage-recording-config.ts +13 -0
- package/src/usage-recording-store.ts +183 -0
- package/src/usage-recording.ts +478 -0
- package/src/verification-harness.ts +1 -1
- package/src/workflow-ui.ts +17 -9
- package/dist/chunks/chunk-434NII74.ts.map +0 -7
- package/dist/chunks/chunk-7OBINKFM.ts.map +0 -7
- package/dist/chunks/chunk-7QPPBBXZ.ts.map +0 -7
- package/dist/chunks/chunk-AEUYS7JC.ts.map +0 -7
- package/dist/chunks/chunk-CBP76ARQ.ts.map +0 -7
- package/dist/chunks/chunk-DPPVEQAM.ts.map +0 -7
- package/dist/chunks/chunk-DQMN4OYM.ts.map +0 -7
- package/dist/chunks/chunk-EFBPISNT.ts.map +0 -7
- package/dist/chunks/chunk-G3RSMSXJ.ts.map +0 -7
- package/dist/chunks/chunk-I2FAK44T.ts.map +0 -7
- package/dist/chunks/chunk-NIF42QMF.ts.map +0 -7
- package/dist/chunks/chunk-QBORTI4W.ts.map +0 -7
- package/dist/chunks/chunk-S2IWVK3J.ts.map +0 -7
- package/dist/chunks/config-ui-2YUCUEBM.ts.map +0 -7
- package/dist/chunks/consult-IV7UBNQQ.ts.map +0 -7
- package/dist/chunks/execution-LA7HN5YF.ts.map +0 -7
- package/dist/chunks/inspect-XV2QALMR.ts.map +0 -7
- package/dist/chunks/persistence-VSGXAW4P.ts.map +0 -7
- package/dist/chunks/registry-E6XPJB7L.ts.map +0 -7
- package/dist/chunks/rpc-transport-NEHBHWX4.ts.map +0 -7
- package/dist/chunks/subprocess-transport-NSHOGDC4.ts.map +0 -7
- /package/dist/chunks/{auto-transport-SY2VHUFH.ts.map → auto-transport-FUUKFDIG.ts.map} +0 -0
- /package/dist/chunks/{capability-grant-CGEWOEKE.ts.map → capability-grant-PR72SWWS.ts.map} +0 -0
- /package/dist/chunks/{chunk-ZHTNCZIA.ts.map → chunk-JU6LUNLP.ts.map} +0 -0
- /package/dist/chunks/{chunk-PSK43Y6A.ts.map → chunk-LASD73CM.ts.map} +0 -0
- /package/dist/chunks/{chunk-H3BFJ7HJ.ts.map → chunk-LL4LP2T7.ts.map} +0 -0
- /package/dist/chunks/{chunk-SCZ33MYW.ts.map → chunk-PGLSFLYW.ts.map} +0 -0
- /package/dist/chunks/{chunk-O4VO6JUJ.ts.map → chunk-TM2R67J3.ts.map} +0 -0
- /package/dist/chunks/{chunk-HKC4ES4B.ts.map → chunk-YPJEN6NU.ts.map} +0 -0
- /package/dist/chunks/{completion-delivery-YPOWSSV3.ts.map → completion-delivery-RSJU6BXL.ts.map} +0 -0
- /package/dist/chunks/{config-status-J4GPWP46.ts.map → config-status-FKGDECZ3.ts.map} +0 -0
- /package/dist/chunks/{create-stateful-transport-ZP3IXNV3.ts.map → create-stateful-transport-JWC2EFYL.ts.map} +0 -0
- /package/dist/chunks/{delegation-contract-WJPT4FVS.ts.map → delegation-contract-LA56I5DT.ts.map} +0 -0
- /package/dist/chunks/{discovery-K25T3SH4.ts.map → discovery-MIFB2U4Y.ts.map} +0 -0
- /package/dist/chunks/{in-process-transport-4RF3J6XK.ts.map → in-process-transport-HJ6TZXC3.ts.map} +0 -0
- /package/dist/chunks/{retained-semantic-state-7WXSGRJU.ts.map → retained-semantic-state-GM75FZGE.ts.map} +0 -0
- /package/dist/chunks/{spawn-idempotency-QGHO2WKC.ts.map → spawn-idempotency-BNHOSMZW.ts.map} +0 -0
package/src/registry.ts
CHANGED
|
@@ -10,6 +10,16 @@ import {
|
|
|
10
10
|
isCapabilityGrantActive,
|
|
11
11
|
revokeCapabilityGrant,
|
|
12
12
|
} from "./capability-grant.js";
|
|
13
|
+
import {
|
|
14
|
+
beginCompletionRequirement,
|
|
15
|
+
type CompletionRequirementMode,
|
|
16
|
+
cancelPendingCompletionRequirements,
|
|
17
|
+
completionRequirementKey,
|
|
18
|
+
MAX_UNRESOLVED_REQUIRED_COMPLETIONS,
|
|
19
|
+
makeCompletionAvailable,
|
|
20
|
+
makeCompletionVisible,
|
|
21
|
+
pendingRequiredCompletionCount,
|
|
22
|
+
} from "./completion-requirement.js";
|
|
13
23
|
import { resolveCompletionRecipient } from "./completion-routing.js";
|
|
14
24
|
import type { TargetPolicyAudit } from "./cwd-policy.js";
|
|
15
25
|
import type { DelegationContract } from "./delegation-contract.js";
|
|
@@ -259,8 +269,19 @@ export class AgentRegistry {
|
|
|
259
269
|
mailbox: (record.mailbox ?? [])
|
|
260
270
|
.slice(-this.maxMailboxMessages)
|
|
261
271
|
.map((message) => ({ ...message, recipientId: record.id })),
|
|
272
|
+
completionRequirements: (record.completionRequirements ?? []).map((item) => ({
|
|
273
|
+
...item,
|
|
274
|
+
})),
|
|
262
275
|
history: record.history.slice(-this.maxHistoryTurns).map((turn) => ({ ...turn })),
|
|
263
276
|
});
|
|
277
|
+
const restored = this.agents.get(record.id);
|
|
278
|
+
if (restored && restored.state !== "running" && restored.state !== "starting") {
|
|
279
|
+
restored.completionRequirements = cancelPendingCompletionRequirements(
|
|
280
|
+
restored.completionRequirements,
|
|
281
|
+
restored.state,
|
|
282
|
+
this.now(),
|
|
283
|
+
);
|
|
284
|
+
}
|
|
264
285
|
}
|
|
265
286
|
for (const agent of this.agents.values()) {
|
|
266
287
|
if (agent.parentId) {
|
|
@@ -291,6 +312,7 @@ export class AgentRegistry {
|
|
|
291
312
|
idleTimeoutMs?: number;
|
|
292
313
|
maxTurns?: number;
|
|
293
314
|
maxToolCalls?: number;
|
|
315
|
+
completionRequirement?: CompletionRequirementMode;
|
|
294
316
|
parentId?: string;
|
|
295
317
|
context?: string;
|
|
296
318
|
contextSourceIds?: string[];
|
|
@@ -316,6 +338,7 @@ export class AgentRegistry {
|
|
|
316
338
|
input.spawnRequestHash,
|
|
317
339
|
);
|
|
318
340
|
if (existing) return existing;
|
|
341
|
+
this.assertRequiredCompletionCapacity(input.completionRequirement);
|
|
319
342
|
const task = truncateUtf8(input.task, this.maxTaskBytes).text;
|
|
320
343
|
const expired = this.evictExpired();
|
|
321
344
|
let expiryReleaseError: unknown;
|
|
@@ -369,6 +392,7 @@ export class AgentRegistry {
|
|
|
369
392
|
currentTask: task,
|
|
370
393
|
turnGeneration: 0,
|
|
371
394
|
pendingCompletions: [],
|
|
395
|
+
completionRequirements: [],
|
|
372
396
|
history: [],
|
|
373
397
|
mailbox: [],
|
|
374
398
|
context: input.context,
|
|
@@ -393,7 +417,7 @@ export class AgentRegistry {
|
|
|
393
417
|
parent.updatedAt = now;
|
|
394
418
|
}
|
|
395
419
|
await this.changed();
|
|
396
|
-
this.startTurn(record, task, input);
|
|
420
|
+
this.startTurn(record, task, input, input.completionRequirement);
|
|
397
421
|
return this.copy(record);
|
|
398
422
|
}
|
|
399
423
|
|
|
@@ -417,7 +441,10 @@ export class AgentRegistry {
|
|
|
417
441
|
async followUp(
|
|
418
442
|
id: string,
|
|
419
443
|
task: string,
|
|
420
|
-
options: TurnLimits & {
|
|
444
|
+
options: TurnLimits & {
|
|
445
|
+
timeoutMs?: number;
|
|
446
|
+
completionRequirement?: CompletionRequirementMode;
|
|
447
|
+
} = {},
|
|
421
448
|
): Promise<ManagedAgent> {
|
|
422
449
|
if (!task.trim()) throw new Error("Subagent tasks cannot be empty");
|
|
423
450
|
if (options.timeoutMs !== undefined) validateTurnTimeout(options.timeoutMs);
|
|
@@ -428,6 +455,7 @@ export class AgentRegistry {
|
|
|
428
455
|
![
|
|
429
456
|
"idle",
|
|
430
457
|
"completed",
|
|
458
|
+
"partial",
|
|
431
459
|
"blocked",
|
|
432
460
|
"needs-input",
|
|
433
461
|
"abstained",
|
|
@@ -438,9 +466,10 @@ export class AgentRegistry {
|
|
|
438
466
|
) {
|
|
439
467
|
throw new Error(`Agent ${id} cannot accept follow-up while ${agent.state}`);
|
|
440
468
|
}
|
|
469
|
+
this.assertRequiredCompletionCapacity(options.completionRequirement);
|
|
441
470
|
const unread = agent.mailbox.filter((message) => !message.readAt).slice(-20);
|
|
442
471
|
agent.currentMailboxMessageIds = unread.map((message) => message.id);
|
|
443
|
-
this.startTurn(agent, boundedTask, options);
|
|
472
|
+
this.startTurn(agent, boundedTask, options, options.completionRequirement);
|
|
444
473
|
return this.copy(agent);
|
|
445
474
|
}
|
|
446
475
|
|
|
@@ -628,6 +657,13 @@ export class AgentRegistry {
|
|
|
628
657
|
createdAt: this.completionCreatedAt(),
|
|
629
658
|
};
|
|
630
659
|
agent.state = "interrupted";
|
|
660
|
+
agent.completionRequirements = makeCompletionAvailable(agent.completionRequirements, {
|
|
661
|
+
runId: persistedCompletion.runId,
|
|
662
|
+
generation: persistedCompletion.generation,
|
|
663
|
+
completionId: persistedCompletion.completionId,
|
|
664
|
+
terminalState: agent.state,
|
|
665
|
+
updatedAt: persistedCompletion.createdAt,
|
|
666
|
+
});
|
|
631
667
|
agent.pendingCompletions = [...(agent.pendingCompletions ?? []), persistedCompletion];
|
|
632
668
|
this.enqueueCompletionMessage(agent, persistedCompletion, persistedCompletion.error);
|
|
633
669
|
clearCurrentTurn(agent);
|
|
@@ -698,6 +734,11 @@ export class AgentRegistry {
|
|
|
698
734
|
await this.running.get(agentId)?.catch(() => undefined);
|
|
699
735
|
agent.state = "closed";
|
|
700
736
|
agent.updatedAt = this.now();
|
|
737
|
+
agent.completionRequirements = cancelPendingCompletionRequirements(
|
|
738
|
+
agent.completionRequirements,
|
|
739
|
+
agent.state,
|
|
740
|
+
agent.updatedAt,
|
|
741
|
+
);
|
|
701
742
|
if (agent.parentId) {
|
|
702
743
|
const parent = this.agents.get(agent.parentId);
|
|
703
744
|
if (parent) parent.children = parent.children.filter((childId) => childId !== agentId);
|
|
@@ -766,6 +807,11 @@ export class AgentRegistry {
|
|
|
766
807
|
if (agent.state === "running" || agent.state === "starting") {
|
|
767
808
|
agent.state = "interrupted";
|
|
768
809
|
}
|
|
810
|
+
agent.completionRequirements = cancelPendingCompletionRequirements(
|
|
811
|
+
agent.completionRequirements,
|
|
812
|
+
agent.state,
|
|
813
|
+
this.now(),
|
|
814
|
+
);
|
|
769
815
|
clearCurrentTurn(agent);
|
|
770
816
|
}
|
|
771
817
|
}
|
|
@@ -814,6 +860,9 @@ export class AgentRegistry {
|
|
|
814
860
|
currentTask: agent.currentTask,
|
|
815
861
|
currentRunId: agent.currentRunId,
|
|
816
862
|
currentTurnGeneration: agent.currentTurnGeneration,
|
|
863
|
+
completionRequirements: (agent.completionRequirements ?? []).map((record) => ({
|
|
864
|
+
...record,
|
|
865
|
+
})),
|
|
817
866
|
error: agent.error,
|
|
818
867
|
workspaceMode: agent.workspaceMode,
|
|
819
868
|
contextTurns: agent.contextTurns,
|
|
@@ -864,6 +913,37 @@ export class AgentRegistry {
|
|
|
864
913
|
return agent ? this.copy(agent) : undefined;
|
|
865
914
|
}
|
|
866
915
|
|
|
916
|
+
reconcileCompletionRequirements(
|
|
917
|
+
activeRecords: ReadonlyMap<
|
|
918
|
+
string,
|
|
919
|
+
import("./completion-requirement.js").CompletionRequirementRecord
|
|
920
|
+
>,
|
|
921
|
+
observedState: boolean,
|
|
922
|
+
): void {
|
|
923
|
+
if (!observedState) return;
|
|
924
|
+
for (const agent of this.agents.values()) {
|
|
925
|
+
agent.completionRequirements = (agent.completionRequirements ?? []).flatMap((record) => {
|
|
926
|
+
const restored = activeRecords.get(completionRequirementKey(record));
|
|
927
|
+
if (!restored) return [];
|
|
928
|
+
if (
|
|
929
|
+
restored.state === "pending" &&
|
|
930
|
+
agent.state !== "running" &&
|
|
931
|
+
agent.state !== "starting"
|
|
932
|
+
) {
|
|
933
|
+
return [
|
|
934
|
+
{
|
|
935
|
+
...restored,
|
|
936
|
+
state: "cancelled" as const,
|
|
937
|
+
terminalState: "interrupted" as const,
|
|
938
|
+
updatedAt: Math.max(restored.updatedAt, this.now()),
|
|
939
|
+
},
|
|
940
|
+
];
|
|
941
|
+
}
|
|
942
|
+
return [{ ...restored }];
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
867
947
|
listPendingCompletions(): AgentTurnCompletion[] {
|
|
868
948
|
return [...this.agents.values()]
|
|
869
949
|
.flatMap((agent) =>
|
|
@@ -889,6 +969,11 @@ export class AgentRegistry {
|
|
|
889
969
|
(completion) => completion.completionId === completionId,
|
|
890
970
|
);
|
|
891
971
|
if (!acknowledged) return;
|
|
972
|
+
agent.completionRequirements = makeCompletionVisible(
|
|
973
|
+
agent.completionRequirements,
|
|
974
|
+
completionId,
|
|
975
|
+
deliveredAt,
|
|
976
|
+
);
|
|
892
977
|
agent.pendingCompletions = (agent.pendingCompletions ?? []).filter(
|
|
893
978
|
(completion) => completion.completionId !== completionId,
|
|
894
979
|
);
|
|
@@ -903,6 +988,11 @@ export class AgentRegistry {
|
|
|
903
988
|
try {
|
|
904
989
|
await this.changed(true);
|
|
905
990
|
} catch (error) {
|
|
991
|
+
agent.completionRequirements = (agent.completionRequirements ?? []).map((record) =>
|
|
992
|
+
record.completionId === completionId && record.state === "visible"
|
|
993
|
+
? { ...record, state: "available", updatedAt: acknowledged.createdAt }
|
|
994
|
+
: record,
|
|
995
|
+
);
|
|
906
996
|
if (
|
|
907
997
|
!agent.pendingCompletions?.some(
|
|
908
998
|
(completion) => completion.completionId === acknowledged.completionId,
|
|
@@ -937,6 +1027,7 @@ export class AgentRegistry {
|
|
|
937
1027
|
agent: ManagedAgent,
|
|
938
1028
|
task: string,
|
|
939
1029
|
limits: TurnLimits & { timeoutMs?: number } = {},
|
|
1030
|
+
completionRequirement: CompletionRequirementMode = "background",
|
|
940
1031
|
): void {
|
|
941
1032
|
if ((agent.pendingCompletions?.length ?? 0) >= MAX_PENDING_COMPLETIONS_PER_AGENT) {
|
|
942
1033
|
throw new Error(
|
|
@@ -946,6 +1037,13 @@ export class AgentRegistry {
|
|
|
946
1037
|
agent.turnGeneration = (agent.turnGeneration ?? 0) + 1;
|
|
947
1038
|
agent.currentTurnGeneration = agent.turnGeneration;
|
|
948
1039
|
agent.currentRunId = `run:${agent.id}:${randomUUID()}`;
|
|
1040
|
+
if (completionRequirement === "required") {
|
|
1041
|
+
agent.completionRequirements = beginCompletionRequirement(agent.completionRequirements, {
|
|
1042
|
+
runId: agent.currentRunId,
|
|
1043
|
+
generation: agent.currentTurnGeneration,
|
|
1044
|
+
createdAt: this.now(),
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
949
1047
|
agent.state = "starting";
|
|
950
1048
|
agent.error = undefined;
|
|
951
1049
|
agent.currentTask = task;
|
|
@@ -962,6 +1060,12 @@ export class AgentRegistry {
|
|
|
962
1060
|
queuePosition: this.queue.length + 1,
|
|
963
1061
|
updatedAt: agent.updatedAt,
|
|
964
1062
|
timing: { queuedAt: agent.updatedAt },
|
|
1063
|
+
budgetSource: {
|
|
1064
|
+
timeout: agent.currentTimeoutMs === undefined ? "runtime" : "explicit",
|
|
1065
|
+
idleTimeout: agent.currentIdleTimeoutMs === undefined ? "runtime" : "explicit",
|
|
1066
|
+
turnLimit: agent.currentMaxTurns === undefined ? "runtime" : "explicit",
|
|
1067
|
+
toolCallLimit: agent.currentMaxToolCalls === undefined ? "runtime" : "explicit",
|
|
1068
|
+
},
|
|
965
1069
|
};
|
|
966
1070
|
let resolveQueued!: (agent: ManagedAgent) => void;
|
|
967
1071
|
const completion = new Promise<ManagedAgent>((resolve) => {
|
|
@@ -1007,6 +1111,13 @@ export class AgentRegistry {
|
|
|
1007
1111
|
error: truncateUtf8(agent.error, 512).text,
|
|
1008
1112
|
createdAt: this.completionCreatedAt(),
|
|
1009
1113
|
};
|
|
1114
|
+
agent.completionRequirements = makeCompletionAvailable(agent.completionRequirements, {
|
|
1115
|
+
runId: persistedCompletion.runId,
|
|
1116
|
+
generation: persistedCompletion.generation,
|
|
1117
|
+
completionId: persistedCompletion.completionId,
|
|
1118
|
+
terminalState: agent.state,
|
|
1119
|
+
updatedAt: persistedCompletion.createdAt,
|
|
1120
|
+
});
|
|
1010
1121
|
agent.pendingCompletions = [...(agent.pendingCompletions ?? []), persistedCompletion];
|
|
1011
1122
|
this.enqueueCompletionMessage(agent, persistedCompletion, persistedCompletion.error ?? "");
|
|
1012
1123
|
clearCurrentTurn(agent);
|
|
@@ -1078,20 +1189,25 @@ export class AgentRegistry {
|
|
|
1078
1189
|
agent.history = agent.history.slice(-this.maxHistoryTurns);
|
|
1079
1190
|
agent.structuredResult =
|
|
1080
1191
|
outcome.structuredResult ?? parseAnyStructuredSubagentResult(output, agent.resultFormat);
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
:
|
|
1192
|
+
const malformedStructuredResult =
|
|
1193
|
+
agent.resultFormat !== undefined &&
|
|
1194
|
+
agent.resultFormat !== "text" &&
|
|
1195
|
+
agent.structuredResult === undefined;
|
|
1196
|
+
const finalizedPartial =
|
|
1197
|
+
outcome.termination?.finalization.status === "completed" && output.trim().length > 0;
|
|
1198
|
+
agent.outcome = outcome.aborted
|
|
1199
|
+
? classifyStructuredOutcome("interrupted", "transport-aborted")
|
|
1200
|
+
: malformedStructuredResult
|
|
1201
|
+
? classifyStructuredOutcome("contract-invalid", "malformed-structured-result")
|
|
1202
|
+
: finalizedPartial
|
|
1203
|
+
? classifyStructuredOutcome("partial", outcome.termination?.reason)
|
|
1204
|
+
: (outcome.outcome ??
|
|
1205
|
+
(agent.structuredResult?.version === "pi-subagents:result:v2"
|
|
1206
|
+
? classifyStructuredOutcome(
|
|
1207
|
+
agent.structuredResult.status,
|
|
1208
|
+
agent.structuredResult.reasonCode,
|
|
1209
|
+
)
|
|
1210
|
+
: undefined));
|
|
1095
1211
|
const staleGeneration = Boolean(
|
|
1096
1212
|
acceptedPlanId && agent.executionPlan?.id !== acceptedPlanId,
|
|
1097
1213
|
);
|
|
@@ -1102,7 +1218,7 @@ export class AgentRegistry {
|
|
|
1102
1218
|
? "stale"
|
|
1103
1219
|
: outcome.aborted
|
|
1104
1220
|
? "interrupted"
|
|
1105
|
-
: outcome.exitCode !== 0
|
|
1221
|
+
: outcome.exitCode !== 0 && agent.outcome?.status !== "partial"
|
|
1106
1222
|
? "failed"
|
|
1107
1223
|
: lifecycleStateForOutcome(agent.outcome?.status);
|
|
1108
1224
|
agent.error = error;
|
|
@@ -1121,6 +1237,7 @@ export class AgentRegistry {
|
|
|
1121
1237
|
queuedAt: agent.telemetry?.timing.queuedAt,
|
|
1122
1238
|
...outcome.telemetry.timing,
|
|
1123
1239
|
},
|
|
1240
|
+
budgetSource: outcome.telemetry.budgetSource ?? agent.telemetry?.budgetSource,
|
|
1124
1241
|
}
|
|
1125
1242
|
: agent.telemetry;
|
|
1126
1243
|
agent.termination = outcome.termination
|
|
@@ -1195,6 +1312,13 @@ export class AgentRegistry {
|
|
|
1195
1312
|
error: completionError ? truncateUtf8(completionError, 512).text : undefined,
|
|
1196
1313
|
createdAt: this.completionCreatedAt(),
|
|
1197
1314
|
};
|
|
1315
|
+
agent.completionRequirements = makeCompletionAvailable(agent.completionRequirements, {
|
|
1316
|
+
runId,
|
|
1317
|
+
generation: turnGeneration,
|
|
1318
|
+
completionId: persistedCompletion.completionId,
|
|
1319
|
+
terminalState: agent.state,
|
|
1320
|
+
updatedAt: persistedCompletion.createdAt,
|
|
1321
|
+
});
|
|
1198
1322
|
agent.pendingCompletions = [...(agent.pendingCompletions ?? []), persistedCompletion];
|
|
1199
1323
|
this.enqueueCompletionMessage(agent, persistedCompletion, completionContent);
|
|
1200
1324
|
clearCurrentTurn(agent);
|
|
@@ -1357,6 +1481,19 @@ export class AgentRegistry {
|
|
|
1357
1481
|
return { taskName, taskPath };
|
|
1358
1482
|
}
|
|
1359
1483
|
|
|
1484
|
+
private assertRequiredCompletionCapacity(mode: CompletionRequirementMode | undefined): void {
|
|
1485
|
+
if (mode !== "required") return;
|
|
1486
|
+
const unresolved = [...this.agents.values()].reduce(
|
|
1487
|
+
(sum, agent) => sum + pendingRequiredCompletionCount(agent),
|
|
1488
|
+
0,
|
|
1489
|
+
);
|
|
1490
|
+
if (unresolved >= MAX_UNRESOLVED_REQUIRED_COMPLETIONS) {
|
|
1491
|
+
throw new Error(
|
|
1492
|
+
`Required subagent completion capacity reached (${MAX_UNRESOLVED_REQUIRED_COMPLETIONS}); wait for exact completion visibility or terminalize an existing requirement`,
|
|
1493
|
+
);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1360
1497
|
private retainedCount(): number {
|
|
1361
1498
|
return [...this.agents.values()].filter((agent) => agent.state !== "closed").length;
|
|
1362
1499
|
}
|
|
@@ -1479,6 +1616,7 @@ export class AgentRegistry {
|
|
|
1479
1616
|
unreadMessages,
|
|
1480
1617
|
turnGeneration: agent.turnGeneration ?? 0,
|
|
1481
1618
|
pendingCompletionCount: agent.pendingCompletions?.length ?? 0,
|
|
1619
|
+
pendingRequiredCompletionCount: pendingRequiredCompletionCount(agent),
|
|
1482
1620
|
};
|
|
1483
1621
|
}
|
|
1484
1622
|
|
|
@@ -1493,6 +1631,9 @@ export class AgentRegistry {
|
|
|
1493
1631
|
pendingCompletions: (agent.pendingCompletions ?? []).map((completion) => ({
|
|
1494
1632
|
...completion,
|
|
1495
1633
|
})),
|
|
1634
|
+
completionRequirements: (agent.completionRequirements ?? []).map((record) => ({
|
|
1635
|
+
...record,
|
|
1636
|
+
})),
|
|
1496
1637
|
history: agent.history.map((turn) => ({ ...turn })),
|
|
1497
1638
|
mailbox: agent.mailbox.map((message) => ({ ...message })),
|
|
1498
1639
|
contract: agent.contract ? structuredClone(agent.contract) : undefined,
|
|
@@ -1526,6 +1667,8 @@ function lifecycleStateForOutcome(
|
|
|
1526
1667
|
status: import("./result-contract.js").SubagentOutcomeStatus | undefined,
|
|
1527
1668
|
): AgentLifecycleState {
|
|
1528
1669
|
switch (status) {
|
|
1670
|
+
case "partial":
|
|
1671
|
+
return "partial";
|
|
1529
1672
|
case "blocked":
|
|
1530
1673
|
case "needs-input":
|
|
1531
1674
|
case "abstained":
|
|
@@ -1550,5 +1693,6 @@ function copyTelemetry(value: TransportTelemetry): TransportTelemetry {
|
|
|
1550
1693
|
...value,
|
|
1551
1694
|
timing: { ...value.timing },
|
|
1552
1695
|
usage: value.usage ? { ...value.usage } : undefined,
|
|
1696
|
+
budgetSource: value.budgetSource ? { ...value.budgetSource } : undefined,
|
|
1553
1697
|
};
|
|
1554
1698
|
}
|
package/src/render.ts
CHANGED
|
@@ -11,8 +11,9 @@ import type { AgentScope } from "./agents/types.js";
|
|
|
11
11
|
import { renderPanelCall, renderPanelResult } from "./panel-render.js";
|
|
12
12
|
import { hasUsableAggregator, type SubagentParams } from "./params.js";
|
|
13
13
|
import { expansionHint, formatToolActivity, safeBlock, safeLine } from "./render-common.js";
|
|
14
|
-
import type { SingleResult, SubagentDetails } from "./runner.js";
|
|
15
14
|
import { getResultFinalOutput, isResultError } from "./runner-outcome.js";
|
|
15
|
+
import type { SingleResult } from "./runner-types.js";
|
|
16
|
+
import type { SubagentDetails } from "./subagent-details.js";
|
|
16
17
|
import { formatUsageStats } from "./usage-format.js";
|
|
17
18
|
|
|
18
19
|
const COLLAPSED_ITEM_COUNT = 5;
|
package/src/rpc-transport.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
peerBridgeEnvironment,
|
|
25
25
|
} from "./peer-transport.js";
|
|
26
26
|
import { type PiInvocation, resolvePiInvocation } from "./pi-invocation.js";
|
|
27
|
+
import { terminateProcess } from "./process-control.js";
|
|
27
28
|
import { resolvePiPromptResources } from "./prompt-resources.js";
|
|
28
29
|
import { JsonLineDecoder } from "./protocol.js";
|
|
29
30
|
import type { AgentMailboxMessage, ManagedAgent, TurnOutcome } from "./registry.js";
|
|
@@ -42,7 +43,6 @@ import {
|
|
|
42
43
|
observeRpcBudgetEvent,
|
|
43
44
|
snapshotRpcUsage,
|
|
44
45
|
} from "./rpc-turn-capture.js";
|
|
45
|
-
import { terminateProcess } from "./runner.js";
|
|
46
46
|
import { safeTerminalText } from "./safe-text.js";
|
|
47
47
|
import { readSubagentSettings } from "./settings.js";
|
|
48
48
|
import { buildStatefulTurnPrompt, resolveStatefulTurnTimeout } from "./stateful-prompt.js";
|
package/src/runner-outcome.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { SingleResult } from "./runner.js";
|
|
2
1
|
import {
|
|
3
2
|
formatResultFailure as formatBaseResultFailure,
|
|
4
3
|
getResultFinalOutput as getBaseResultFinalOutput,
|
|
5
4
|
isResultError as isBaseResultError,
|
|
6
5
|
} from "./runner-result.js";
|
|
6
|
+
import type { SingleResult } from "./runner-types.js";
|
|
7
7
|
|
|
8
8
|
export function getResultFinalOutput(result: SingleResult): string {
|
|
9
9
|
return getBaseResultFinalOutput(result);
|
package/src/runner-result.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Message } from "@earendil-works/pi-ai";
|
|
2
2
|
import { DEFAULT_MAX_CONTEXT_BYTES, truncateUtf8 } from "./limits.js";
|
|
3
|
-
import type { SingleResult } from "./runner.js";
|
|
3
|
+
import type { SingleResult } from "./runner-types.js";
|
|
4
4
|
import { formatTimeoutCheckpoint } from "./timeout-checkpoint.js";
|
|
5
5
|
|
|
6
6
|
export function getFinalOutput(messages: Message[]): string {
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { Message } from "@earendil-works/pi-ai";
|
|
2
|
+
import type { AgentSource, SubagentThinkingLevel } from "./agents/types.js";
|
|
3
|
+
import type { CapabilityGrant } from "./capability-grant.js";
|
|
4
|
+
import type { TargetPolicyAudit } from "./cwd-policy.js";
|
|
5
|
+
import type { DelegationContract } from "./delegation-contract.js";
|
|
6
|
+
import type { ExecutionPlan } from "./execution-plan.js";
|
|
7
|
+
import type { ClassifiedSubagentOutcome } from "./outcome.js";
|
|
8
|
+
import type { AnyStructuredSubagentResult, SubagentResultFormat } from "./result-contract.js";
|
|
9
|
+
import type { UsageStats } from "./runner-usage.js";
|
|
10
|
+
import type { TurnTerminationReport } from "./timeout-checkpoint.js";
|
|
11
|
+
import type { TurnLimits } from "./turn-budget.js";
|
|
12
|
+
|
|
13
|
+
export type RecentActivityItem =
|
|
14
|
+
| { type: "text"; text: string }
|
|
15
|
+
| { type: "toolCall"; name: string; args: Record<string, unknown> };
|
|
16
|
+
|
|
17
|
+
export interface SingleResult {
|
|
18
|
+
agent: string;
|
|
19
|
+
agentSource: AgentSource | "unknown";
|
|
20
|
+
task: string;
|
|
21
|
+
exitCode: number;
|
|
22
|
+
messages: Message[];
|
|
23
|
+
stderr: string;
|
|
24
|
+
usage: UsageStats;
|
|
25
|
+
model?: string;
|
|
26
|
+
actualProvider?: string;
|
|
27
|
+
actualModel?: string;
|
|
28
|
+
recentActivity?: RecentActivityItem[];
|
|
29
|
+
recentActivityTotal?: number;
|
|
30
|
+
thinkingLevel?: SubagentThinkingLevel;
|
|
31
|
+
stopReason?: string;
|
|
32
|
+
errorMessage?: string;
|
|
33
|
+
step?: number;
|
|
34
|
+
finalOutput?: string;
|
|
35
|
+
partialOutput?: string;
|
|
36
|
+
timeoutSummary?: string;
|
|
37
|
+
timeoutSummaryError?: string;
|
|
38
|
+
termination?: TurnTerminationReport;
|
|
39
|
+
timedOut?: boolean;
|
|
40
|
+
timeoutMs?: number;
|
|
41
|
+
aborted?: boolean;
|
|
42
|
+
truncated?: boolean;
|
|
43
|
+
malformedEvents?: number;
|
|
44
|
+
launchFailed?: boolean;
|
|
45
|
+
processStarted?: boolean;
|
|
46
|
+
target?: TargetPolicyAudit;
|
|
47
|
+
policy?: {
|
|
48
|
+
inherited: string[];
|
|
49
|
+
overridden: string[];
|
|
50
|
+
unsupported: string[];
|
|
51
|
+
};
|
|
52
|
+
contract?: DelegationContract;
|
|
53
|
+
resultFormat?: SubagentResultFormat;
|
|
54
|
+
structuredResult?: AnyStructuredSubagentResult;
|
|
55
|
+
resultContractInvalid?: boolean;
|
|
56
|
+
outcome?: ClassifiedSubagentOutcome;
|
|
57
|
+
attemptCount?: number;
|
|
58
|
+
hedged?: boolean;
|
|
59
|
+
executionPlan?: ExecutionPlan;
|
|
60
|
+
capabilityGrant?: CapabilityGrant;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface ChildLaunchPolicy {
|
|
64
|
+
tools?: string[];
|
|
65
|
+
disableExtensions?: boolean;
|
|
66
|
+
disableSkills?: boolean;
|
|
67
|
+
disablePromptTemplates?: boolean;
|
|
68
|
+
disableContextFiles?: boolean;
|
|
69
|
+
projectTrust?: boolean;
|
|
70
|
+
baseSystemPrompt?: string;
|
|
71
|
+
appendSystemPromptPaths?: string[];
|
|
72
|
+
/** Package-owned explicit child extensions loaded even when unrelated extensions are disabled. */
|
|
73
|
+
extensionPaths?: string[];
|
|
74
|
+
/** Package-owned tools added to the child allowlist without changing delegated execution tools. */
|
|
75
|
+
additionalTools?: string[];
|
|
76
|
+
/** Ephemeral child-process environment consumed and cleared by a package-owned bridge. */
|
|
77
|
+
env?: NodeJS.ProcessEnv;
|
|
78
|
+
/** Internal timeout recovery control; omitted means enabled. */
|
|
79
|
+
finalizeOnTimeout?: boolean;
|
|
80
|
+
/** Internal hard deadline for the summary attempt. */
|
|
81
|
+
timeoutFinalizationMs?: number;
|
|
82
|
+
/** Optional stateful result contract retained during timeout finalization. */
|
|
83
|
+
timeoutResultFormat?: SubagentResultFormat;
|
|
84
|
+
/** Optional non-wall-clock limits for this turn. */
|
|
85
|
+
turnLimits?: TurnLimits;
|
|
86
|
+
/** Override the timeout reason when an orchestration deadline caps this child. */
|
|
87
|
+
workTimeoutReason?: "work_timeout" | "orchestration_timeout";
|
|
88
|
+
/** Public limit value reported when the effective child timeout is only the remaining budget. */
|
|
89
|
+
workTimeoutReportLimit?: number;
|
|
90
|
+
/** Absolute blocking-workflow deadline that also caps model finalization. */
|
|
91
|
+
orchestrationDeadlineAt?: number;
|
|
92
|
+
/** Completion contract requested for this turn. */
|
|
93
|
+
resultFormat?: SubagentResultFormat;
|
|
94
|
+
/** Normalized request contract retained in result details. */
|
|
95
|
+
contract?: DelegationContract;
|
|
96
|
+
/** Original task summary shown in result details when the executed prompt has contract metadata. */
|
|
97
|
+
displayTask?: string;
|
|
98
|
+
/** Immutable audit or enforcement decision made before launch. */
|
|
99
|
+
executionPlan?: ExecutionPlan;
|
|
100
|
+
/** Executor-owned authority lifetime bound to the accepted plan generation. */
|
|
101
|
+
capabilityGrant?: CapabilityGrant;
|
|
102
|
+
}
|