@narumitw/pi-subagents 2.0.1 → 2.0.3

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.
Files changed (148) hide show
  1. package/README.md +20 -7
  2. package/dist/chunks/auto-transport-SY2VHUFH.ts +109 -0
  3. package/dist/chunks/auto-transport-SY2VHUFH.ts.map +7 -0
  4. package/dist/chunks/capability-grant-CGEWOEKE.ts +19 -0
  5. package/dist/chunks/capability-grant-CGEWOEKE.ts.map +7 -0
  6. package/dist/chunks/chunk-434NII74.ts +282 -0
  7. package/dist/chunks/chunk-434NII74.ts.map +7 -0
  8. package/dist/chunks/chunk-47SK2QYC.ts +56 -0
  9. package/dist/chunks/chunk-47SK2QYC.ts.map +7 -0
  10. package/dist/chunks/chunk-6KJ34M6S.ts +159 -0
  11. package/dist/chunks/chunk-6KJ34M6S.ts.map +7 -0
  12. package/dist/chunks/chunk-7OBINKFM.ts +80 -0
  13. package/dist/chunks/chunk-7OBINKFM.ts.map +7 -0
  14. package/dist/chunks/chunk-7QPPBBXZ.ts +335 -0
  15. package/dist/chunks/chunk-7QPPBBXZ.ts.map +7 -0
  16. package/dist/chunks/chunk-AEUYS7JC.ts +73 -0
  17. package/dist/chunks/chunk-AEUYS7JC.ts.map +7 -0
  18. package/dist/chunks/chunk-BFK2Z4ZF.ts +189 -0
  19. package/dist/chunks/chunk-BFK2Z4ZF.ts.map +7 -0
  20. package/dist/chunks/chunk-BOAXY55Y.ts +153 -0
  21. package/dist/chunks/chunk-BOAXY55Y.ts.map +7 -0
  22. package/dist/chunks/chunk-C4L6P266.ts +22 -0
  23. package/dist/chunks/chunk-C4L6P266.ts.map +7 -0
  24. package/dist/chunks/chunk-DPPVEQAM.ts +29 -0
  25. package/dist/chunks/chunk-DPPVEQAM.ts.map +7 -0
  26. package/dist/chunks/chunk-DQMN4OYM.ts +913 -0
  27. package/dist/chunks/chunk-DQMN4OYM.ts.map +7 -0
  28. package/dist/chunks/chunk-DSOOH73Y.ts +238 -0
  29. package/dist/chunks/chunk-DSOOH73Y.ts.map +7 -0
  30. package/dist/chunks/chunk-EFBPISNT.ts +421 -0
  31. package/dist/chunks/chunk-EFBPISNT.ts.map +7 -0
  32. package/dist/chunks/chunk-EWWXFU7N.ts +150 -0
  33. package/dist/chunks/chunk-EWWXFU7N.ts.map +7 -0
  34. package/dist/chunks/chunk-F4L2UVSK.ts +380 -0
  35. package/dist/chunks/chunk-F4L2UVSK.ts.map +7 -0
  36. package/dist/chunks/chunk-F5YWVHQX.ts +1543 -0
  37. package/dist/chunks/chunk-F5YWVHQX.ts.map +7 -0
  38. package/dist/chunks/chunk-G3RSMSXJ.ts +63 -0
  39. package/dist/chunks/chunk-G3RSMSXJ.ts.map +7 -0
  40. package/dist/chunks/chunk-G6VZTCFH.ts +70 -0
  41. package/dist/chunks/chunk-G6VZTCFH.ts.map +7 -0
  42. package/dist/chunks/chunk-H3FP6DLR.ts +160 -0
  43. package/dist/chunks/chunk-H3FP6DLR.ts.map +7 -0
  44. package/dist/chunks/chunk-HA36LPCO.ts +130 -0
  45. package/dist/chunks/chunk-HA36LPCO.ts.map +7 -0
  46. package/dist/chunks/chunk-HKC4ES4B.ts +65 -0
  47. package/dist/chunks/chunk-HKC4ES4B.ts.map +7 -0
  48. package/dist/chunks/chunk-HOP5FXDT.ts +27 -0
  49. package/dist/chunks/chunk-HOP5FXDT.ts.map +7 -0
  50. package/dist/chunks/chunk-I2FAK44T.ts +324 -0
  51. package/dist/chunks/chunk-I2FAK44T.ts.map +7 -0
  52. package/dist/chunks/chunk-IGAMVWFN.ts +139 -0
  53. package/dist/chunks/chunk-IGAMVWFN.ts.map +7 -0
  54. package/dist/chunks/chunk-KMGKCEO4.ts +38 -0
  55. package/dist/chunks/chunk-KMGKCEO4.ts.map +7 -0
  56. package/dist/chunks/chunk-N7BLVXKK.ts +73 -0
  57. package/dist/chunks/chunk-N7BLVXKK.ts.map +7 -0
  58. package/dist/chunks/chunk-NIF42QMF.ts +297 -0
  59. package/dist/chunks/chunk-NIF42QMF.ts.map +7 -0
  60. package/dist/chunks/chunk-O4VO6JUJ.ts +52 -0
  61. package/dist/chunks/chunk-O4VO6JUJ.ts.map +7 -0
  62. package/dist/chunks/chunk-ONDTY4EL.ts +91 -0
  63. package/dist/chunks/chunk-ONDTY4EL.ts.map +7 -0
  64. package/dist/chunks/chunk-OVPHFGKO.ts +1769 -0
  65. package/dist/chunks/chunk-OVPHFGKO.ts.map +7 -0
  66. package/dist/chunks/chunk-P7OH4XMF.ts +60 -0
  67. package/dist/chunks/chunk-P7OH4XMF.ts.map +7 -0
  68. package/dist/chunks/chunk-PSK43Y6A.ts +339 -0
  69. package/dist/chunks/chunk-PSK43Y6A.ts.map +7 -0
  70. package/dist/chunks/chunk-QBORTI4W.ts +468 -0
  71. package/dist/chunks/chunk-QBORTI4W.ts.map +7 -0
  72. package/dist/chunks/chunk-QDVGH2X7.ts +171 -0
  73. package/dist/chunks/chunk-QDVGH2X7.ts.map +7 -0
  74. package/dist/chunks/chunk-RHRQMT7Q.ts +490 -0
  75. package/dist/chunks/chunk-RHRQMT7Q.ts.map +7 -0
  76. package/dist/chunks/chunk-RRR66UWR.ts +28 -0
  77. package/dist/chunks/chunk-RRR66UWR.ts.map +7 -0
  78. package/dist/chunks/chunk-RSUXZD6S.ts +275 -0
  79. package/dist/chunks/chunk-RSUXZD6S.ts.map +7 -0
  80. package/dist/chunks/chunk-RTCVYIZA.ts +221 -0
  81. package/dist/chunks/chunk-RTCVYIZA.ts.map +7 -0
  82. package/dist/chunks/chunk-S2IWVK3J.ts +44 -0
  83. package/dist/chunks/chunk-S2IWVK3J.ts.map +7 -0
  84. package/dist/chunks/chunk-SCZ33MYW.ts +52 -0
  85. package/dist/chunks/chunk-SCZ33MYW.ts.map +7 -0
  86. package/dist/chunks/chunk-SWGQLFSD.ts +60 -0
  87. package/dist/chunks/chunk-SWGQLFSD.ts.map +7 -0
  88. package/dist/chunks/chunk-UMBPMVJW.ts +22 -0
  89. package/dist/chunks/chunk-UMBPMVJW.ts.map +7 -0
  90. package/dist/chunks/chunk-UVFVHIOP.ts +735 -0
  91. package/dist/chunks/chunk-UVFVHIOP.ts.map +7 -0
  92. package/dist/chunks/completion-delivery-YPOWSSV3.ts +16 -0
  93. package/dist/chunks/completion-delivery-YPOWSSV3.ts.map +7 -0
  94. package/dist/chunks/config-status-J4GPWP46.ts +34 -0
  95. package/dist/chunks/config-status-J4GPWP46.ts.map +7 -0
  96. package/dist/chunks/config-ui-3IBMHTQB.ts +1146 -0
  97. package/dist/chunks/config-ui-3IBMHTQB.ts.map +7 -0
  98. package/dist/chunks/consult-NYXVDN5G.ts +518 -0
  99. package/dist/chunks/consult-NYXVDN5G.ts.map +7 -0
  100. package/dist/chunks/context-QDKLVQXE.ts +11 -0
  101. package/dist/chunks/context-QDKLVQXE.ts.map +7 -0
  102. package/dist/chunks/create-stateful-transport-4WKZHRSI.ts +130 -0
  103. package/dist/chunks/create-stateful-transport-4WKZHRSI.ts.map +7 -0
  104. package/dist/chunks/cwd-policy-NB6XZ5GF.ts +17 -0
  105. package/dist/chunks/cwd-policy-NB6XZ5GF.ts.map +7 -0
  106. package/dist/chunks/delegation-contract-WJPT4FVS.ts +24 -0
  107. package/dist/chunks/delegation-contract-WJPT4FVS.ts.map +7 -0
  108. package/dist/chunks/discovery-K25T3SH4.ts +12 -0
  109. package/dist/chunks/discovery-K25T3SH4.ts.map +7 -0
  110. package/dist/chunks/execution-DS2DEIQZ.ts +4034 -0
  111. package/dist/chunks/execution-DS2DEIQZ.ts.map +7 -0
  112. package/dist/chunks/in-process-transport-TEYAWSEC.ts +38 -0
  113. package/dist/chunks/in-process-transport-TEYAWSEC.ts.map +7 -0
  114. package/dist/chunks/inspect-UOQQ3KNL.ts +619 -0
  115. package/dist/chunks/inspect-UOQQ3KNL.ts.map +7 -0
  116. package/dist/chunks/peer-communication-KL36Z6CO.ts +294 -0
  117. package/dist/chunks/peer-communication-KL36Z6CO.ts.map +7 -0
  118. package/dist/chunks/persistence-VSGXAW4P.ts +344 -0
  119. package/dist/chunks/persistence-VSGXAW4P.ts.map +7 -0
  120. package/dist/chunks/registry-E6XPJB7L.ts +1324 -0
  121. package/dist/chunks/registry-E6XPJB7L.ts.map +7 -0
  122. package/dist/chunks/retained-semantic-state-7WXSGRJU.ts +81 -0
  123. package/dist/chunks/retained-semantic-state-7WXSGRJU.ts.map +7 -0
  124. package/dist/chunks/rpc-transport-Y6LA5BOP.ts +1154 -0
  125. package/dist/chunks/rpc-transport-Y6LA5BOP.ts.map +7 -0
  126. package/dist/chunks/runtime-policy-5YELCOVC.ts +15 -0
  127. package/dist/chunks/runtime-policy-5YELCOVC.ts.map +7 -0
  128. package/dist/chunks/semantic-snapshot-WPJ3UAFW.ts +19 -0
  129. package/dist/chunks/semantic-snapshot-WPJ3UAFW.ts.map +7 -0
  130. package/dist/chunks/spawn-idempotency-QGHO2WKC.ts +13 -0
  131. package/dist/chunks/spawn-idempotency-QGHO2WKC.ts.map +7 -0
  132. package/dist/chunks/stateful-lifecycle-JAR6K55H.ts +15 -0
  133. package/dist/chunks/stateful-lifecycle-JAR6K55H.ts.map +7 -0
  134. package/dist/chunks/subprocess-transport-C2XVR25R.ts +158 -0
  135. package/dist/chunks/subprocess-transport-C2XVR25R.ts.map +7 -0
  136. package/dist/chunks/workspace-WDKLN72J.ts +11 -0
  137. package/dist/chunks/workspace-WDKLN72J.ts.map +7 -0
  138. package/dist/index.ts +1057 -0
  139. package/dist/index.ts.map +7 -0
  140. package/package.json +9 -5
  141. package/src/index.ts +1 -1
  142. package/src/settings-reader.ts +208 -0
  143. package/src/settings.ts +22 -187
  144. package/src/stateful-registration.ts +1230 -0
  145. package/src/stateful-safety.ts +1 -1
  146. package/src/stateful.ts +2 -1234
  147. package/src/subagents-extension.ts +307 -0
  148. package/src/subagents.ts +1 -308
