@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
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
2
|
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
|
+
import {
|
|
4
|
+
grammarSafeToolObject
|
|
5
|
+
} from "./chunk-TZ34IQ3M.ts";
|
|
3
6
|
import {
|
|
4
7
|
MAX_SPAWN_IDEMPOTENCY_KEY_LENGTH,
|
|
5
8
|
assertSpawnIdempotencyKey
|
|
6
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ILEQ27AL.ts";
|
|
7
10
|
import {
|
|
8
11
|
assertCurrentSpawn,
|
|
9
12
|
waitForOwnedSpawn
|
|
@@ -17,21 +20,21 @@ import {
|
|
|
17
20
|
} from "./chunk-ONDTY4EL.ts";
|
|
18
21
|
import {
|
|
19
22
|
confirmProjectAgent
|
|
20
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-TM2R67J3.ts";
|
|
21
24
|
import {
|
|
22
25
|
SUBAGENT_RESULT_FORMATS
|
|
23
26
|
} from "./chunk-RSUXZD6S.ts";
|
|
24
27
|
import {
|
|
25
28
|
DEFAULT_DELEGATION_CWD_POLICY,
|
|
26
29
|
readSubagentSettings
|
|
27
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-TMZRHIIK.ts";
|
|
28
31
|
import {
|
|
29
32
|
resolveStatefulLimits
|
|
30
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-VDG7LTYE.ts";
|
|
31
34
|
import {
|
|
32
35
|
THINKING_LEVELS,
|
|
33
36
|
isThinkingLevel
|
|
34
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-4AQSF7AS.ts";
|
|
35
38
|
import {
|
|
36
39
|
COLLAPSED_LIST_LIMIT,
|
|
37
40
|
expansionHint,
|
|
@@ -45,9 +48,13 @@ import {
|
|
|
45
48
|
textResult,
|
|
46
49
|
toolHeader
|
|
47
50
|
} from "./chunk-BFK2Z4ZF.ts";
|
|
51
|
+
import {
|
|
52
|
+
CompletionRequirementModeSchema,
|
|
53
|
+
completionRequirementsFromBranch
|
|
54
|
+
} from "./chunk-NLT67IZS.ts";
|
|
48
55
|
import {
|
|
49
56
|
DelegationContractSchema
|
|
50
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-JSZIP73U.ts";
|
|
51
58
|
import {
|
|
52
59
|
DEFAULT_MAX_CONTEXT_BYTES,
|
|
53
60
|
MAX_SUBAGENT_TIMEOUT_MS,
|
|
@@ -58,23 +65,10 @@ import {
|
|
|
58
65
|
// src/stateful-agent-view.ts
|
|
59
66
|
function formatStatefulAgentLine(agent, now = Date.now()) {
|
|
60
67
|
const elapsedSeconds = Math.max(0, Math.floor((now - agent.updatedAt) / 1e3));
|
|
61
|
-
const actions = agent.state === "running" || agent.state === "starting" ? "interrupt, close" : agent.state === "closed" ? "inspect" : "send, close";
|
|
62
68
|
const task = agent.currentTask ? ` \u2014 ${sanitizeStatusLine(agent.currentTask, 80)}` : "";
|
|
63
69
|
const unread = agent.mailbox.filter((message) => !message.readAt).length;
|
|
64
70
|
const indent = " ".repeat(agent.depth);
|
|
65
|
-
|
|
66
|
-
const timeout = agent.currentTimeoutMs ?? agent.timeoutMs;
|
|
67
|
-
const timeoutText = timeout ? ` timeout:${timeout}ms` : "";
|
|
68
|
-
const idleTimeout = agent.currentIdleTimeoutMs ?? agent.idleTimeoutMs;
|
|
69
|
-
const idleText = idleTimeout ? ` idle:${idleTimeout}ms` : "";
|
|
70
|
-
const maxTurns = agent.currentMaxTurns ?? agent.maxTurns;
|
|
71
|
-
const turnsText = maxTurns ? ` turns:${maxTurns}` : "";
|
|
72
|
-
const maxToolCalls = agent.currentMaxToolCalls ?? agent.maxToolCalls;
|
|
73
|
-
const toolsText = maxToolCalls ? ` tools:${maxToolCalls}` : "";
|
|
74
|
-
const transport = agent.telemetry?.transport ? ` transport:${agent.telemetry.transport}` : "";
|
|
75
|
-
const phase = agent.telemetry?.phase ? ` phase:${agent.telemetry.phase}` : "";
|
|
76
|
-
const queued = agent.telemetry?.queuePosition ? ` queue:${agent.telemetry.queuePosition}` : "";
|
|
77
|
-
return `${indent}${sanitizeStatusLine(agent.taskPath ?? agent.id, 256)} (${sanitizeStatusLine(agent.id, 128)}) ${sanitizeStatusLine(agent.agent, 128)} ${agent.state} ${elapsedSeconds}s${thinking}${timeoutText}${idleText}${turnsText}${toolsText}${transport}${phase}${queued} unread:${unread} [${actions}]${task}`;
|
|
71
|
+
return `${indent}${sanitizeStatusLine(agent.taskPath ?? agent.id, 256)} \xB7 ${sanitizeStatusLine(agent.agent, 128)} \xB7 ${agentStateLabel(agent.state)} \xB7 updated ${elapsedSeconds}s ago \xB7 ${unread} unread${task}`;
|
|
78
72
|
}
|
|
79
73
|
function summarizeStatefulAgent(agent) {
|
|
80
74
|
return {
|
|
@@ -110,6 +104,9 @@ function summarizeStatefulAgent(agent) {
|
|
|
110
104
|
truncated: agent.contextTruncated === true
|
|
111
105
|
},
|
|
112
106
|
resultFormat: agent.resultFormat ?? "text",
|
|
107
|
+
completionRequirements: (agent.completionRequirements ?? []).map((record) => ({
|
|
108
|
+
...record
|
|
109
|
+
})),
|
|
113
110
|
structuredResult: agent.structuredResult,
|
|
114
111
|
termination: agent.termination,
|
|
115
112
|
outcome: agent.outcome,
|
|
@@ -123,6 +120,16 @@ function summarizeStatefulAgent(agent) {
|
|
|
123
120
|
policy: agent.policy
|
|
124
121
|
};
|
|
125
122
|
}
|
|
123
|
+
function agentStateLabel(state) {
|
|
124
|
+
switch (state) {
|
|
125
|
+
case "running":
|
|
126
|
+
return "working";
|
|
127
|
+
case "completed":
|
|
128
|
+
return "finished";
|
|
129
|
+
default:
|
|
130
|
+
return state;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
126
133
|
function sanitizeStatusLine(value, maxLength) {
|
|
127
134
|
return value.slice(0, maxLength).replace(/[\u0000-\u001f\u007f-\u009f]/gu, " ").replace(/\s+/gu, " ").trim();
|
|
128
135
|
}
|
|
@@ -142,24 +149,29 @@ import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
|
142
149
|
import { Type as Type2 } from "typebox";
|
|
143
150
|
|
|
144
151
|
// src/stateful-guidance.ts
|
|
145
|
-
function createSpawnPromptGuidelines(
|
|
146
|
-
const deliveryGuidance = completionDelivery === "auto-resume" ? blockingEnabled ? "With subagent_spawn completion delivery set to auto-resume, prefer one subagent_spawn for broad asynchronous research or consequential independent review that covers related branches even when the final answer depends on its result; do not choose blocking parallel fan-out merely to keep delegation in the same turn." : "With subagent_spawn completion delivery set to auto-resume, prefer one subagent_spawn for broad asynchronous research or consequential independent review that covers related branches even when the final answer depends on its result." : blockingEnabled ? "With subagent_spawn completion delivery set to next-turn (the default), prefer one subagent_spawn for broad asynchronous research or consequential independent review only when the current response does not depend on its result; use the blocking subagent when the final answer depends on the detached result." : "With subagent_spawn completion delivery set to next-turn (the default), use subagent_spawn only when the current response does not depend on its result; complete final-answer-dependent work directly because an idle root is not awakened.";
|
|
152
|
+
function createSpawnPromptGuidelines(blockingEnabled = true) {
|
|
147
153
|
return [
|
|
148
154
|
"Do not use subagent_spawn for simple or critical-path work that the main agent can perform directly. The main agent retains overall planning, immediate critical-path work, integration, final verification, and the final answer.",
|
|
149
155
|
"Before one ordinary subagent_spawn, identify concrete useful non-overlapping main-agent work you can start immediately and a supported completion integration path. If none exists, perform the task directly instead of calling subagent_spawn.",
|
|
150
156
|
"Give subagent_spawn a concise unique taskName using lowercase letters, digits, and underscores so the retained agent has a stable canonical task path.",
|
|
151
157
|
"Set subagent_spawn thinkingLevel to the lowest sufficient thinking level for the delegated task: use off or minimal for extraction, formatting, or mechanical work; low for straightforward bounded work; medium for ordinary multi-step research or implementation; high for complex debugging, design, review, or cross-file analysis; xhigh for highly ambiguous, cross-system, or high-risk analysis; and max only for the hardest tasks when quality clearly outweighs latency and cost. Omit subagent_spawn thinkingLevel only to preserve the agent or child default.",
|
|
152
|
-
"Set subagent_spawn timeoutMs to the shortest realistic work deadline for the task difficulty; use idleTimeoutMs for stalled work and maxTurns or maxToolCalls to stop repeated work without progress.
|
|
153
|
-
|
|
158
|
+
"Set subagent_spawn timeoutMs to the shortest realistic work deadline for the task difficulty; use idleTimeoutMs for stalled work and maxTurns or maxToolCalls to stop repeated work without progress. Scope the task to the smallest named files or questions. When setting subagent_spawn maxTurns or maxToolCalls, leave sufficient headroom for discovery, evidence reads, and final synthesis; otherwise omit them instead of guessing speculative tight values. Split oversized tasks instead of extending budgets merely to compensate for broad scope.",
|
|
159
|
+
"For an ordinary subagent_spawn, omit contract; use a delegation contract only when explicit acceptance, authority, evidence, or admission semantics are required.",
|
|
160
|
+
"Do not set subagent_spawn contract enforcement to enforce with requestedAuthority readPaths, writePaths, network, or secrets; those guarantees are unsupported and reject before child launch, while capabilities and tools remain enforceable.",
|
|
161
|
+
"If subagent_spawn rejects an unsupported guarantee, retry once with those fields removed or enforcement set to audit only when they were advisory; when any field is a required security boundary, stop instead of weakening it.",
|
|
162
|
+
"Read the current pi-subagents session-guidance message before choosing detached completion behavior. With next-turn delivery, use subagent_spawn only when the current response does not depend on its result unless useful overlap ends with an intentional subagent_await. With auto-resume delivery, final-answer-dependent detached work may continue asynchronously.",
|
|
163
|
+
'Track every final-answer-dependent subagent_spawn by setting completionRequirement to "required" and retaining its returned agentId or taskPath; treat interim output as progress, and synthesize only after every corresponding completion message is visible or terminal.',
|
|
154
164
|
"Keep ordinary review in the main agent with a review skill and deterministic checks; use subagent_spawn for detached review only when consequential independent verification has concrete parallel value.",
|
|
155
165
|
"Use a single subagent_spawn for a bounded implementation slice with clear ownership only when it can run beside the identified main-agent work.",
|
|
156
166
|
"Use a single subagent_spawn without concurrent main-agent work only for an explicit user-requested specialist model, tool profile, or isolation boundary.",
|
|
157
167
|
...blockingEnabled ? [
|
|
158
|
-
"
|
|
159
|
-
"
|
|
168
|
+
"The subagent tool is deprecated; do not select it merely because synchronous output is required. Prefer subagent_spawn with supported completion delivery, and use subagent_await only after useful overlapping main-agent work is complete and an intentional join is required.",
|
|
169
|
+
"Use deprecated subagent instead of subagent_spawn only for an existing caller or an explicit user request whose blocking chain, fan-in, panel, or workflow semantics do not yet have a detached replacement; queued steering cannot be processed until it returns."
|
|
160
170
|
] : [],
|
|
161
171
|
"Add another subagent_spawn only for truly independent work with safe workspace concurrency and disjoint write ownership; shared workspaces permit concurrent writes by default, so use workspaceMode worktree when repository isolation is required. The main agent still owns integration.",
|
|
162
172
|
"After subagent_spawn returns, immediately continue the identified local task; do not merely announce the spawn, wait, poll, or end the response while useful local work remains.",
|
|
173
|
+
"When completionRequirement required subagent_spawn work remains active after local work is exhausted, emit at most one brief progress sentence and end the turn; do not repeat waiting updates or use the requested final format, verdict, or conclusion until every required completion is visible or terminal. Current Pi versions do not enforce a hard pre-display barrier.",
|
|
174
|
+
"Do not duplicate assigned work from subagent_spawn while its retained agent is running; use a bounded parent fallback only after its completion reports failure or insufficient evidence.",
|
|
163
175
|
'Consume and synthesize available subagent_spawn completion messages; use subagent_manage with action "interrupt" or "close" for agents that are no longer needed.',
|
|
164
176
|
'Completion from subagent_spawn is delivered automatically. Do not poll with subagent_inspect or subagent_mailbox action "read", repeatedly check progress, or duplicate the delegated work.'
|
|
165
177
|
];
|
|
@@ -213,6 +225,11 @@ function renderStatefulCall(tool, args, theme) {
|
|
|
213
225
|
0
|
|
214
226
|
);
|
|
215
227
|
}
|
|
228
|
+
if (tool === "await") {
|
|
229
|
+
const metadata2 = ["blocking"];
|
|
230
|
+
if (typeof args.timeoutMs === "number") metadata2.push(`timeout:${args.timeoutMs}ms`);
|
|
231
|
+
return new Text(toolHeader(theme, "subagent_await", args.agentId, metadata2), 0, 0);
|
|
232
|
+
}
|
|
216
233
|
if (tool === "manage") {
|
|
217
234
|
const metadata2 = [];
|
|
218
235
|
if (typeof args.agentId === "string") metadata2.push(`id:${safeLine(args.agentId, "", 256)}`);
|
|
@@ -233,9 +250,12 @@ function renderStatefulResult(tool, result2, options, theme, context) {
|
|
|
233
250
|
const details = recordValue(result2.details);
|
|
234
251
|
const args = recordValue(context.args) ?? {};
|
|
235
252
|
if (!details) return renderFallbackResult(result2, options, theme, context.isError);
|
|
236
|
-
if (tool === "spawn" || tool === "send") {
|
|
253
|
+
if (tool === "spawn" || tool === "send" || tool === "await") {
|
|
237
254
|
const agent = recordValue(details.agent);
|
|
238
255
|
if (!agent) return renderFallbackResult(result2, options, theme, context.isError);
|
|
256
|
+
if (tool === "await" && details.timedOut === true) {
|
|
257
|
+
return new Text(renderAwaitTimeout(agent, result2, options.expanded, theme), 0, 0);
|
|
258
|
+
}
|
|
239
259
|
return new Text(renderAgentResult(agent, result2, options.expanded, theme), 0, 0);
|
|
240
260
|
}
|
|
241
261
|
if (tool === "manage") {
|
|
@@ -279,6 +299,16 @@ function renderAgentResult(agent, result2, expanded, theme) {
|
|
|
279
299
|
} else lines.push(expansionHint());
|
|
280
300
|
return lines.join("\n");
|
|
281
301
|
}
|
|
302
|
+
function renderAwaitTimeout(agent, result2, expanded, theme) {
|
|
303
|
+
const lines = [
|
|
304
|
+
`${statusBadge(theme, "running")} \xB7 ${theme.fg("accent", safeLine(agent.id, "agent", 256))} \xB7 ${theme.fg("warning", "wait timed out")} \xB7 ${theme.fg("muted", safeLine(agent.state, "unknown", 128))}`
|
|
305
|
+
];
|
|
306
|
+
if (expanded) {
|
|
307
|
+
const content = safeBlock(textResult(result2), "", 8 * 1024).trim();
|
|
308
|
+
if (content) lines.push(theme.fg("toolOutput", content));
|
|
309
|
+
} else lines.push(expansionHint());
|
|
310
|
+
return lines.join("\n");
|
|
311
|
+
}
|
|
282
312
|
function renderManageResult(args, details, result2, expanded, theme) {
|
|
283
313
|
const action = safeLine(args.action, "action", 128);
|
|
284
314
|
const agents = recordList(details.agents);
|
|
@@ -364,6 +394,7 @@ function lifecycleStatus(state) {
|
|
|
364
394
|
return "running";
|
|
365
395
|
case "idle":
|
|
366
396
|
return "idle";
|
|
397
|
+
case "partial":
|
|
367
398
|
case "blocked":
|
|
368
399
|
case "needs-input":
|
|
369
400
|
case "abstained":
|
|
@@ -544,13 +575,13 @@ var statefulSpawnModules;
|
|
|
544
575
|
var workspaceModule;
|
|
545
576
|
function loadStatefulSessionModules() {
|
|
546
577
|
statefulSessionModules ??= Promise.all([
|
|
547
|
-
import("./completion-delivery-
|
|
578
|
+
import("./completion-delivery-RSJU6BXL.ts"),
|
|
548
579
|
import("./peer-communication-KL36Z6CO.ts"),
|
|
549
580
|
import("./context-QDKLVQXE.ts"),
|
|
550
|
-
import("./create-stateful-transport-
|
|
581
|
+
import("./create-stateful-transport-JWC2EFYL.ts"),
|
|
551
582
|
import("./cwd-policy-NB6XZ5GF.ts"),
|
|
552
|
-
import("./persistence-
|
|
553
|
-
import("./registry-
|
|
583
|
+
import("./persistence-UY3PY6E5.ts"),
|
|
584
|
+
import("./registry-BT54L6CY.ts"),
|
|
554
585
|
import("./stateful-lifecycle-JAR6K55H.ts")
|
|
555
586
|
]).then(
|
|
556
587
|
([
|
|
@@ -580,15 +611,15 @@ function loadStatefulSessionModules() {
|
|
|
580
611
|
}
|
|
581
612
|
function loadStatefulSpawnModules() {
|
|
582
613
|
statefulSpawnModules ??= Promise.all([
|
|
583
|
-
import("./discovery-
|
|
584
|
-
import("./capability-grant-
|
|
614
|
+
import("./discovery-MIFB2U4Y.ts"),
|
|
615
|
+
import("./capability-grant-PR72SWWS.ts"),
|
|
585
616
|
import("./context-QDKLVQXE.ts"),
|
|
586
617
|
import("./cwd-policy-NB6XZ5GF.ts"),
|
|
587
|
-
import("./delegation-contract-
|
|
618
|
+
import("./delegation-contract-LA56I5DT.ts"),
|
|
588
619
|
import("./runtime-policy-5YELCOVC.ts"),
|
|
589
|
-
import("./retained-semantic-state-
|
|
620
|
+
import("./retained-semantic-state-GM75FZGE.ts"),
|
|
590
621
|
import("./semantic-snapshot-WPJ3UAFW.ts"),
|
|
591
|
-
import("./spawn-idempotency-
|
|
622
|
+
import("./spawn-idempotency-BNHOSMZW.ts")
|
|
592
623
|
]).then(
|
|
593
624
|
([
|
|
594
625
|
agents,
|
|
@@ -640,6 +671,20 @@ var StatefulTimeoutSchema = Type2.Integer({
|
|
|
640
671
|
maximum: MAX_SUBAGENT_TIMEOUT_MS,
|
|
641
672
|
description: "Work deadline in milliseconds selected for the task difficulty. On expiry, Pi aborts the work and makes one separately bounded summary attempt. Retained as the agent default."
|
|
642
673
|
});
|
|
674
|
+
var DEFAULT_SUBAGENT_AWAIT_TIMEOUT_MS = 3e4;
|
|
675
|
+
var SubagentAwaitParams = Type2.Object({
|
|
676
|
+
agentId: Type2.String({
|
|
677
|
+
minLength: 1,
|
|
678
|
+
description: "Retained agent ID or canonical task path."
|
|
679
|
+
}),
|
|
680
|
+
timeoutMs: Type2.Optional(
|
|
681
|
+
Type2.Integer({
|
|
682
|
+
minimum: 1,
|
|
683
|
+
maximum: MAX_SUBAGENT_TIMEOUT_MS,
|
|
684
|
+
description: "Maximum time to wait in milliseconds. A wait timeout stops only this tool call and does not interrupt or close the subagent. Defaults to 30000."
|
|
685
|
+
})
|
|
686
|
+
)
|
|
687
|
+
});
|
|
643
688
|
var StatefulTurnLimitFields = {
|
|
644
689
|
idleTimeoutMs: Type2.Optional(
|
|
645
690
|
Type2.Integer({
|
|
@@ -652,14 +697,14 @@ var StatefulTurnLimitFields = {
|
|
|
652
697
|
Type2.Integer({
|
|
653
698
|
minimum: 1,
|
|
654
699
|
maximum: MAX_SUBAGENT_TURNS,
|
|
655
|
-
description: "Maximum unfinished assistant turns; retained as the agent default."
|
|
700
|
+
description: "Maximum unfinished assistant turns; retained as the agent default. Omit rather than guessing a tight bound."
|
|
656
701
|
})
|
|
657
702
|
),
|
|
658
703
|
maxToolCalls: Type2.Optional(
|
|
659
704
|
Type2.Integer({
|
|
660
705
|
minimum: 1,
|
|
661
706
|
maximum: MAX_SUBAGENT_TOOL_CALLS,
|
|
662
|
-
description: "Maximum tool calls; retained as the agent default."
|
|
707
|
+
description: "Maximum tool calls; retained as the agent default. Omit rather than guessing a tight bound."
|
|
663
708
|
})
|
|
664
709
|
)
|
|
665
710
|
};
|
|
@@ -670,10 +715,8 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
670
715
|
const transportKind = resolveStatefulTransportKind(settings.transport);
|
|
671
716
|
let completionDelivery = resolveCompletionDelivery(settings.completionDelivery);
|
|
672
717
|
let runtimeLimits = resolveStatefulLimits(settings);
|
|
673
|
-
let agentCatalog = "";
|
|
674
718
|
let completionBroker;
|
|
675
719
|
let peerBroker;
|
|
676
|
-
let refreshSpawnToolRegistration;
|
|
677
720
|
let registry;
|
|
678
721
|
let persistence;
|
|
679
722
|
let sweepTimer;
|
|
@@ -719,14 +762,6 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
719
762
|
setCompletionDelivery(value) {
|
|
720
763
|
completionDelivery = value;
|
|
721
764
|
completionBroker?.setDelivery(value);
|
|
722
|
-
refreshSpawnToolRegistration?.();
|
|
723
|
-
},
|
|
724
|
-
setAgentCatalog(value) {
|
|
725
|
-
agentCatalog = value;
|
|
726
|
-
refreshSpawnToolRegistration?.();
|
|
727
|
-
},
|
|
728
|
-
refreshSettingsGuidance() {
|
|
729
|
-
refreshSpawnToolRegistration?.();
|
|
730
765
|
},
|
|
731
766
|
getRuntimeStatus() {
|
|
732
767
|
const counts = registry?.inspectionCounts() ?? { activeAgents: 0, retainedAgents: 0 };
|
|
@@ -755,7 +790,7 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
755
790
|
if (!registry) throw new Error("Stateful subagents are not initialized for this session");
|
|
756
791
|
return registry;
|
|
757
792
|
};
|
|
758
|
-
pi.on("session_start", async (
|
|
793
|
+
pi.on("session_start", async (event, ctx) => {
|
|
759
794
|
const generation = ++runtimeGeneration;
|
|
760
795
|
completionBroker?.close();
|
|
761
796
|
completionBroker = void 0;
|
|
@@ -805,9 +840,16 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
805
840
|
const reason = error instanceof Error ? error.message : String(error);
|
|
806
841
|
ctx.ui.notify(`Subagent completion delivery failed: ${reason}`, "warning");
|
|
807
842
|
},
|
|
843
|
+
onDeliveryAttempt: (completions, input) => {
|
|
844
|
+
if (generation !== runtimeGeneration) return;
|
|
845
|
+
for (const completion of completions) {
|
|
846
|
+
dependencies.usageRecording?.recordCompletionDeliveryAttempt(completion, input);
|
|
847
|
+
}
|
|
848
|
+
},
|
|
808
849
|
onAcknowledged: (completions, deliveredAt) => {
|
|
809
850
|
if (generation !== runtimeGeneration) return;
|
|
810
851
|
for (const completion of completions) {
|
|
852
|
+
dependencies.usageRecording?.recordCompletionVisible(completion);
|
|
811
853
|
void nextRegistry.markCompletionDelivered(completion.completionId, deliveredAt).catch((error) => {
|
|
812
854
|
if (!ctx.hasUI || generation !== runtimeGeneration) return;
|
|
813
855
|
const reason = error instanceof Error ? error.message : String(error);
|
|
@@ -867,6 +909,7 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
867
909
|
if (generation !== runtimeGeneration) return;
|
|
868
910
|
await sessionPersistence.save(agents);
|
|
869
911
|
if (generation !== runtimeGeneration) return;
|
|
912
|
+
dependencies.usageRecording?.observeAgents(agents);
|
|
870
913
|
for (const agent of agents) {
|
|
871
914
|
for (const message of agent.mailbox) {
|
|
872
915
|
if (seenMessageIds.has(message.id)) continue;
|
|
@@ -890,9 +933,9 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
890
933
|
}
|
|
891
934
|
},
|
|
892
935
|
onTurnComplete: (completion) => {
|
|
893
|
-
if (generation
|
|
894
|
-
|
|
895
|
-
|
|
936
|
+
if (generation !== runtimeGeneration) return;
|
|
937
|
+
dependencies.usageRecording?.recordChildCompletion(completion);
|
|
938
|
+
if (completion.recipientId === "root") sessionBroker.enqueue(completion);
|
|
896
939
|
}
|
|
897
940
|
});
|
|
898
941
|
const persisted = sessionPersistence.load();
|
|
@@ -929,6 +972,25 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
929
972
|
for (const message of agent.mailbox) seenMessageIds.add(message.id);
|
|
930
973
|
}
|
|
931
974
|
nextRegistry.restore(restored);
|
|
975
|
+
const branchRequirements = completionRequirementsFromBranch(ctx.sessionManager.getBranch());
|
|
976
|
+
const branchOwnsRequirementState = branchRequirements.observedState || event.reason === "fork" || event.reason === "new";
|
|
977
|
+
nextRegistry.reconcileCompletionRequirements(
|
|
978
|
+
branchRequirements.records,
|
|
979
|
+
branchOwnsRequirementState
|
|
980
|
+
);
|
|
981
|
+
if (branchOwnsRequirementState) {
|
|
982
|
+
try {
|
|
983
|
+
await sessionPersistence.save(nextRegistry.list(true));
|
|
984
|
+
} catch (error) {
|
|
985
|
+
if (generation === runtimeGeneration && ctx.hasUI) {
|
|
986
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
987
|
+
ctx.ui.notify(
|
|
988
|
+
`Subagent requirement reconciliation could not be persisted yet: ${reason}`,
|
|
989
|
+
"warning"
|
|
990
|
+
);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
932
994
|
if (generation !== runtimeGeneration) {
|
|
933
995
|
sessionBroker.close();
|
|
934
996
|
await sessionPeerBroker.close();
|
|
@@ -943,7 +1005,6 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
943
1005
|
if (completion.recipientId === "root") sessionBroker.enqueue(completion);
|
|
944
1006
|
}
|
|
945
1007
|
runtimeLimits = nextLimits;
|
|
946
|
-
refreshSpawnToolRegistration?.();
|
|
947
1008
|
const sweepEveryMs = Math.max(
|
|
948
1009
|
1e3,
|
|
949
1010
|
Math.min(sessionSettings.idleTtlMs ?? 60 * 60 * 1e3, 6e4)
|
|
@@ -1003,14 +1064,13 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
1003
1064
|
runtimeTransition = transition.catch(() => void 0);
|
|
1004
1065
|
await transition;
|
|
1005
1066
|
});
|
|
1006
|
-
const baseSpawnDescription = () => `Start an addressable background subagent with an opaque agentId and canonical taskPath, plus an optional thinking level and execution budgets chosen for the task difficulty, return immediately with an agentId, and receive its completion asynchronously. Detached capacity: ${runtimeLimits.maxAgents} retained agents, ${runtimeLimits.maxActiveTurns} active turns, ${runtimeLimits.maxChildrenPerAgent} direct children per agent, and depth ${runtimeLimits.maxDepth}. Working-directory target policy: ${dependencies.getSettings?.()?.cwdPolicy?.delegation ?? DEFAULT_DELEGATION_CWD_POLICY}. This controls launch targets and protected project resources, not filesystem access or sandboxing.`;
|
|
1007
1067
|
const spawnTool = defineTool({
|
|
1008
1068
|
name: "subagent_spawn",
|
|
1009
1069
|
label: "Spawn Subagent",
|
|
1010
|
-
description:
|
|
1070
|
+
description: "Start an addressable background subagent with an opaque agentId and canonical taskPath, an optional thinking level and execution budgets chosen for the task difficulty, and asynchronous completion delivery. The current bounded capacity, completion policy, working-directory policy, and available agent definitions are published in the pi-subagents session-guidance message. Working-directory policy controls launch targets and protected project resources, not filesystem access or sandboxing.",
|
|
1011
1071
|
promptSnippet: "Start a reusable detached subagent; completion is delivered asynchronously",
|
|
1012
|
-
promptGuidelines: createSpawnPromptGuidelines(
|
|
1013
|
-
parameters:
|
|
1072
|
+
promptGuidelines: createSpawnPromptGuidelines(blockingEnabled),
|
|
1073
|
+
parameters: grammarSafeToolObject({
|
|
1014
1074
|
agent: Type2.String({ minLength: 1 }),
|
|
1015
1075
|
taskName: Type2.Optional(
|
|
1016
1076
|
Type2.String({
|
|
@@ -1056,7 +1116,8 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
1056
1116
|
StringEnum2(SUBAGENT_RESULT_FORMATS, {
|
|
1057
1117
|
description: "Use text (default), structured-v1, or the evidence-preserving structured-v2 completion contract."
|
|
1058
1118
|
})
|
|
1059
|
-
)
|
|
1119
|
+
),
|
|
1120
|
+
completionRequirement: Type2.Optional(CompletionRequirementModeSchema)
|
|
1060
1121
|
}),
|
|
1061
1122
|
...createStatefulToolRenderer("spawn"),
|
|
1062
1123
|
async execute(_id, params, signal, _update, ctx) {
|
|
@@ -1146,7 +1207,8 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
1146
1207
|
workspaceMode: params.workspaceMode ?? "shared",
|
|
1147
1208
|
allowConcurrentWrites: params.allowConcurrentWrites ?? false,
|
|
1148
1209
|
contract,
|
|
1149
|
-
resultFormat
|
|
1210
|
+
resultFormat,
|
|
1211
|
+
completionRequirement: params.completionRequirement ?? "background"
|
|
1150
1212
|
});
|
|
1151
1213
|
if (!capturedRegistry) {
|
|
1152
1214
|
throw new Error("Stateful subagents are not initialized for this session");
|
|
@@ -1230,6 +1292,7 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
1230
1292
|
spawnRequestHash: params.idempotencyKey ? requestHash : void 0,
|
|
1231
1293
|
contract,
|
|
1232
1294
|
resultFormat: resultFormat === "text" ? void 0 : resultFormat,
|
|
1295
|
+
completionRequirement: params.completionRequirement ?? "background",
|
|
1233
1296
|
executionPlan,
|
|
1234
1297
|
capabilityGrant,
|
|
1235
1298
|
semanticSnapshot,
|
|
@@ -1247,10 +1310,11 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
1247
1310
|
else if (workspace) await currentWorkspaceManager.cleanup(workspaceOwner);
|
|
1248
1311
|
assertCurrentSpawn(signal, generation, runtimeGeneration);
|
|
1249
1312
|
resolvePending?.(agent);
|
|
1250
|
-
const deliveryNote = completionDelivery === "auto-resume" ? "Auto-resume
|
|
1313
|
+
const deliveryNote = completionDelivery === "auto-resume" ? "Auto-resume steers completions into active parent work or requests synthesis when idle. Treat this response as progress, not final synthesis, until every final-answer-required completion message is visible. If local work is exhausted while required children remain active, emit at most one brief progress sentence and end the turn; do not repeat waiting updates or use the requested final format, verdict, or conclusion. Do not redo a running child's assigned work." : "The current response must not depend on the result because next-turn delivery will not wake an idle root.";
|
|
1314
|
+
const requirementNote = params.completionRequirement === "required" ? "This exact run is runtime-tracked as required until its completion becomes visible or reaches an explicit terminal state. Current Pi versions still cannot prevent already-streamed premature output." : "This run is background work and does not block the parent final answer.";
|
|
1251
1315
|
return result(
|
|
1252
1316
|
agent,
|
|
1253
|
-
`Spawned ${agent.agent} as ${agent.taskPath ?? agent.id} (${agent.id}). Continue the identified non-overlapping local work immediately; do not merely announce the spawn or end while useful local work remains. Only an explicit user-requested specialist model, tool-profile, or isolation exception may lack concurrent local work. ${deliveryNote} Do not poll for progress.`
|
|
1317
|
+
`Spawned ${agent.agent} as ${agent.taskPath ?? agent.id} (${agent.id}). ${requirementNote} Continue the identified non-overlapping local work immediately; do not merely announce the spawn or end while useful local work remains. Only an explicit user-requested specialist model, tool-profile, or isolation exception may lack concurrent local work. ${deliveryNote} Do not poll for progress.`
|
|
1254
1318
|
);
|
|
1255
1319
|
} catch (error) {
|
|
1256
1320
|
rejectPending?.(error);
|
|
@@ -1262,12 +1326,7 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
1262
1326
|
}
|
|
1263
1327
|
}
|
|
1264
1328
|
});
|
|
1265
|
-
|
|
1266
|
-
spawnTool.description = appendAgentCatalog(baseSpawnDescription(), agentCatalog);
|
|
1267
|
-
spawnTool.promptGuidelines = createSpawnPromptGuidelines(completionDelivery, blockingEnabled);
|
|
1268
|
-
pi.registerTool(spawnTool);
|
|
1269
|
-
};
|
|
1270
|
-
refreshSpawnToolRegistration();
|
|
1329
|
+
pi.registerTool(spawnTool);
|
|
1271
1330
|
pi.registerTool({
|
|
1272
1331
|
name: "subagent_send",
|
|
1273
1332
|
label: "Send Subagent Follow-up",
|
|
@@ -1284,6 +1343,7 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
1284
1343
|
})
|
|
1285
1344
|
),
|
|
1286
1345
|
...StatefulTurnLimitFields,
|
|
1346
|
+
completionRequirement: Type2.Optional(CompletionRequirementModeSchema),
|
|
1287
1347
|
revalidate: Type2.Optional(
|
|
1288
1348
|
Type2.Boolean({
|
|
1289
1349
|
description: "Accept the current semantic resource snapshot after a reported mismatch before starting this follow-up."
|
|
@@ -1381,12 +1441,34 @@ function registerStatefulSubagents(pi, dependencies = {}) {
|
|
|
1381
1441
|
timeoutMs: params.timeoutMs,
|
|
1382
1442
|
idleTimeoutMs: params.idleTimeoutMs,
|
|
1383
1443
|
maxTurns: params.maxTurns,
|
|
1384
|
-
maxToolCalls: params.maxToolCalls
|
|
1444
|
+
maxToolCalls: params.maxToolCalls,
|
|
1445
|
+
completionRequirement: params.completionRequirement ?? "background"
|
|
1385
1446
|
});
|
|
1386
1447
|
assertCurrentSpawn(signal, generation, runtimeGeneration);
|
|
1387
1448
|
return result(agent, `Started follow-up for ${agent.id}.`);
|
|
1388
1449
|
}
|
|
1389
1450
|
});
|
|
1451
|
+
if (blockingEnabled) {
|
|
1452
|
+
pi.registerTool({
|
|
1453
|
+
name: "subagent_await",
|
|
1454
|
+
label: "Await Subagent",
|
|
1455
|
+
description: "Wait for one retained subagent's current turn to settle and return its latest bounded output. This blocks Pi from processing queued steering until the wait finishes. A wait timeout or caller cancellation stops only the wait and never interrupts or closes the subagent; use subagent_manage for lifecycle changes. Automatic completion delivery remains active and may later repeat the same at-least-once completion.",
|
|
1456
|
+
promptSnippet: "Intentionally block until one retained subagent settles or the wait times out",
|
|
1457
|
+
promptGuidelines: [
|
|
1458
|
+
"Use subagent_await only when the retained result is required before the next action, useful overlapping main-agent work is complete, and blocking Pi is intentional.",
|
|
1459
|
+
"Do not repeatedly call subagent_await after a timeout; the subagent keeps running and completion delivery remains active. Use subagent_manage only when the user wants to interrupt or close it."
|
|
1460
|
+
],
|
|
1461
|
+
parameters: SubagentAwaitParams,
|
|
1462
|
+
...createStatefulToolRenderer("await"),
|
|
1463
|
+
async execute(_id, params, signal) {
|
|
1464
|
+
const generation = runtimeGeneration;
|
|
1465
|
+
const timeoutMs = params.timeoutMs ?? DEFAULT_SUBAGENT_AWAIT_TIMEOUT_MS;
|
|
1466
|
+
const waited = await requireRegistry().wait(params.agentId, timeoutMs, signal);
|
|
1467
|
+
assertCurrentSpawn(signal, generation, runtimeGeneration);
|
|
1468
|
+
return awaitResult(waited.agent, waited.timedOut, timeoutMs);
|
|
1469
|
+
}
|
|
1470
|
+
});
|
|
1471
|
+
}
|
|
1390
1472
|
pi.registerTool({
|
|
1391
1473
|
name: "subagent_manage",
|
|
1392
1474
|
label: "Manage Subagents",
|
|
@@ -1521,17 +1603,33 @@ async function cleanupClosedWorkspaces(registry, isolatedAgents, workspaceManage
|
|
|
1521
1603
|
isolatedAgents.delete(agentId);
|
|
1522
1604
|
}
|
|
1523
1605
|
}
|
|
1524
|
-
function appendAgentCatalog(baseDescription, catalog) {
|
|
1525
|
-
return catalog ? `${baseDescription}
|
|
1526
|
-
|
|
1527
|
-
${catalog}` : baseDescription;
|
|
1528
|
-
}
|
|
1529
1606
|
function result(agent, text) {
|
|
1530
1607
|
return {
|
|
1531
1608
|
content: [{ type: "text", text }],
|
|
1532
1609
|
details: { agent: summarizeStatefulAgent(agent) }
|
|
1533
1610
|
};
|
|
1534
1611
|
}
|
|
1612
|
+
function awaitResult(agent, timedOut, timeoutMs) {
|
|
1613
|
+
const latestTurn = agent.history.at(-1);
|
|
1614
|
+
const output = timedOut ? "" : truncateUtf8(latestTurn?.output ?? "", DEFAULT_MAX_CONTEXT_BYTES).text;
|
|
1615
|
+
const error = timedOut ? "" : truncateUtf8(agent.error ?? "", MAX_TOOL_MESSAGE_BYTES).text;
|
|
1616
|
+
const text = timedOut ? `Stopped waiting for ${agent.taskPath ?? agent.id} after ${timeoutMs}ms; it remains ${agent.state}. The wait did not interrupt or close the subagent.` : [`Subagent ${agent.taskPath ?? agent.id} settled as ${agent.state}.`, output || error].filter(Boolean).join("\n\n");
|
|
1617
|
+
return {
|
|
1618
|
+
content: [
|
|
1619
|
+
{
|
|
1620
|
+
type: "text",
|
|
1621
|
+
text: truncateUtf8(text, DEFAULT_MAX_CONTEXT_BYTES).text
|
|
1622
|
+
}
|
|
1623
|
+
],
|
|
1624
|
+
details: {
|
|
1625
|
+
agent: summarizeStatefulAgent(agent),
|
|
1626
|
+
timedOut,
|
|
1627
|
+
timeoutMs,
|
|
1628
|
+
...output ? { output } : {},
|
|
1629
|
+
...error ? { error } : {}
|
|
1630
|
+
}
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1535
1633
|
function normalizeRuntimeThinkingLevel(value) {
|
|
1536
1634
|
return isThinkingLevel(value) ? value : "off";
|
|
1537
1635
|
}
|
|
@@ -1540,4 +1638,4 @@ export {
|
|
|
1540
1638
|
formatStatefulAgentLine,
|
|
1541
1639
|
registerStatefulSubagents
|
|
1542
1640
|
};
|
|
1543
|
-
//# sourceMappingURL=chunk-
|
|
1641
|
+
//# sourceMappingURL=chunk-2LMJU25E.ts.map
|