@@ -0,0 +1,1154 @@
1
+ // @generated by scripts/build-runtime.mjs; do not edit.
2
+ // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
+ import {
4
+ buildStatefulTurnPrompt,
5
+ resolveStatefulTurnTimeout
6
+ } from "./chunk-SCZ33MYW.ts";
7
+ import {
8
+ JsonLineDecoder,
9
+ terminateProcess
10
+ } from "./chunk-DQMN4OYM.ts";
11
+ import {
12
+ resolvePiInvocation
13
+ } from "./chunk-IGAMVWFN.ts";
14
+ import "./chunk-47SK2QYC.ts";
15
+ import "./chunk-HKC4ES4B.ts";
16
+ import "./chunk-DSOOH73Y.ts";
17
+ import {
18
+ buildCurrentTurnPrompt,
19
+ validateInProcessTools
20
+ } from "./chunk-UVFVHIOP.ts";
21
+ import {
22
+ CHILD_PEER_TOOL_NAMES,
23
+ childPeerBridgePath,
24
+ formatPeerMessage,
25
+ peerBridgeEnvironment
26
+ } from "./chunk-EWWXFU7N.ts";
27
+ import {
28
+ resolvePiPromptResources
29
+ } from "./chunk-G6VZTCFH.ts";
30
+ import {
31
+ buildTimeoutFinalizationPrompt,
32
+ resolveTimeoutFinalizationMs
33
+ } from "./chunk-G3RSMSXJ.ts";
34
+ import "./chunk-AEUYS7JC.ts";
35
+ import {
36
+ TURN_TERMINATION_VERSION,
37
+ TimeoutProgressJournal,
38
+ formatTimeoutCheckpoint,
39
+ formatTurnTerminationMessage,
40
+ journalMessages
41
+ } from "./chunk-RTCVYIZA.ts";
42
+ import {
43
+ TurnBudgetMonitor
44
+ } from "./chunk-ONDTY4EL.ts";
45
+ import {
46
+ discoverAgents
47
+ } from "./chunk-PSK43Y6A.ts";
48
+ import "./chunk-RSUXZD6S.ts";
49
+ import "./chunk-7QPPBBXZ.ts";
50
+ import {
51
+ readSubagentSettings
52
+ } from "./chunk-QBORTI4W.ts";
53
+ import "./chunk-7OBINKFM.ts";
54
+ import "./chunk-DPPVEQAM.ts";
55
+ import {
56
+ PI_SUBAGENTS_RPC_PROTOCOL,
57
+ emptyTransportUsage
58
+ } from "./chunk-C4L6P266.ts";
59
+ import {
60
+ boundedPrivateText,
61
+ safeTerminalText
62
+ } from "./chunk-SWGQLFSD.ts";
63
+ import "./chunk-I2FAK44T.ts";
64
+ import {
65
+ DEFAULT_MAX_OUTPUT_BYTES,
66
+ DEFAULT_MAX_STDERR_BYTES,
67
+ appendBounded,
68
+ truncateUtf8
69
+ } from "./chunk-H3FP6DLR.ts";
70
+ import "./chunk-RRR66UWR.ts";
71
+
72
+ // src/rpc-transport.ts
73
+ import { spawn } from "node:child_process";
74
+ import * as fs from "node:fs";
75
+ import * as os from "node:os";
76
+ import * as path from "node:path";
77
+
78
+ // src/rpc-timeout-finalization.ts
79
+ async function finalizeTimedOutRpcTurn(options) {
80
+ options.resetCapture();
81
+ let settleResolve;
82
+ let settleReject;
83
+ const settled = new Promise((resolve, reject) => {
84
+ settleResolve = resolve;
85
+ settleReject = reject;
86
+ });
87
+ void settled.catch(() => void 0);
88
+ const unsubscribeEvent = options.client.onEvent((event) => {
89
+ if (eventType(event) === "agent_settled") settleResolve();
90
+ });
91
+ const unsubscribeClose = options.client.onClose(settleReject);
92
+ let error;
93
+ try {
94
+ const finalizationMs = resolveTimeoutFinalizationMs(
95
+ options.workTimeoutMs,
96
+ options.finalizationTimeoutMs
97
+ );
98
+ const deadline = Date.now() + finalizationMs;
99
+ await raceWithAbort(
100
+ () => options.client.prompt(
101
+ buildTimeoutFinalizationPrompt({
102
+ task: options.task,
103
+ partialOutput: options.partialOutput,
104
+ checkpoint: options.checkpoint,
105
+ terminationReason: options.terminationReason,
106
+ resultFormat: options.resultFormat
107
+ }),
108
+ remainingMs(deadline)
109
+ ),
110
+ options.signal,
111
+ remainingMs(deadline)
112
+ );
113
+ const settlement = await waitForSettlement(settled, options.signal, remainingMs(deadline));
114
+ if (settlement !== "settled") {
115
+ const [abortCompleted, stopped] = await Promise.all([
116
+ settlesWithin(options.client.abort(), options.abortGraceMs),
117
+ settlesWithin(settled, options.abortGraceMs)
118
+ ]);
119
+ if (!stopped) await boundedRelease(options);
120
+ error = [
121
+ `timeout summary ${settlement}`,
122
+ abortCompleted ? void 0 : "summary abort command did not settle"
123
+ ].filter(Boolean).join("; ");
124
+ }
125
+ } catch (caught) {
126
+ error = boundedError(caught);
127
+ await boundedRelease(options);
128
+ } finally {
129
+ unsubscribeEvent();
130
+ unsubscribeClose();
131
+ }
132
+ const capture = options.getCapture();
133
+ const output = truncateUtf8(capture.output || capture.partial, DEFAULT_MAX_OUTPUT_BYTES);
134
+ if (!error && (capture.stopReason === "error" || !output.text.trim())) {
135
+ error = capture.error || "Timeout summary produced no final text";
136
+ }
137
+ return {
138
+ output: output.text,
139
+ truncated: output.truncated,
140
+ status: error ? /timed out|timeout/iu.test(error) ? "timed_out" : "failed" : "completed",
141
+ error
142
+ };
143
+ }
144
+ function eventType(value) {
145
+ return value && typeof value === "object" && typeof value.type === "string" ? value.type ?? void 0 : void 0;
146
+ }
147
+ function remainingMs(deadline) {
148
+ return Math.max(1, deadline - Date.now());
149
+ }
150
+ async function raceWithAbort(start, signal, timeoutMs) {
151
+ if (signal.aborted) throw abortError();
152
+ let onAbort;
153
+ let timer;
154
+ const aborted = new Promise((_resolve, reject) => {
155
+ onAbort = () => reject(abortError());
156
+ signal.addEventListener("abort", onAbort, { once: true });
157
+ if (signal.aborted) onAbort();
158
+ });
159
+ const timedOut = new Promise((_resolve, reject) => {
160
+ timer = setTimeout(() => reject(new Error("RPC timeout summary prompt timed out")), timeoutMs);
161
+ });
162
+ try {
163
+ return await Promise.race([start(), aborted, timedOut]);
164
+ } finally {
165
+ if (timer) clearTimeout(timer);
166
+ if (onAbort) signal.removeEventListener("abort", onAbort);
167
+ }
168
+ }
169
+ async function waitForSettlement(settled, signal, timeoutMs) {
170
+ if (signal.aborted) return "aborted";
171
+ let timer;
172
+ let onAbort;
173
+ try {
174
+ return await Promise.race([
175
+ settled.then(() => "settled"),
176
+ new Promise((resolve) => {
177
+ onAbort = () => resolve("aborted");
178
+ signal.addEventListener("abort", onAbort, { once: true });
179
+ }),
180
+ new Promise((resolve) => {
181
+ timer = setTimeout(() => resolve("timeout"), timeoutMs);
182
+ })
183
+ ]);
184
+ } finally {
185
+ if (timer) clearTimeout(timer);
186
+ if (onAbort) signal.removeEventListener("abort", onAbort);
187
+ }
188
+ }
189
+ async function boundedRelease(options) {
190
+ return settlesWithin(options.release(), options.abortGraceMs + 1e3);
191
+ }
192
+ async function settlesWithin(settled, timeoutMs) {
193
+ let timer;
194
+ try {
195
+ return await Promise.race([
196
+ settled.then(
197
+ () => true,
198
+ () => true
199
+ ),
200
+ new Promise((resolve) => {
201
+ timer = setTimeout(() => resolve(false), timeoutMs);
202
+ })
203
+ ]);
204
+ } finally {
205
+ if (timer) clearTimeout(timer);
206
+ }
207
+ }
208
+ function abortError() {
209
+ const error = new Error("RPC timeout summary aborted");
210
+ error.name = "AbortError";
211
+ return error;
212
+ }
213
+ function boundedError(error) {
214
+ return truncateUtf8(error instanceof Error ? error.message : String(error), 16 * 1024).text;
215
+ }
216
+
217
+ // src/rpc-transport-metadata.ts
218
+ function modelIdentity(value) {
219
+ if (!value || typeof value !== "object") return {};
220
+ const model = value;
221
+ return {
222
+ provider: typeof model.provider === "string" ? boundedPrivateText(model.provider, 256) : void 0,
223
+ model: typeof model.id === "string" ? boundedPrivateText(model.id, 256) : void 0
224
+ };
225
+ }
226
+ function normalizeThinking(value) {
227
+ return typeof value === "string" && ["off", "minimal", "low", "medium", "high", "xhigh", "max"].includes(value) ? value : void 0;
228
+ }
229
+ function rpcPolicy(config, agent) {
230
+ return {
231
+ inherited: ["environment", "cwdResources"],
232
+ overridden: [
233
+ "cwd",
234
+ "extensions",
235
+ ...config.model ? ["model"] : [],
236
+ ...agent.thinkingLevel || config.thinkingLevel ? ["thinkingLevel"] : [],
237
+ ...config.tools ? ["tools"] : []
238
+ ],
239
+ unsupported: ["approvalPolicy", "sandboxProfile", "providerHeaders", "extensionState"]
240
+ };
241
+ }
242
+ function interruptedRpcOutcome(output, telemetry, failurePhase) {
243
+ return {
244
+ output,
245
+ exitCode: 130,
246
+ aborted: true,
247
+ error: "RPC subagent was aborted",
248
+ telemetry: {
249
+ ...telemetry,
250
+ phase: "interrupted",
251
+ failurePhase,
252
+ updatedAt: Date.now()
253
+ }
254
+ };
255
+ }
256
+ function boundedError2(error) {
257
+ return boundedPrivateText(
258
+ error instanceof Error ? error.message : String(error),
259
+ DEFAULT_MAX_OUTPUT_BYTES
260
+ );
261
+ }
262
+
263
+ // src/rpc-turn-capture.ts
264
+ function createRpcTurnCapture() {
265
+ return {
266
+ output: "",
267
+ partial: "",
268
+ usage: emptyTransportUsage(),
269
+ journal: new TimeoutProgressJournal()
270
+ };
271
+ }
272
+ function captureRpcEvent(event, capture) {
273
+ if (!isRecord(event)) return;
274
+ if (event.type === "tool_execution_start") {
275
+ capture.journal.recordToolCall(
276
+ typeof event.toolCallId === "string" ? event.toolCallId : "",
277
+ typeof event.toolName === "string" ? event.toolName : "tool",
278
+ isRecord(event.args) ? event.args : {}
279
+ );
280
+ }
281
+ if (event.type === "tool_execution_end") {
282
+ const result = isRecord(event.result) ? event.result : {};
283
+ capture.journal.recordToolResult(
284
+ typeof event.toolCallId === "string" ? event.toolCallId : "",
285
+ typeof event.toolName === "string" ? event.toolName : "tool",
286
+ { content: result.content, isError: event.isError }
287
+ );
288
+ }
289
+ if (event.type === "message_update") {
290
+ const delta = event.assistantMessageEvent;
291
+ if (isRecord(delta) && delta.type === "text_delta" && typeof delta.delta === "string") {
292
+ capture.partial = truncateUtf8(
293
+ `${capture.partial}${delta.delta}`,
294
+ DEFAULT_MAX_OUTPUT_BYTES
295
+ ).text;
296
+ }
297
+ }
298
+ if (event.type !== "message_end" || !isRecord(event.message)) return;
299
+ const candidate = event.message;
300
+ if (candidate.role !== "toolResult") journalMessages(capture.journal, [candidate]);
301
+ if (candidate.role !== "assistant") return;
302
+ capture.output = truncateUtf8(
303
+ assistantText(candidate.content) || capture.partial,
304
+ DEFAULT_MAX_OUTPUT_BYTES
305
+ ).text;
306
+ capture.partial = capture.output;
307
+ capture.stopReason = typeof candidate.stopReason === "string" ? candidate.stopReason : void 0;
308
+ capture.error = typeof candidate.errorMessage === "string" ? boundedPrivateText(candidate.errorMessage, 4 * 1024) : void 0;
309
+ capture.provider = typeof candidate.provider === "string" ? boundedPrivateText(candidate.provider, 256) : void 0;
310
+ const responseModel = typeof candidate.responseModel === "string" ? candidate.responseModel : typeof candidate.model === "string" ? candidate.model : void 0;
311
+ capture.model = responseModel ? boundedPrivateText(responseModel, 256) : void 0;
312
+ capture.usage.turns++;
313
+ addUsage(capture.usage, candidate.usage);
314
+ }
315
+ function observeRpcBudgetEvent(event, monitor) {
316
+ if (!isRecord(event)) return;
317
+ if (event.type === "tool_execution_end") monitor.recordActivity();
318
+ if (event.type !== "message_end" || !isRecord(event.message)) return;
319
+ const message = event.message;
320
+ if (message.role === "toolResult") {
321
+ monitor.recordActivity();
322
+ return;
323
+ }
324
+ if (message.role !== "assistant") return;
325
+ monitor.recordToolCalls(assistantToolCallCount(message.content));
326
+ monitor.recordAssistantTurn(
327
+ typeof message.stopReason === "string" ? message.stopReason : void 0
328
+ );
329
+ }
330
+ function assistantToolCallCount(content) {
331
+ if (!Array.isArray(content)) return 0;
332
+ return content.filter((part) => isRecord(part) && part.type === "toolCall").length;
333
+ }
334
+ function addUsage(target, value) {
335
+ if (!isRecord(value)) return;
336
+ target.input += safeNonNegative(value.input);
337
+ target.output += safeNonNegative(value.output);
338
+ target.cacheRead += safeNonNegative(value.cacheRead);
339
+ target.cacheWrite += safeNonNegative(value.cacheWrite);
340
+ const reportedTotal = safeNonNegative(value.totalTokens);
341
+ target.totalTokens += reportedTotal || safeNonNegative(value.input) + safeNonNegative(value.output) + safeNonNegative(value.cacheRead) + safeNonNegative(value.cacheWrite);
342
+ if (isRecord(value.cost)) target.cost += safeNonNegative(value.cost.total);
343
+ }
344
+ function safeNonNegative(value) {
345
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= Number.MAX_SAFE_INTEGER ? value : 0;
346
+ }
347
+ function assistantText(value) {
348
+ if (typeof value === "string") return value;
349
+ if (!Array.isArray(value)) return "";
350
+ return value.flatMap((part) => {
351
+ if (!isRecord(part)) return [];
352
+ return part.type === "text" && typeof part.text === "string" ? [part.text] : [];
353
+ }).join("\n");
354
+ }
355
+ function isRecord(value) {
356
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
357
+ }
358
+
359
+ // src/rpc-transport.ts
360
+ var COMMAND_TIMEOUT_MS = 3e4;
361
+ var STARTUP_TIMEOUT_MS = 3e4;
362
+ var ABORT_GRACE_MS = 5e3;
363
+ var BUILT_IN_TOOL_NAMES = /* @__PURE__ */ new Set(["read", "bash", "edit", "write", "grep", "find", "ls"]);
364
+ var RpcProtocolClient = class {
365
+ constructor(options) {
366
+ this.options = options;
367
+ }
368
+ options;
369
+ process;
370
+ processClosed = false;
371
+ decoder;
372
+ pending = /* @__PURE__ */ new Map();
373
+ listeners = /* @__PURE__ */ new Set();
374
+ closeListeners = /* @__PURE__ */ new Set();
375
+ nextRequestId = 0;
376
+ stderr = "";
377
+ malformedLines = 0;
378
+ oversizedLines = 0;
379
+ closedError;
380
+ closePromise;
381
+ cleanupTermination;
382
+ async start(signal) {
383
+ if (this.process) throw new Error("RPC subagent client already started");
384
+ if (signal?.aborted) throw abortError2("RPC subagent start aborted");
385
+ const invocation = this.options.invocation ? {
386
+ command: this.options.invocation.command,
387
+ args: [...this.options.invocation.args, ...this.options.args]
388
+ } : resolvePiInvocation(this.options.args);
389
+ const proc = spawn(invocation.command, invocation.args, {
390
+ cwd: this.options.cwd,
391
+ detached: process.platform !== "win32",
392
+ shell: false,
393
+ stdio: ["pipe", "pipe", "pipe"],
394
+ env: { ...process.env, ...this.options.env }
395
+ });
396
+ this.process = proc;
397
+ this.processClosed = false;
398
+ this.decoder = new JsonLineDecoder({
399
+ onValue: (value) => this.handleValue(value),
400
+ onMalformed: () => {
401
+ this.malformedLines++;
402
+ this.fail(new Error("RPC subagent emitted malformed JSONL"));
403
+ },
404
+ onOversized: () => {
405
+ this.oversizedLines++;
406
+ this.fail(new Error("RPC subagent emitted an oversized JSONL record"));
407
+ }
408
+ });
409
+ proc.stdout?.on("data", (chunk) => this.decoder?.push(chunk));
410
+ proc.stdin?.on("error", (error) => this.fail(errorMessage("RPC stdin failed", error)));
411
+ proc.stderr?.on("data", (chunk) => {
412
+ this.stderr = appendBounded(
413
+ this.stderr,
414
+ Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk),
415
+ DEFAULT_MAX_STDERR_BYTES
416
+ ).text;
417
+ });
418
+ proc.once("error", (error) => this.fail(errorMessage("RPC process failed", error)));
419
+ proc.once("close", (code, childSignal) => {
420
+ this.processClosed = true;
421
+ this.decoder?.finish();
422
+ this.fail(
423
+ new Error(
424
+ `RPC subagent exited (code=${code ?? "null"}, signal=${childSignal ?? "null"})${this.stderr ? `: ${safeTerminalText(this.stderr)}` : ""}`
425
+ )
426
+ );
427
+ });
428
+ try {
429
+ await waitForSpawn(proc, signal, this.options.startupTimeoutMs ?? STARTUP_TIMEOUT_MS);
430
+ if (signal?.aborted) throw abortError2("RPC subagent start aborted");
431
+ const state = await raceWithAbort2(
432
+ this.requestData(
433
+ { type: "get_state" },
434
+ this.options.startupTimeoutMs ?? STARTUP_TIMEOUT_MS
435
+ ),
436
+ signal,
437
+ "RPC subagent readiness aborted"
438
+ );
439
+ return {
440
+ state,
441
+ stderr: this.stderr,
442
+ malformedLines: this.malformedLines,
443
+ oversizedLines: this.oversizedLines
444
+ };
445
+ } catch (error) {
446
+ await this.stop();
447
+ throw error;
448
+ }
449
+ }
450
+ onEvent(listener) {
451
+ this.listeners.add(listener);
452
+ return () => this.listeners.delete(listener);
453
+ }
454
+ onClose(listener) {
455
+ this.closeListeners.add(listener);
456
+ return () => this.closeListeners.delete(listener);
457
+ }
458
+ async prompt(message, timeoutMs) {
459
+ await this.request({ type: "prompt", message }, timeoutMs);
460
+ }
461
+ async steer(message, timeoutMs) {
462
+ await this.request({ type: "steer", message }, timeoutMs);
463
+ }
464
+ async abort() {
465
+ await this.request(
466
+ { type: "abort" },
467
+ this.options.abortTimeoutMs ?? Math.min(COMMAND_TIMEOUT_MS, ABORT_GRACE_MS)
468
+ );
469
+ }
470
+ async getState() {
471
+ return this.requestData({ type: "get_state" });
472
+ }
473
+ getStderr() {
474
+ return this.stderr;
475
+ }
476
+ async stop() {
477
+ if (this.closePromise) return this.closePromise;
478
+ const proc = this.process;
479
+ if (!proc) return;
480
+ if (this.processClosed) {
481
+ this.cleanupTermination?.();
482
+ this.cleanupTermination = void 0;
483
+ this.process = void 0;
484
+ this.rejectPending(this.closedError ?? new Error("RPC subagent process already exited"));
485
+ this.listeners.clear();
486
+ this.closeListeners.clear();
487
+ return;
488
+ }
489
+ this.closePromise = new Promise((resolve) => {
490
+ let settled = false;
491
+ let terminationDeadline;
492
+ const finish = () => {
493
+ if (settled) return;
494
+ settled = true;
495
+ if (terminationDeadline) clearTimeout(terminationDeadline);
496
+ proc.off("close", finish);
497
+ this.cleanupTermination?.();
498
+ this.cleanupTermination = void 0;
499
+ resolve();
500
+ };
501
+ proc.once("close", finish);
502
+ try {
503
+ proc.stdin?.end();
504
+ } catch {
505
+ }
506
+ const graceMs = this.options.terminationGraceMs ?? ABORT_GRACE_MS;
507
+ this.cleanupTermination?.();
508
+ this.cleanupTermination = terminateProcess(proc, graceMs);
509
+ terminationDeadline = setTimeout(() => {
510
+ proc.stdin?.destroy();
511
+ proc.stdout?.destroy();
512
+ proc.stderr?.destroy();
513
+ finish();
514
+ }, graceMs + 1e3);
515
+ });
516
+ await this.closePromise;
517
+ this.process = void 0;
518
+ this.rejectPending(new Error("RPC subagent client stopped"));
519
+ this.listeners.clear();
520
+ this.closeListeners.clear();
521
+ }
522
+ async requestData(command, timeoutMs = this.options.commandTimeoutMs ?? COMMAND_TIMEOUT_MS) {
523
+ const response = await this.request(command, timeoutMs);
524
+ return response.data;
525
+ }
526
+ request(command, timeoutMs = this.options.commandTimeoutMs ?? COMMAND_TIMEOUT_MS) {
527
+ const proc = this.process;
528
+ if (!proc?.stdin || proc.stdin.destroyed || !proc.stdin.writable) {
529
+ return Promise.reject(this.closedError ?? new Error("RPC subagent stdin is unavailable"));
530
+ }
531
+ const id = `psa_${++this.nextRequestId}`;
532
+ return new Promise((resolve, reject) => {
533
+ const timer = setTimeout(() => {
534
+ this.pending.delete(id);
535
+ reject(rpcTimeoutError(`RPC ${command.type} response timed out after ${timeoutMs}ms`));
536
+ }, timeoutMs);
537
+ timer.unref();
538
+ this.pending.set(id, { command: command.type, resolve, reject, timer });
539
+ try {
540
+ proc.stdin?.write(`${JSON.stringify({ ...command, id })}
541
+ `, (error) => {
542
+ if (!error) return;
543
+ this.fail(errorMessage("RPC stdin write failed", error));
544
+ });
545
+ } catch (error) {
546
+ this.pending.delete(id);
547
+ clearTimeout(timer);
548
+ reject(error instanceof Error ? error : new Error(String(error)));
549
+ }
550
+ }).then((response) => {
551
+ if (!response.success) throw new Error(response.error || `RPC ${command.type} failed`);
552
+ return response;
553
+ });
554
+ }
555
+ handleValue(value) {
556
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
557
+ const event = value;
558
+ if (event.type === "response" && typeof event.id === "string") {
559
+ const pending = this.pending.get(event.id);
560
+ if (!pending) return;
561
+ if (typeof event.command !== "string" || event.command !== pending.command) {
562
+ this.fail(
563
+ new Error(`RPC response command mismatch for ${event.id}: expected ${pending.command}`)
564
+ );
565
+ return;
566
+ }
567
+ this.pending.delete(event.id);
568
+ clearTimeout(pending.timer);
569
+ pending.resolve(event);
570
+ return;
571
+ }
572
+ if (event.type === "extension_ui_request" && typeof event.id === "string") {
573
+ this.writeFireAndForget({
574
+ type: "extension_ui_response",
575
+ id: event.id,
576
+ cancelled: true
577
+ });
578
+ }
579
+ for (const listener of this.listeners) listener(value);
580
+ }
581
+ writeFireAndForget(value) {
582
+ try {
583
+ this.process?.stdin?.write(`${JSON.stringify(value)}
584
+ `);
585
+ } catch {
586
+ }
587
+ }
588
+ fail(error) {
589
+ if (this.closedError) return;
590
+ this.closedError = error;
591
+ this.rejectPending(error);
592
+ for (const listener of this.closeListeners) listener(error);
593
+ if (this.process && !this.closePromise) {
594
+ this.cleanupTermination = terminateProcess(
595
+ this.process,
596
+ this.options.terminationGraceMs ?? ABORT_GRACE_MS
597
+ );
598
+ }
599
+ }
600
+ rejectPending(error) {
601
+ for (const pending of this.pending.values()) {
602
+ clearTimeout(pending.timer);
603
+ pending.reject(error);
604
+ }
605
+ this.pending.clear();
606
+ }
607
+ };
608
+ var RpcTransport = class {
609
+ constructor(options) {
610
+ this.options = options;
611
+ this.createClient = options.createClient ?? ((clientOptions) => new RpcProtocolClient(clientOptions));
612
+ }
613
+ options;
614
+ kind = "rpc";
615
+ children = /* @__PURE__ */ new Map();
616
+ createClient;
617
+ async runTurn(agent, task, signal, onProgress) {
618
+ const startedAt = Date.now();
619
+ let telemetry = {
620
+ transport: "rpc",
621
+ protocol: PI_SUBAGENTS_RPC_PROTOCOL,
622
+ phase: "starting",
623
+ updatedAt: startedAt,
624
+ timing: { startedAt, transportStartedAt: startedAt }
625
+ };
626
+ const publish = (patch) => {
627
+ telemetry = {
628
+ ...telemetry,
629
+ ...patch,
630
+ timing: { ...telemetry.timing, ...patch.timing },
631
+ usage: patch.usage ? { ...patch.usage } : telemetry.usage,
632
+ updatedAt: Date.now()
633
+ };
634
+ onProgress?.({
635
+ ...telemetry,
636
+ timing: { ...telemetry.timing },
637
+ usage: telemetry.usage ? { ...telemetry.usage } : void 0
638
+ });
639
+ };
640
+ publish({});
641
+ if (signal.aborted) return interruptedRpcOutcome("", telemetry, "starting");
642
+ const settings = this.options.getSettings ? this.options.getSettings() : readSubagentSettings();
643
+ const agentConfig = discoverAgents(agent.cwd, agent.agentScope ?? "user", settings).agents.find(
644
+ (candidate) => candidate.name === agent.agent
645
+ );
646
+ if (!agentConfig) {
647
+ publish({ phase: "failed", failurePhase: "starting" });
648
+ return { output: "", exitCode: 1, error: `Unknown subagent: ${agent.agent}`, telemetry };
649
+ }
650
+ const effectiveAgentConfig = {
651
+ ...agentConfig,
652
+ tools: agent.executionPlan?.effectiveTools ?? agentConfig.tools
653
+ };
654
+ try {
655
+ validateRpcTools(effectiveAgentConfig.tools);
656
+ } catch (error) {
657
+ publish({ phase: "failed", failurePhase: "starting" });
658
+ return { output: "", exitCode: 1, error: boundedError2(error), telemetry };
659
+ }
660
+ let child;
661
+ try {
662
+ child = await this.getOrCreate(agent, effectiveAgentConfig, signal);
663
+ } catch (error) {
664
+ publish({ phase: signal.aborted ? "interrupted" : "failed", failurePhase: "starting" });
665
+ return {
666
+ output: "",
667
+ exitCode: signal.aborted ? 130 : 1,
668
+ aborted: signal.aborted,
669
+ error: boundedError2(error),
670
+ telemetry
671
+ };
672
+ }
673
+ const stateModel = modelIdentity(child.state.model);
674
+ publish({
675
+ phase: "ready",
676
+ provider: stateModel.provider,
677
+ model: stateModel.model,
678
+ thinkingLevel: normalizeThinking(child.state.thinkingLevel),
679
+ timing: { readyAt: Date.now() }
680
+ });
681
+ if (signal.aborted) {
682
+ await this.releaseById(agent.id).catch(() => void 0);
683
+ return interruptedRpcOutcome("", telemetry, "ready");
684
+ }
685
+ const timeoutMs = agent.currentTimeoutMs ?? agent.timeoutMs ?? agentConfig.timeoutMs ?? this.options.defaultTimeoutMs ?? resolveStatefulTurnTimeout(agentConfig);
686
+ const capture = createRpcTurnCapture();
687
+ let resolveBudget;
688
+ let resolvePreAcceptanceIdle;
689
+ const budgetExceeded = new Promise((resolve) => {
690
+ resolveBudget = resolve;
691
+ });
692
+ const preAcceptanceIdleExceeded = new Promise((resolve) => {
693
+ resolvePreAcceptanceIdle = resolve;
694
+ });
695
+ const budgetMonitor = new TurnBudgetMonitor({
696
+ idleTimeoutMs: agent.currentIdleTimeoutMs ?? agent.idleTimeoutMs,
697
+ maxTurns: agent.currentMaxTurns ?? agent.maxTurns,
698
+ maxToolCalls: agent.currentMaxToolCalls ?? agent.maxToolCalls,
699
+ onExceeded(stop) {
700
+ resolveBudget(stop);
701
+ if (stop.reason === "idle_timeout") resolvePreAcceptanceIdle(stop);
702
+ }
703
+ });
704
+ let settledResolve;
705
+ let settledReject;
706
+ const settled = new Promise((resolve, reject) => {
707
+ settledResolve = resolve;
708
+ settledReject = reject;
709
+ });
710
+ void settled.catch(() => void 0);
711
+ const unsubscribeEvent = child.client.onEvent((event) => {
712
+ captureRpcEvent(event, capture);
713
+ observeRpcBudgetEvent(event, budgetMonitor);
714
+ if (!capture.firstActivityAt && isActivityEvent(event)) {
715
+ capture.firstActivityAt = Date.now();
716
+ publish({ phase: "running", timing: { firstActivityAt: capture.firstActivityAt } });
717
+ }
718
+ const type = eventType2(event);
719
+ if (type === "auto_retry_start") publish({ phase: "retrying" });
720
+ if (type === "compaction_start" || type === "summarization_retry_attempt_start") {
721
+ publish({ phase: "compacting" });
722
+ }
723
+ if (type === "agent_settled") settledResolve();
724
+ });
725
+ const unsubscribeClose = child.client.onClose(settledReject);
726
+ const prompt = child.started ? buildCurrentTurnPrompt(agent, task) : buildStatefulTurnPrompt(agent, task).text;
727
+ let accepted = false;
728
+ let preAcceptanceStop;
729
+ const deadline = Date.now() + timeoutMs;
730
+ try {
731
+ await Promise.race([
732
+ raceWithAbort2(
733
+ child.client.prompt(prompt, remainingMs2(deadline)),
734
+ signal,
735
+ "RPC subagent prompt acceptance aborted"
736
+ ),
737
+ preAcceptanceIdleExceeded.then((stop) => {
738
+ preAcceptanceStop = stop;
739
+ throw new Error(formatTurnTerminationMessage(stop.reason, stop.limit, "RPC subagent"));
740
+ })
741
+ ]);
742
+ accepted = true;
743
+ child.started = true;
744
+ publish({ phase: "accepted", timing: { promptAcceptedAt: Date.now() } });
745
+ const settlement = await Promise.race([
746
+ waitForTurnSettlement(settled, signal, remainingMs2(deadline)).then((kind) => ({
747
+ kind
748
+ })),
749
+ budgetExceeded.then((stop) => ({ kind: "limit", stop }))
750
+ ]);
751
+ if (settlement.kind !== "settled") {
752
+ const [, stopped] = await Promise.all([
753
+ child.client.abort().catch(() => void 0),
754
+ settlesWithin2(settled, this.options.abortGraceMs ?? ABORT_GRACE_MS)
755
+ ]);
756
+ const partial = truncateUtf8(capture.output || capture.partial, DEFAULT_MAX_OUTPUT_BYTES);
757
+ const stop = settlement.kind === "limit" ? settlement.stop : { reason: "work_timeout", limit: timeoutMs };
758
+ const explicitAbort = settlement.kind === "aborted" || signal.aborted;
759
+ const termination = explicitAbort ? void 0 : {
760
+ version: TURN_TERMINATION_VERSION,
761
+ reason: stop.reason,
762
+ limit: stop.limit,
763
+ checkpoint: capture.journal.checkpoint(task, partial.text),
764
+ finalization: {
765
+ attempted: false,
766
+ status: "skipped",
767
+ durationMs: 0
768
+ }
769
+ };
770
+ if (explicitAbort || !stopped) {
771
+ if (!stopped) await this.releaseById(agent.id);
772
+ publish({
773
+ phase: explicitAbort ? "interrupted" : "failed",
774
+ failurePhase: "running",
775
+ timing: { settledAt: Date.now() },
776
+ usage: capture.usage
777
+ });
778
+ const checkpointOutput2 = termination ? formatTimeoutCheckpoint(termination.checkpoint) : partial.text;
779
+ return {
780
+ output: partial.text || checkpointOutput2,
781
+ exitCode: explicitAbort ? 130 : 124,
782
+ aborted: explicitAbort,
783
+ truncated: partial.truncated || agent.contextTruncated,
784
+ error: explicitAbort ? "RPC subagent was aborted" : `${formatTurnTerminationMessage(stop.reason, stop.limit, "RPC subagent")}; abort did not settle`,
785
+ policy: rpcPolicy(agentConfig, agent),
786
+ termination,
787
+ telemetry
788
+ };
789
+ }
790
+ publish({ phase: "finalizing", failurePhase: "running" });
791
+ const finalizationStartedAt = Date.now();
792
+ const summary = await finalizeTimedOutRpcTurn({
793
+ client: child.client,
794
+ task,
795
+ partialOutput: partial.text,
796
+ checkpoint: termination?.checkpoint,
797
+ terminationReason: stop.reason,
798
+ resultFormat: agent.resultFormat,
799
+ signal,
800
+ workTimeoutMs: timeoutMs,
801
+ finalizationTimeoutMs: this.options.timeoutFinalizationMs,
802
+ abortGraceMs: this.options.abortGraceMs ?? ABORT_GRACE_MS,
803
+ resetCapture() {
804
+ capture.output = "";
805
+ capture.partial = "";
806
+ capture.stopReason = void 0;
807
+ capture.error = void 0;
808
+ },
809
+ getCapture: () => capture,
810
+ release: () => this.releaseById(agent.id)
811
+ });
812
+ if (termination) {
813
+ termination.finalization = {
814
+ attempted: true,
815
+ status: summary.status,
816
+ durationMs: Date.now() - finalizationStartedAt,
817
+ error: summary.error
818
+ };
819
+ }
820
+ publish({
821
+ phase: "failed",
822
+ failurePhase: "running",
823
+ timing: { settledAt: Date.now() },
824
+ usage: capture.usage
825
+ });
826
+ const checkpointOutput = termination ? formatTimeoutCheckpoint(termination.checkpoint) : "";
827
+ return {
828
+ output: summary.error ? partial.text || checkpointOutput : summary.output,
829
+ exitCode: 124,
830
+ truncated: partial.truncated || summary.truncated || agent.contextTruncated,
831
+ error: [
832
+ formatTurnTerminationMessage(stop.reason, stop.limit, "RPC subagent"),
833
+ summary.error
834
+ ].filter(Boolean).join("; "),
835
+ policy: rpcPolicy(agentConfig, agent),
836
+ termination,
837
+ telemetry
838
+ };
839
+ }
840
+ const output = truncateUtf8(capture.output || capture.partial, DEFAULT_MAX_OUTPUT_BYTES);
841
+ const failed = capture.stopReason === "error" || !output.text.trim();
842
+ publish({
843
+ phase: failed ? "failed" : "settled",
844
+ failurePhase: failed ? "running" : void 0,
845
+ timing: { settledAt: Date.now() },
846
+ provider: capture.provider ?? telemetry.provider,
847
+ model: capture.model ?? telemetry.model,
848
+ usage: capture.usage
849
+ });
850
+ return {
851
+ output: output.text,
852
+ exitCode: failed ? 1 : 0,
853
+ truncated: output.truncated || agent.contextTruncated,
854
+ error: failed ? capture.error || "RPC subagent completed without final text" : void 0,
855
+ policy: rpcPolicy(agentConfig, agent),
856
+ telemetry
857
+ };
858
+ } catch (error) {
859
+ await this.releaseById(agent.id).catch(() => void 0);
860
+ const timedOut = isTimeoutError(error);
861
+ const stop = preAcceptanceStop ?? (timedOut ? { reason: "work_timeout", limit: timeoutMs } : void 0);
862
+ const partial = truncateUtf8(capture.output || capture.partial, DEFAULT_MAX_OUTPUT_BYTES);
863
+ const termination = stop && !signal.aborted ? {
864
+ version: TURN_TERMINATION_VERSION,
865
+ reason: stop.reason,
866
+ limit: stop.limit,
867
+ checkpoint: capture.journal.checkpoint(task, partial.text),
868
+ finalization: {
869
+ attempted: false,
870
+ status: "skipped",
871
+ durationMs: 0
872
+ }
873
+ } : void 0;
874
+ publish({
875
+ phase: signal.aborted ? "interrupted" : "failed",
876
+ failurePhase: accepted ? "running" : "ready",
877
+ timing: { settledAt: Date.now() }
878
+ });
879
+ return {
880
+ output: partial.text || (termination ? formatTimeoutCheckpoint(termination.checkpoint) : ""),
881
+ exitCode: signal.aborted ? 130 : stop ? 124 : 1,
882
+ aborted: signal.aborted,
883
+ error: stop ? formatTurnTerminationMessage(stop.reason, stop.limit, "RPC subagent") : boundedError2(error),
884
+ policy: rpcPolicy(agentConfig, agent),
885
+ termination,
886
+ telemetry
887
+ };
888
+ } finally {
889
+ budgetMonitor.dispose();
890
+ unsubscribeEvent();
891
+ unsubscribeClose();
892
+ }
893
+ }
894
+ async deliverMessage(agent, message) {
895
+ const child = this.children.get(agent.id);
896
+ if (!child) return false;
897
+ await child.client.steer(formatPeerMessage(message));
898
+ return true;
899
+ }
900
+ async release(agent) {
901
+ await this.releaseById(agent.id);
902
+ }
903
+ async shutdown() {
904
+ const results = await Promise.allSettled(
905
+ [...this.children.keys()].map((agentId) => this.releaseById(agentId))
906
+ );
907
+ const failures = results.flatMap(
908
+ (result) => result.status === "rejected" ? [result.reason] : []
909
+ );
910
+ if (failures.length > 0) {
911
+ throw new AggregateError(failures, `Failed to release ${failures.length} RPC subagent(s)`);
912
+ }
913
+ }
914
+ async getOrCreate(agent, agentConfig, signal) {
915
+ const existing = this.children.get(agent.id);
916
+ if (existing) return existing;
917
+ const hasRolePrompt = agentConfig.systemPrompt.trim().length > 0;
918
+ const resources = hasRolePrompt ? await (this.options.resolvePromptResources ?? resolvePiPromptResources)(
919
+ agent.cwd,
920
+ agent.target?.trust.projectTrusted ?? false
921
+ ) : { appendSystemPromptPaths: [] };
922
+ if (signal.aborted) throw abortError2("RPC subagent start aborted");
923
+ const temporaryPrompt = hasRolePrompt ? await writeRolePrompt(agentConfig.name, agentConfig.systemPrompt) : void 0;
924
+ if (signal.aborted) {
925
+ cleanupRolePrompt(temporaryPrompt);
926
+ throw abortError2("RPC subagent start aborted");
927
+ }
928
+ let client;
929
+ try {
930
+ const credentials = this.options.peerRuntime ? await this.options.peerRuntime.issueCredentials(
931
+ agent.id,
932
+ agent.currentTurnGeneration ?? agent.turnGeneration ?? 1
933
+ ) : void 0;
934
+ if (signal.aborted) throw abortError2("RPC subagent start aborted");
935
+ client = this.createClient({
936
+ cwd: agent.cwd,
937
+ abortTimeoutMs: this.options.abortGraceMs ?? ABORT_GRACE_MS,
938
+ terminationGraceMs: this.options.abortGraceMs ?? ABORT_GRACE_MS,
939
+ args: buildRpcArgs(
940
+ agent,
941
+ agentConfig,
942
+ this.options.getParentRuntime(),
943
+ temporaryPrompt?.filePath,
944
+ resources.appendSystemPromptPaths,
945
+ credentials !== void 0
946
+ ),
947
+ env: {
948
+ PI_SUBAGENT_DEPTH: String(
949
+ (Number.parseInt(process.env.PI_SUBAGENT_DEPTH ?? "0", 10) || 0) + 1
950
+ ),
951
+ PI_SUBAGENT_RPC_PROTOCOL: PI_SUBAGENTS_RPC_PROTOCOL,
952
+ ...credentials ? peerBridgeEnvironment(credentials) : {}
953
+ }
954
+ });
955
+ const snapshot = await client.start(signal);
956
+ if (signal.aborted) throw abortError2("RPC subagent start aborted");
957
+ const record = {
958
+ client,
959
+ state: snapshot.state,
960
+ started: false,
961
+ temporaryPrompt
962
+ };
963
+ this.children.set(agent.id, record);
964
+ return record;
965
+ } catch (error) {
966
+ await client?.stop().catch(() => void 0);
967
+ this.options.peerRuntime?.revoke(agent.id);
968
+ cleanupRolePrompt(temporaryPrompt);
969
+ throw error;
970
+ }
971
+ }
972
+ async releaseById(agentId) {
973
+ const child = this.children.get(agentId);
974
+ if (!child) return;
975
+ this.children.delete(agentId);
976
+ this.options.peerRuntime?.revoke(agentId);
977
+ try {
978
+ await child.client.abort().catch(() => void 0);
979
+ await child.client.stop();
980
+ } finally {
981
+ cleanupRolePrompt(child.temporaryPrompt);
982
+ }
983
+ }
984
+ };
985
+ function validateRpcTools(tools) {
986
+ const validated = validateInProcessTools(tools);
987
+ if (validated?.some((tool) => !BUILT_IN_TOOL_NAMES.has(tool))) {
988
+ throw new Error("RPC subagents support only built-in Pi tools in pi-subagents:v1");
989
+ }
990
+ return validated;
991
+ }
992
+ function buildRpcArgs(agent, agentConfig, parentRuntime, rolePromptPath, appendSystemPromptPaths = [], peerBridge = false) {
993
+ const args = ["--mode", "rpc", "--no-session", "--no-extensions"];
994
+ if (peerBridge) args.push("-e", childPeerBridgePath());
995
+ const model = agentConfig.model ?? (parentRuntime.model ? `${parentRuntime.model.provider}/${parentRuntime.model.id}` : void 0);
996
+ if (model) args.push("--model", model);
997
+ const modelSelectsThinking = agentConfig.model ? /:(?:off|minimal|low|medium|high|xhigh|max)$/u.test(agentConfig.model.trim()) : false;
998
+ const thinking = agent.thinkingLevel ?? agentConfig.thinkingLevel ?? (modelSelectsThinking ? void 0 : parentRuntime.thinkingLevel);
999
+ if (thinking) args.push("--thinking", thinking);
1000
+ if (agent.target?.trust.projectTrusted ?? false) args.push("--approve");
1001
+ else args.push("--no-approve");
1002
+ if (Array.isArray(agentConfig.tools)) {
1003
+ const tools = [...agentConfig.tools, ...peerBridge ? CHILD_PEER_TOOL_NAMES : []];
1004
+ if (tools.length > 0) args.push("--tools", [...new Set(tools)].join(","));
1005
+ else args.push("--no-tools");
1006
+ }
1007
+ for (const promptPath of appendSystemPromptPaths) {
1008
+ args.push("--append-system-prompt", promptPath);
1009
+ }
1010
+ if (rolePromptPath) args.push("--append-system-prompt", rolePromptPath);
1011
+ return args;
1012
+ }
1013
+ function eventType2(value) {
1014
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1015
+ const type = value.type;
1016
+ return typeof type === "string" ? type : void 0;
1017
+ }
1018
+ function isActivityEvent(value) {
1019
+ return [
1020
+ "message_start",
1021
+ "message_update",
1022
+ "message_end",
1023
+ "tool_execution_start",
1024
+ "tool_execution_update",
1025
+ "auto_retry_start",
1026
+ "compaction_start"
1027
+ ].includes(eventType2(value) ?? "");
1028
+ }
1029
+ async function writeRolePrompt(agentName, prompt) {
1030
+ const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "pi-subagent-rpc-"));
1031
+ const safeName = agentName.replace(/[^\w.-]+/gu, "_");
1032
+ const filePath = path.join(dir, `prompt-${safeName}.md`);
1033
+ await fs.promises.writeFile(filePath, prompt, {
1034
+ encoding: "utf8",
1035
+ mode: 384
1036
+ });
1037
+ return { dir, filePath };
1038
+ }
1039
+ function cleanupRolePrompt(value) {
1040
+ if (!value) return;
1041
+ try {
1042
+ fs.rmSync(value.dir, { recursive: true, force: true });
1043
+ } catch {
1044
+ }
1045
+ }
1046
+ function waitForSpawn(proc, signal, timeoutMs) {
1047
+ return new Promise((resolve, reject) => {
1048
+ let settled = false;
1049
+ const finish = (error) => {
1050
+ if (settled) return;
1051
+ settled = true;
1052
+ clearTimeout(timer);
1053
+ proc.off("spawn", onSpawn);
1054
+ proc.off("error", onError);
1055
+ signal?.removeEventListener("abort", onAbort);
1056
+ if (error) reject(error);
1057
+ else resolve();
1058
+ };
1059
+ const onSpawn = () => finish();
1060
+ const onError = (error) => finish(error);
1061
+ const onAbort = () => finish(abortError2("RPC subagent start aborted"));
1062
+ const timer = setTimeout(
1063
+ () => finish(new Error(`RPC subagent start timed out after ${timeoutMs}ms`)),
1064
+ timeoutMs
1065
+ );
1066
+ timer.unref();
1067
+ proc.once("spawn", onSpawn);
1068
+ proc.once("error", onError);
1069
+ signal?.addEventListener("abort", onAbort, { once: true });
1070
+ if (signal?.aborted) onAbort();
1071
+ });
1072
+ }
1073
+ async function raceWithAbort2(promise, signal, message) {
1074
+ if (!signal) return promise;
1075
+ if (signal.aborted) throw abortError2(message);
1076
+ let onAbort;
1077
+ try {
1078
+ return await Promise.race([
1079
+ promise,
1080
+ new Promise((_resolve, reject) => {
1081
+ onAbort = () => reject(abortError2(message));
1082
+ signal.addEventListener("abort", onAbort, { once: true });
1083
+ if (signal.aborted) onAbort();
1084
+ })
1085
+ ]);
1086
+ } finally {
1087
+ if (onAbort) signal.removeEventListener("abort", onAbort);
1088
+ }
1089
+ }
1090
+ function waitForTurnSettlement(settled, signal, timeoutMs) {
1091
+ if (signal.aborted) return Promise.resolve("aborted");
1092
+ return new Promise((resolve, reject) => {
1093
+ let finished = false;
1094
+ const finish = (value, error) => {
1095
+ if (finished) return;
1096
+ finished = true;
1097
+ clearTimeout(timer);
1098
+ signal.removeEventListener("abort", onAbort);
1099
+ if (error) reject(error);
1100
+ else resolve(value);
1101
+ };
1102
+ const onAbort = () => finish("aborted");
1103
+ const timer = setTimeout(() => finish("timeout"), timeoutMs);
1104
+ timer.unref();
1105
+ signal.addEventListener("abort", onAbort, { once: true });
1106
+ if (signal.aborted) onAbort();
1107
+ settled.then(
1108
+ () => finish("settled"),
1109
+ (error) => finish("settled", error)
1110
+ );
1111
+ });
1112
+ }
1113
+ async function settlesWithin2(settled, timeoutMs) {
1114
+ let timer;
1115
+ try {
1116
+ return await Promise.race([
1117
+ settled.then(
1118
+ () => true,
1119
+ () => true
1120
+ ),
1121
+ new Promise((resolve) => {
1122
+ timer = setTimeout(() => resolve(false), timeoutMs);
1123
+ })
1124
+ ]);
1125
+ } finally {
1126
+ if (timer) clearTimeout(timer);
1127
+ }
1128
+ }
1129
+ function remainingMs2(deadline) {
1130
+ return Math.max(1, deadline - Date.now());
1131
+ }
1132
+ function rpcTimeoutError(message) {
1133
+ const error = new Error(message);
1134
+ error.name = "RpcTimeoutError";
1135
+ return error;
1136
+ }
1137
+ function isTimeoutError(error) {
1138
+ return error instanceof Error && error.name === "RpcTimeoutError";
1139
+ }
1140
+ function abortError2(message) {
1141
+ const error = new Error(message);
1142
+ error.name = "AbortError";
1143
+ return error;
1144
+ }
1145
+ function errorMessage(prefix, error) {
1146
+ return new Error(`${prefix}: ${error.message}`);
1147
+ }
1148
+ export {
1149
+ RpcProtocolClient,
1150
+ RpcTransport,
1151
+ buildRpcArgs,
1152
+ validateRpcTools
1153
+ };
1154
+ //# sourceMappingURL=rpc-transport-Y6LA5BOP.ts.map