@agimon-ai/po-team 0.0.0-alpha.30 → 0.0.0-alpha.32

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.
@@ -32,14 +32,233 @@ let _agimon_ai_po_core_contextContributions = require("@agimon-ai/po-core/contex
32
32
  let _agimon_ai_po_core_mcpToolResolver = require("@agimon-ai/po-core/mcpToolResolver");
33
33
  let _agimon_ai_po_core_telemetry = require("@agimon-ai/po-core/telemetry");
34
34
  let _agimon_ai_po_session = require("@agimon-ai/po-session");
35
- let typebox_value = require("typebox/value");
36
35
  let node_crypto = require("node:crypto");
36
+ let typebox_value = require("typebox/value");
37
37
  let node_child_process = require("node:child_process");
38
38
  let node_url = require("node:url");
39
39
  let _agimon_ai_po_core_headless = require("@agimon-ai/po-core/headless");
40
40
  let _agimon_ai_po_config_majorModes = require("@agimon-ai/po-config/majorModes");
41
41
  require("@agimon-ai/po-core/cordisHost");
42
42
  let _agimon_ai_po_core_hubChannel = require("@agimon-ai/po-core/hubChannel");
43
+ //#region src/constants/awaitedInlineRun.ts
44
+ const AWAITED_INLINE_CHILD_GUIDANCE = "You are an inline agent owned by the parent workflow step. Write the requested artifacts and evidence. Never record workflow complete, fix, or fail decisions. Do not launch or delegate agents. The parent owns all step decisions and bookkeeping.";
45
+ //#endregion
46
+ //#region src/services/modelInfo/index.ts
47
+ /**
48
+ * Model identity and thinking-level resolution.
49
+ *
50
+ * DESIGN PATTERNS:
51
+ * - A model string may carry a thinking level as a `:level` suffix. Only suffixes
52
+ * in THINKING_LEVELS are recognised, so a model id that legitimately contains a
53
+ * colon (`openrouter/vendor:free`) is never mistaken for a thinking request
54
+ * - `max` is excluded from the default supported set because a model only offers
55
+ * it when its thinkingLevelMap says so explicitly
56
+ *
57
+ * AVOID:
58
+ * - Splitting a model string on the first colon; the suffix is at the end
59
+ * - Assuming a missing thinkingLevelMap means "no thinking"; it means "unknown",
60
+ * which is treated as the standard set
61
+ */
62
+ const THINKING_LEVELS = [
63
+ "off",
64
+ "minimal",
65
+ "low",
66
+ "medium",
67
+ "high",
68
+ "xhigh",
69
+ "max"
70
+ ];
71
+ const THINKING_SUFFIX_SEPARATOR = ":";
72
+ const PROVIDER_SEPARATOR$1 = "/";
73
+ function toModelInfo(model) {
74
+ return {
75
+ provider: model.provider,
76
+ id: model.id,
77
+ fullId: `${model.provider}${PROVIDER_SEPARATOR$1}${model.id}`,
78
+ api: model.api,
79
+ reasoning: model.reasoning,
80
+ thinkingLevelMap: model.thinkingLevelMap
81
+ };
82
+ }
83
+ /** The parent's authenticated models as the host lists them now; only the parent model when it cannot list. */
84
+ async function availableModelInfos(execution) {
85
+ const models = await execution.getAvailableModels?.();
86
+ if (models) return models.map(toModelInfo);
87
+ return execution.model ? [toModelInfo(execution.model)] : [];
88
+ }
89
+ function splitKnownThinkingSuffix(model) {
90
+ const colonIdx = model.lastIndexOf(THINKING_SUFFIX_SEPARATOR);
91
+ if (colonIdx === -1) return {
92
+ baseModel: model,
93
+ thinkingSuffix: ""
94
+ };
95
+ const suffix = THINKING_LEVELS.find((level) => level === model.substring(colonIdx + 1));
96
+ if (!suffix) return {
97
+ baseModel: model,
98
+ thinkingSuffix: ""
99
+ };
100
+ return {
101
+ baseModel: model.substring(0, colonIdx),
102
+ thinkingSuffix: `${THINKING_SUFFIX_SEPARATOR}${suffix}`
103
+ };
104
+ }
105
+ function findModelInfo(model, availableModels, preferredProvider) {
106
+ if (!model || !availableModels || availableModels.length === 0) return void 0;
107
+ const { baseModel } = splitKnownThinkingSuffix(model);
108
+ const exact = availableModels.find((entry) => entry.fullId === baseModel);
109
+ if (exact) return exact;
110
+ const matches = availableModels.filter((entry) => entry.id === baseModel);
111
+ if (preferredProvider) {
112
+ const preferred = matches.find((entry) => entry.provider === preferredProvider);
113
+ if (preferred) return preferred;
114
+ }
115
+ return matches.length === 1 ? matches[0] : void 0;
116
+ }
117
+ function getSupportedThinkingLevels(model) {
118
+ if (!model) return THINKING_LEVELS.filter((level) => level !== "max");
119
+ if (model.reasoning === false) return ["off"];
120
+ if (!model.thinkingLevelMap) return THINKING_LEVELS.filter((level) => level !== "max");
121
+ return THINKING_LEVELS.filter((level) => {
122
+ const mapped = model.thinkingLevelMap?.[level];
123
+ if (mapped === null) return false;
124
+ if (level === "xhigh" || level === "max") return mapped !== void 0;
125
+ return true;
126
+ });
127
+ }
128
+ //#endregion
129
+ //#region src/services/awaitedInlineRun/index.ts
130
+ const DEFAULT_TIMEOUT_MS$2 = 18e5;
131
+ const MAX_TIMEOUT_MS = 72e5;
132
+ function validate(input) {
133
+ if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("team.run requires an object.");
134
+ const value = input;
135
+ for (const key of ["systemPrompt", "task"]) if (typeof value[key] !== "string" || !value[key].trim()) throw new Error(`team.run requires a nonblank ${key}.`);
136
+ if (value.model !== void 0 && (typeof value.model !== "string" || !value.model.trim())) throw new Error("team.run model must be a nonblank string.");
137
+ if (value.timeoutMs !== void 0 && (typeof value.timeoutMs !== "number" || !Number.isSafeInteger(value.timeoutMs) || value.timeoutMs <= 0 || value.timeoutMs > MAX_TIMEOUT_MS)) throw new Error(`team.run timeoutMs must be an integer from 1 to ${MAX_TIMEOUT_MS}.`);
138
+ return {
139
+ systemPrompt: value.systemPrompt.trim(),
140
+ task: value.task.trim(),
141
+ ...typeof value.model === "string" ? { model: value.model.trim() } : {},
142
+ ...typeof value.timeoutMs === "number" ? { timeoutMs: value.timeoutMs } : {}
143
+ };
144
+ }
145
+ /** Session-owned adapter over the existing planner and coordinator, with no child completion messages. */
146
+ function createAwaitedInlineRunner(options) {
147
+ const lifetime = new AbortController();
148
+ const active = /* @__PURE__ */ new Set();
149
+ const execute = async (input, parentSignal) => {
150
+ let runId;
151
+ const notify = (status) => {
152
+ if (!runId) return;
153
+ try {
154
+ options.emit?.({
155
+ sessionId: options.execution.sessionId,
156
+ runId,
157
+ status
158
+ });
159
+ } catch {}
160
+ };
161
+ const finish = (result) => {
162
+ notify(result.status);
163
+ return result;
164
+ };
165
+ let waiter;
166
+ let timer;
167
+ let removeAbort;
168
+ let signal;
169
+ try {
170
+ const params = validate(input);
171
+ const deadline = new AbortController();
172
+ timer = setTimeout(() => deadline.abort(/* @__PURE__ */ new Error(`Inline agent timed out after ${params.timeoutMs ?? DEFAULT_TIMEOUT_MS$2}ms.`)), params.timeoutMs ?? DEFAULT_TIMEOUT_MS$2);
173
+ timer.unref?.();
174
+ signal = AbortSignal.any([
175
+ parentSignal,
176
+ lifetime.signal,
177
+ deadline.signal
178
+ ]);
179
+ signal.throwIfAborted();
180
+ const execution = options.execution;
181
+ const models = await availableModelInfos(execution);
182
+ signal.throwIfAborted();
183
+ runId = crypto.randomUUID();
184
+ notify("running");
185
+ waiter = options.coordinator.waitFor(execution.sessionId, runId);
186
+ const outcome = (await options.planner.spawn({
187
+ single: {
188
+ agent: "inline",
189
+ inlineAgent: { systemPrompt: `${params.systemPrompt}\n\n${AWAITED_INLINE_CHILD_GUIDANCE}` },
190
+ task: params.task,
191
+ ...params.model ? { model: params.model } : {}
192
+ },
193
+ cwd: execution.cwd,
194
+ agentScope: "both",
195
+ sessionScope: require_atomicJson.createSessionScope(execution.sessionId),
196
+ environment: execution.environment,
197
+ parentSessionId: execution.sessionId,
198
+ parentSelection: execution.selection,
199
+ ...execution.model ? { parentModel: execution.model } : {},
200
+ availableModels: models,
201
+ preallocatedRunIds: [runId],
202
+ awaitedInline: true,
203
+ signal
204
+ }, options.config)).outcomes[0];
205
+ if (!outcome?.runId) throw new Error(outcome?.error ?? "The inline agent did not start.");
206
+ const aborted = new Promise((resolve) => {
207
+ const abort = () => resolve(void 0);
208
+ signal.addEventListener("abort", abort, { once: true });
209
+ removeAbort = () => signal.removeEventListener("abort", abort);
210
+ if (signal.aborted) abort();
211
+ });
212
+ const completion = await Promise.race([waiter.result, aborted]);
213
+ if (completion) return finish(completion);
214
+ const reason = signal.reason instanceof Error ? signal.reason.message : "The inline agent was cancelled.";
215
+ const child = options.coordinator.get(execution.sessionId, runId);
216
+ if (child) await child.stop(reason);
217
+ const stopped = await waiter.result;
218
+ return finish(stopped.status === "failed" ? stopped : {
219
+ ...stopped,
220
+ status: "stopped",
221
+ error: reason
222
+ });
223
+ } catch (error) {
224
+ let cleanupError;
225
+ if (runId) {
226
+ const child = options.coordinator.get(options.execution.sessionId, runId);
227
+ if (child) try {
228
+ await child.stop("The owning inline run failed or was cancelled.");
229
+ } catch (stopError) {
230
+ cleanupError = stopError;
231
+ }
232
+ const status = options.coordinator.status(options.execution.sessionId, runId)?.status;
233
+ if (status === "completed" || status === "failed" || status === "stopped") await waiter?.result;
234
+ }
235
+ const failure = cleanupError ?? error;
236
+ return finish({
237
+ ...runId ? { runId } : {},
238
+ status: cleanupError ? "failed" : signal?.aborted ? "stopped" : "failed",
239
+ output: "",
240
+ error: failure instanceof Error ? failure.message : String(failure)
241
+ });
242
+ } finally {
243
+ clearTimeout(timer);
244
+ removeAbort?.();
245
+ waiter?.dispose();
246
+ }
247
+ };
248
+ return {
249
+ run(input, signal) {
250
+ const pending = execute(input, signal);
251
+ active.add(pending);
252
+ pending.finally(() => active.delete(pending));
253
+ return pending;
254
+ },
255
+ async close() {
256
+ lifetime.abort(/* @__PURE__ */ new Error("The owning Team session is shutting down."));
257
+ await Promise.all(active);
258
+ }
259
+ };
260
+ }
261
+ //#endregion
43
262
  //#region src/services/config/index.ts
44
263
  /**
45
264
  * `subagent` tool config file: read/write, and the scoped `ExtensionConfig`
@@ -81,8 +300,8 @@ const ARTIFACT_DIR_PREFERENCES = /* @__PURE__ */ new Set([
81
300
  "session",
82
301
  "temp"
83
302
  ]);
84
- function getConfigPath() {
85
- return node_path.join(require_agentDiscovery.getAgentDir(), "extensions", "subagent", "config.json");
303
+ function getConfigPath(environment) {
304
+ return node_path.join(require_agentDiscovery.getAgentDir(environment), "extensions", "subagent", "config.json");
86
305
  }
87
306
  function readConfigForUpdate(configPath = getConfigPath()) {
88
307
  if (!node_fs.existsSync(configPath)) return {};
@@ -124,8 +343,8 @@ function configStamp(configPath) {
124
343
  }
125
344
  }
126
345
  /** Never throws. A malformed config degrades to defaults, reported via `loadError` rather than `console.*`. */
127
- function loadConfig() {
128
- const configPath = getConfigPath();
346
+ function loadConfig(environment) {
347
+ const configPath = getConfigPath(environment);
129
348
  const stamp = configStamp(configPath);
130
349
  if (configCache?.path === configPath && configCache.stamp === stamp) return configCache.loaded;
131
350
  let loaded;
@@ -167,14 +386,28 @@ var AdmissionGate = class {
167
386
  admit(request) {
168
387
  const admission = this.queue.then(() => this.waitForSlot(request), () => this.waitForSlot(request));
169
388
  this.queue = admission.then(() => void 0, () => void 0);
170
- return admission;
389
+ const signal = request.signal;
390
+ if (!signal) return admission;
391
+ return new Promise((resolve, reject) => {
392
+ const abort = () => reject(signal.reason ?? /* @__PURE__ */ new Error("Child admission was aborted."));
393
+ signal.addEventListener("abort", abort, { once: true });
394
+ if (signal.aborted) abort();
395
+ admission.then((ticket) => {
396
+ if (signal.aborted) {
397
+ ticket.release();
398
+ abort();
399
+ } else resolve(ticket);
400
+ }, reject).finally(() => signal.removeEventListener("abort", abort));
401
+ });
171
402
  }
172
403
  async waitForSlot(request) {
173
404
  const deadline = this.now() + request.timeoutMs;
174
405
  const waitStartedAt = this.now();
175
406
  let waited = false;
176
407
  for (;;) {
408
+ request.signal?.throwIfAborted();
177
409
  const live = await this.countLiveRuns(request.sessionScope) + this.reserved;
410
+ request.signal?.throwIfAborted();
178
411
  if (live < request.maxLiveRuns) {
179
412
  this.reserved += 1;
180
413
  return this.ticket();
@@ -1070,89 +1303,6 @@ function invalidRequest(message, recovery) {
1070
1303
  return new PoTeamExpectedError("invalid_request", message, false, recovery);
1071
1304
  }
1072
1305
  //#endregion
1073
- //#region src/services/modelInfo/index.ts
1074
- /**
1075
- * Model identity and thinking-level resolution.
1076
- *
1077
- * DESIGN PATTERNS:
1078
- * - A model string may carry a thinking level as a `:level` suffix. Only suffixes
1079
- * in THINKING_LEVELS are recognised, so a model id that legitimately contains a
1080
- * colon (`openrouter/vendor:free`) is never mistaken for a thinking request
1081
- * - `max` is excluded from the default supported set because a model only offers
1082
- * it when its thinkingLevelMap says so explicitly
1083
- *
1084
- * AVOID:
1085
- * - Splitting a model string on the first colon; the suffix is at the end
1086
- * - Assuming a missing thinkingLevelMap means "no thinking"; it means "unknown",
1087
- * which is treated as the standard set
1088
- */
1089
- const THINKING_LEVELS = [
1090
- "off",
1091
- "minimal",
1092
- "low",
1093
- "medium",
1094
- "high",
1095
- "xhigh",
1096
- "max"
1097
- ];
1098
- const THINKING_SUFFIX_SEPARATOR = ":";
1099
- const PROVIDER_SEPARATOR$1 = "/";
1100
- function toModelInfo(model) {
1101
- return {
1102
- provider: model.provider,
1103
- id: model.id,
1104
- fullId: `${model.provider}${PROVIDER_SEPARATOR$1}${model.id}`,
1105
- api: model.api,
1106
- reasoning: model.reasoning,
1107
- thinkingLevelMap: model.thinkingLevelMap
1108
- };
1109
- }
1110
- /** The parent's authenticated models as the host lists them now; only the parent model when it cannot list. */
1111
- async function availableModelInfos(execution) {
1112
- const models = await execution.getAvailableModels?.();
1113
- if (models) return models.map(toModelInfo);
1114
- return execution.model ? [toModelInfo(execution.model)] : [];
1115
- }
1116
- function splitKnownThinkingSuffix(model) {
1117
- const colonIdx = model.lastIndexOf(THINKING_SUFFIX_SEPARATOR);
1118
- if (colonIdx === -1) return {
1119
- baseModel: model,
1120
- thinkingSuffix: ""
1121
- };
1122
- const suffix = THINKING_LEVELS.find((level) => level === model.substring(colonIdx + 1));
1123
- if (!suffix) return {
1124
- baseModel: model,
1125
- thinkingSuffix: ""
1126
- };
1127
- return {
1128
- baseModel: model.substring(0, colonIdx),
1129
- thinkingSuffix: `${THINKING_SUFFIX_SEPARATOR}${suffix}`
1130
- };
1131
- }
1132
- function findModelInfo(model, availableModels, preferredProvider) {
1133
- if (!model || !availableModels || availableModels.length === 0) return void 0;
1134
- const { baseModel } = splitKnownThinkingSuffix(model);
1135
- const exact = availableModels.find((entry) => entry.fullId === baseModel);
1136
- if (exact) return exact;
1137
- const matches = availableModels.filter((entry) => entry.id === baseModel);
1138
- if (preferredProvider) {
1139
- const preferred = matches.find((entry) => entry.provider === preferredProvider);
1140
- if (preferred) return preferred;
1141
- }
1142
- return matches.length === 1 ? matches[0] : void 0;
1143
- }
1144
- function getSupportedThinkingLevels(model) {
1145
- if (!model) return THINKING_LEVELS.filter((level) => level !== "max");
1146
- if (model.reasoning === false) return ["off"];
1147
- if (!model.thinkingLevelMap) return THINKING_LEVELS.filter((level) => level !== "max");
1148
- return THINKING_LEVELS.filter((level) => {
1149
- const mapped = model.thinkingLevelMap?.[level];
1150
- if (mapped === null) return false;
1151
- if (level === "xhigh" || level === "max") return mapped !== void 0;
1152
- return true;
1153
- });
1154
- }
1155
- //#endregion
1156
1306
  //#region src/services/modelResolution/index.ts
1157
1307
  /**
1158
1308
  * Resolving a loosely-spelled model name to a canonical `provider/id`.
@@ -1424,6 +1574,8 @@ function storedRunIdentity(run) {
1424
1574
  return {
1425
1575
  identity: meta.identity,
1426
1576
  inline: meta.inline === true,
1577
+ ...meta.awaited === true ? { awaited: true } : {},
1578
+ ...meta.delivery === "silent" ? { delivery: "silent" } : {},
1427
1579
  ...typeof meta.agentDescription === "string" ? { agentDescription: meta.agentDescription } : {},
1428
1580
  ...typeof meta.agentFilePath === "string" ? { agentFilePath: meta.agentFilePath } : {}
1429
1581
  };
@@ -1434,6 +1586,8 @@ var NativeRunCoordinator = class {
1434
1586
  notifier;
1435
1587
  projection;
1436
1588
  entries = /* @__PURE__ */ new Map();
1589
+ waiters = /* @__PURE__ */ new Map();
1590
+ handoffs = /* @__PURE__ */ new Set();
1437
1591
  closed = false;
1438
1592
  closing;
1439
1593
  constructor(childSessions, tracker, notifier, projection) {
@@ -1448,26 +1602,55 @@ var NativeRunCoordinator = class {
1448
1602
  if (!service) throw new Error("The in-process Pi child-session service is unavailable.");
1449
1603
  return service;
1450
1604
  }
1451
- async start(sessionId, request, identity) {
1605
+ async start(sessionId, request, identity, signal) {
1606
+ signal?.throwIfAborted();
1452
1607
  if (!sessionId.trim()) throw new Error("Native child runs require a session identity.");
1453
- const handle = await this.service().start({
1608
+ const childRequest = {
1454
1609
  ...request,
1455
1610
  ...identity ? { meta: {
1456
1611
  ...request.meta,
1457
1612
  ...JSON.parse(JSON.stringify(identity))
1458
1613
  } } : {}
1459
- });
1614
+ };
1615
+ const service = this.service();
1616
+ const handle = await (signal ? service.start(childRequest, signal) : service.start(childRequest));
1460
1617
  return this.adopt(sessionId, request.scope, request, handle, identity);
1461
1618
  }
1462
1619
  async restore(sessionId, run, intercom) {
1463
1620
  const service = this.service();
1621
+ if (storedRunIdentity(run)?.awaited) {
1622
+ if (!service.abandon) throw new Error("This child-session service cannot abandon orphaned awaited runs.");
1623
+ await service.abandon(run.request.runId);
1624
+ const message = "Interrupted: the owning code-mode continuation did not survive the session restart.";
1625
+ const projection = {
1626
+ runId: run.request.runId,
1627
+ agent: run.request.agent,
1628
+ identity: storedRunIdentity(run)?.identity,
1629
+ inline: true,
1630
+ task: run.request.task,
1631
+ cwd: run.request.cwd,
1632
+ runtime: "pi",
1633
+ status: "stopped",
1634
+ startedAt: Date.now(),
1635
+ updatedAt: Date.now(),
1636
+ summary: message,
1637
+ error: message
1638
+ };
1639
+ this.tracker.upsertNative(sessionId, run.request.scope, projection);
1640
+ this.projection?.publish(sessionId, projection);
1641
+ this.tracker.acknowledgeHandoff(sessionId, run.request.runId);
1642
+ return;
1643
+ }
1464
1644
  if (!service.restore) throw new Error("This child-session service cannot restore runs.");
1465
1645
  const handle = await service.restore(run.request.runId, intercom ? { intercom } : void 0);
1466
1646
  return this.adopt(sessionId, run.request.scope, run.request, handle, storedRunIdentity(run));
1467
1647
  }
1468
1648
  async adopt(sessionId, scope, request, handle, identity) {
1469
1649
  if (this.closed) {
1470
- await handle.dispose();
1650
+ if (identity?.awaited) {
1651
+ await handle.stop("The owning Team session closed during child startup.");
1652
+ await this.childSessions?.get()?.markReported?.(request.runId);
1653
+ } else await handle.dispose();
1471
1654
  throw new Error("The native Team run coordinator closed during child startup.");
1472
1655
  }
1473
1656
  const entry = {
@@ -1491,6 +1674,16 @@ var NativeRunCoordinator = class {
1491
1674
  throw error;
1492
1675
  }
1493
1676
  }
1677
+ /** Register before launch, so even a synchronously completed child cannot race the waiter. */
1678
+ waitFor(sessionId, runId) {
1679
+ if (this.closed) throw new Error("The native Team run coordinator is closed.");
1680
+ const key = entryKey(sessionId, runId);
1681
+ if (this.waiters.has(key)) throw new Error(`Native run '${runId}' already has a completion waiter.`);
1682
+ return {
1683
+ result: new Promise((resolve) => this.waiters.set(key, resolve)),
1684
+ dispose: () => this.waiters.delete(key)
1685
+ };
1686
+ }
1494
1687
  get(sessionId, runId) {
1495
1688
  return this.entries.get(entryKey(sessionId, runId))?.handle;
1496
1689
  }
@@ -1529,10 +1722,16 @@ var NativeRunCoordinator = class {
1529
1722
  this.closing ??= (async () => {
1530
1723
  const active = [...this.entries.values()];
1531
1724
  for (const entry of active) {
1725
+ if (entry.identity?.awaited) continue;
1532
1726
  entry.unsubscribe?.();
1533
1727
  this.entries.delete(entryKey(entry.sessionId, entry.request.runId));
1534
1728
  }
1535
- const failures = (await Promise.allSettled(active.map((entry) => entry.handle.dispose()))).filter((outcome) => outcome.status === "rejected").map((outcome) => outcome.reason);
1729
+ const outcomes = await Promise.allSettled(active.map(async (entry) => {
1730
+ if (entry.identity?.awaited) await entry.handle.stop("The owning Team session is shutting down.");
1731
+ else await entry.handle.dispose();
1732
+ }));
1733
+ await Promise.all(this.handoffs);
1734
+ const failures = outcomes.filter((outcome) => outcome.status === "rejected").map((outcome) => outcome.reason);
1536
1735
  if (failures.length) throw new AggregateError(failures, "Native Team run shutdown failed.");
1537
1736
  })();
1538
1737
  return this.closing;
@@ -1587,6 +1786,33 @@ var NativeRunCoordinator = class {
1587
1786
  durationMs: Math.max(0, event.timestamp - (this.tracker.getNative(entry.sessionId, entry.request.runId)?.startedAt ?? event.timestamp)),
1588
1787
  sessionId: entry.sessionId
1589
1788
  };
1789
+ if (entry.identity?.delivery === "silent" || entry.identity?.awaited) {
1790
+ const key = entryKey(entry.sessionId, entry.request.runId);
1791
+ const finish = async () => {
1792
+ let completion = {
1793
+ runId: entry.request.runId,
1794
+ status,
1795
+ output: status === "completed" ? event.message ?? "" : "",
1796
+ ...status === "completed" ? {} : { error: event.message ?? `Native child run ${status}.` }
1797
+ };
1798
+ try {
1799
+ await this.childSessions?.get()?.markReported?.(entry.request.runId);
1800
+ this.tracker.acknowledgeHandoff(entry.sessionId, entry.request.runId);
1801
+ } catch (error) {
1802
+ completion = {
1803
+ ...completion,
1804
+ status: "failed",
1805
+ error: `Could not acknowledge child completion: ${error instanceof Error ? error.message : String(error)}`
1806
+ };
1807
+ }
1808
+ this.waiters.get(key)?.(completion);
1809
+ this.waiters.delete(key);
1810
+ };
1811
+ const handoff = finish();
1812
+ this.handoffs.add(handoff);
1813
+ handoff.finally(() => this.handoffs.delete(handoff));
1814
+ return;
1815
+ }
1590
1816
  if (this.notifier) this.notifier.deliver(result).then(async (delivered) => {
1591
1817
  if (!delivered) return;
1592
1818
  this.tracker.acknowledgeHandoff(entry.sessionId, entry.request.runId);
@@ -2051,15 +2277,15 @@ var SpawnPlanner = class {
2051
2277
  if (!resolved) throw new PoTeamExpectedError(ERROR_CODE_AGENT_NOT_FOUND, `Unknown agent '${name}'.`, false, "Call subagent({\"action\":\"agents\"}) and retry with an exact name.");
2052
2278
  return resolved;
2053
2279
  }
2054
- async resolveExecutableAgent(taskInput, cwd, scope) {
2280
+ async resolveExecutableAgent(taskInput, cwd, scope, inheritParent = false) {
2055
2281
  if (!taskInput.inlineAgent) return this.resolveAgentOrThrow(taskInput.agent, cwd, scope);
2056
2282
  return {
2057
2283
  name: taskInput.agent.trim(),
2058
2284
  systemPromptMode: "append",
2059
2285
  inheritProjectContext: true,
2060
- inheritSkills: false,
2286
+ inheritSkills: inheritParent,
2061
2287
  systemPrompt: taskInput.inlineAgent.systemPrompt.trim(),
2062
- tools: [...INLINE_AGENT_TOOLS],
2288
+ ...inheritParent ? {} : { tools: [...INLINE_AGENT_TOOLS] },
2063
2289
  defaultContext: CONTEXT_FRESH,
2064
2290
  runtime: "pi"
2065
2291
  };
@@ -2145,7 +2371,7 @@ var SpawnPlanner = class {
2145
2371
  * the module header.
2146
2372
  */
2147
2373
  async spawnOneChild(input) {
2148
- const { runId, operationId, agentConfig, identity, capabilityCeiling, excludeTools, teamPackageModels, teamThinking, workflowPreferences, planningPreferences, taskInput, childIndex, fanout, fallbackCwd, parentSessionId, parentForkSource, sessionScope, environment, parentSessionFile, maxLiveRuns, admissionTimeoutMs, handshakeTimeoutMs, artifacts, artifactDir, availableModels, parentModel, runtime, runtimes, skillProjectionCache, sender } = input;
2374
+ const { runId, awaitedInline, silent, signal, operationId, agentConfig, identity, capabilityCeiling, excludeTools, teamPackageModels, teamThinking, workflowPreferences, planningPreferences, taskInput, childIndex, fanout, fallbackCwd, parentSessionId, parentForkSource, sessionScope, environment, parentSessionFile, maxLiveRuns, admissionTimeoutMs, handshakeTimeoutMs, artifacts, artifactDir, availableModels, parentModel, runtime, runtimes, skillProjectionCache, sender } = input;
2149
2375
  const cwd = taskInput.cwd ?? fallbackCwd;
2150
2376
  const task = taskInput.task ?? "";
2151
2377
  const effectiveContext = resolveEffectiveContext(taskInput, agentConfig);
@@ -2199,7 +2425,8 @@ var SpawnPlanner = class {
2199
2425
  ...artifacts !== void 0 ? { artifacts } : {},
2200
2426
  ...artifactDir !== void 0 ? { artifactDir } : {},
2201
2427
  runtime: effectiveRuntime,
2202
- runtimes
2428
+ runtimes,
2429
+ ...silent ? { internal: true } : {}
2203
2430
  };
2204
2431
  const admission = this.admission;
2205
2432
  if (!admission) throw new Error("Po Team spawn admission is not configured.");
@@ -2209,6 +2436,7 @@ var SpawnPlanner = class {
2209
2436
  sessionScope,
2210
2437
  maxLiveRuns,
2211
2438
  timeoutMs: admissionTimeoutMs,
2439
+ ...signal ? { signal } : {},
2212
2440
  ...this.reportConcurrencyEvent ? { report: this.reportConcurrencyEvent } : {}
2213
2441
  });
2214
2442
  } catch (error) {
@@ -2221,13 +2449,14 @@ var SpawnPlanner = class {
2221
2449
  };
2222
2450
  }
2223
2451
  try {
2452
+ signal?.throwIfAborted();
2224
2453
  if (isPiRuntime(effectiveRuntime)) {
2225
2454
  if (!this.nativeRuns || !this.childSessions?.get()) throw new Error("The native Team run coordinator is unavailable.");
2226
2455
  const scope = sessionScope;
2227
2456
  const source = effectiveContext === CONTEXT_FORK ? parentForkSource ?? (() => {
2228
2457
  throw new Error("Native fork input requires the parent session's branch.");
2229
2458
  })() : { kind: "fresh" };
2230
- const intercom = this.teamChannel?.createNativeChildIntercom({
2459
+ const intercom = awaitedInline ? void 0 : this.teamChannel?.createNativeChildIntercom({
2231
2460
  rootSessionId: scope.rootSessionId,
2232
2461
  agent: agentConfig.name,
2233
2462
  identity: identity.identity,
@@ -2267,9 +2496,13 @@ var SpawnPlanner = class {
2267
2496
  }, {
2268
2497
  identity: identity.identity,
2269
2498
  inline: identity.inline,
2499
+ ...awaitedInline ? {
2500
+ awaited: true,
2501
+ delivery: "silent"
2502
+ } : silent ? { delivery: "silent" } : {},
2270
2503
  ...agentConfig.description ? { agentDescription: agentConfig.description } : {},
2271
2504
  ...agentConfig.filePath ? { agentFilePath: agentConfig.filePath } : {}
2272
- });
2505
+ }, signal);
2273
2506
  } catch (error) {
2274
2507
  intercom?.dispose?.();
2275
2508
  throw error;
@@ -2312,7 +2545,9 @@ var SpawnPlanner = class {
2312
2545
  async spawn(request, config) {
2313
2546
  if (!this.agentConfig) throw new PoTeamExpectedError("runtime_unavailable", "Team agent configuration is not loaded yet.", true, "Retry after the session configuration is ready.");
2314
2547
  const team = await this.agentConfig.current();
2548
+ request.signal?.throwIfAborted();
2315
2549
  const tasks = this.resolveTaskList(request);
2550
+ if (request.awaitedInline && tasks.some((task) => !task.inlineAgent)) throw new Error("Awaited Team runs require inline agents.");
2316
2551
  const workflowPreferences = readWorkflowPreferences(request.environment?.WORKFLOW_RUN_CONFIG ?? this.environment.WORKFLOW_RUN_CONFIG);
2317
2552
  const planningConfig = request.parentSelection?.state?.["minor-mode"]?.includes("plan") ? team.planningSubagents : void 0;
2318
2553
  const planningPreferences = {
@@ -2320,7 +2555,15 @@ var SpawnPlanner = class {
2320
2555
  subagentThinking: planningConfig?.thinking
2321
2556
  };
2322
2557
  const fanout = tasks.length > 1;
2323
- const teamPackageExcludeTools = team.excludeTools ? [...team.excludeTools] : void 0;
2558
+ const teamPackageExcludeTools = request.awaitedInline ? [.../* @__PURE__ */ new Set([
2559
+ ...team.excludeTools ?? [],
2560
+ "exec",
2561
+ "discover",
2562
+ "exec_background",
2563
+ "exec_cancel",
2564
+ "subagent",
2565
+ "intercom"
2566
+ ])] : team.excludeTools ? [...team.excludeTools] : void 0;
2324
2567
  const teamPackageModels = team.models;
2325
2568
  const capabilityCeiling = this.policies.resolve();
2326
2569
  const depthCheck = preflightSubagentDepth(request.currentDepth ?? resolveCurrentSubagentDepth(), config);
@@ -2341,7 +2584,7 @@ var SpawnPlanner = class {
2341
2584
  ].join("\0");
2342
2585
  let resolved = taskInput.inlineAgent ? void 0 : resolvedAgentCache.get(cacheKey);
2343
2586
  if (!resolved) {
2344
- resolved = await this.resolveExecutableAgent(taskInput, taskInput.cwd ?? request.cwd, request.agentScope);
2587
+ resolved = await this.resolveExecutableAgent(taskInput, taskInput.cwd ?? request.cwd, request.agentScope, request.awaitedInline);
2345
2588
  if (!taskInput.inlineAgent) resolvedAgentCache.set(cacheKey, resolved);
2346
2589
  }
2347
2590
  resolvedAgents.push(resolved);
@@ -2390,6 +2633,9 @@ var SpawnPlanner = class {
2390
2633
  const skillProjectionCache = /* @__PURE__ */ new Map();
2391
2634
  return { outcomes: (await runWithConcurrency(tasks.map((taskInput, childIndex) => () => this.spawnOneChild({
2392
2635
  runId: runIds[childIndex],
2636
+ awaitedInline: request.awaitedInline,
2637
+ silent: request.silent,
2638
+ signal: request.signal,
2393
2639
  operationId: request.operationId,
2394
2640
  agentConfig: resolvedAgents[childIndex],
2395
2641
  identity: identities[childIndex],
@@ -2407,7 +2653,7 @@ var SpawnPlanner = class {
2407
2653
  parentForkSource: request.parentForkSource,
2408
2654
  sessionScope: request.sessionScope,
2409
2655
  ...request.sender ? { sender: request.sender } : {},
2410
- environment: request.environment ?? {},
2656
+ environment: request.awaitedInline ? Object.fromEntries(Object.entries(request.environment ?? {}).filter(([key]) => key !== "WORKFLOW_DECISION_FILE")) : request.environment ?? {},
2411
2657
  parentSessionFile: request.parentSessionFile,
2412
2658
  maxLiveRuns,
2413
2659
  admissionTimeoutMs,
@@ -2628,7 +2874,8 @@ function createDelegationBridge(deps) {
2628
2874
  environment: session.environment,
2629
2875
  ...forkRequestFields(forkSource),
2630
2876
  availableModels: await session.availableModels(),
2631
- ...session.parentModel ? { parentModel: session.parentModel } : {}
2877
+ ...session.parentModel ? { parentModel: session.parentModel } : {},
2878
+ ...request.internal ? { silent: true } : {}
2632
2879
  }, deps.loadConfig())).outcomes[0];
2633
2880
  if (!outcome?.runId) {
2634
2881
  finish(entry, {
@@ -5740,18 +5987,27 @@ declare const team: {
5740
5987
  members(): TeamMember[];
5741
5988
  /** Tracked runs. Finished runs drop off 10 minutes after acknowledgement. */
5742
5989
  runs(): TeamRun[];
5990
+ /** Await one inline agent. Inherits capabilities except delegation and parent-bound code mode. Never rejects. */
5991
+ run(input: { systemPrompt: string; task: string; model?: string; timeoutMs?: number }): Promise<{
5992
+ runId?: string; status: 'completed' | 'failed' | 'stopped'; output: string; error?: string;
5993
+ }>;
5743
5994
  };`;
5744
- /** Session-owned read-only state. Direct tools retain all mutation capabilities. */
5995
+ /** Session-owned state and awaited inline runs. Direct tools retain discovery and management. */
5745
5996
  function createTeamNamespace(options) {
5746
5997
  return {
5747
5998
  name: "team",
5748
- summary: "Read native team members and tracked runs in this session with team.members() and team.runs().",
5999
+ summary: "Read team members and runs, or await an inline agent with team.run().",
5749
6000
  declarations: DECLARATIONS,
5750
6001
  bind(run) {
5751
6002
  if (run.sessionId !== options.sessionId) throw new Error("Team namespace belongs to another session.");
5752
6003
  let disposed = false;
5753
- run.onDispose(() => {
6004
+ const lifetime = new AbortController();
6005
+ const signal = AbortSignal.any([run.signal, lifetime.signal]);
6006
+ const active = /* @__PURE__ */ new Set();
6007
+ run.onDispose(async () => {
5754
6008
  disposed = true;
6009
+ lifetime.abort(/* @__PURE__ */ new Error("Team code-mode run is disposed."));
6010
+ await Promise.all(active);
5755
6011
  });
5756
6012
  const check = () => {
5757
6013
  run.signal.throwIfAborted();
@@ -5789,6 +6045,24 @@ function createTeamNamespace(options) {
5789
6045
  check();
5790
6046
  return snapshot;
5791
6047
  };
6048
+ members.run = (input) => {
6049
+ const pending = (async () => {
6050
+ try {
6051
+ check();
6052
+ if (!options.run) throw new Error("Awaited inline agents are unavailable on this host.");
6053
+ return JSON.parse(JSON.stringify(await options.run(input, signal)));
6054
+ } catch (error) {
6055
+ return {
6056
+ status: signal.aborted ? "stopped" : "failed",
6057
+ output: "",
6058
+ error: error instanceof Error ? error.message : String(error)
6059
+ };
6060
+ }
6061
+ })();
6062
+ active.add(pending);
6063
+ pending.finally(() => active.delete(pending));
6064
+ return pending;
6065
+ };
5792
6066
  return members;
5793
6067
  }
5794
6068
  };
@@ -6563,6 +6837,10 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
6563
6837
  const environment = serverHost.context.environment;
6564
6838
  const fs = (0, _agimon_ai_po_core_platform.requirePoFs)(context);
6565
6839
  const homeDirectory = environment.HOME ?? _agimon_ai_po_core_platform.nodeHost.homeDirectory();
6840
+ const sessionConfig = loadConfig({
6841
+ ...environment,
6842
+ HOME: homeDirectory
6843
+ }).config;
6566
6844
  const runtime = createTeamExtensionRuntime((event, attributes) => {
6567
6845
  telemetry.recordEvent(event, attributes);
6568
6846
  }, {
@@ -6582,6 +6860,13 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
6582
6860
  childSessions: { get: () => (0, _agimon_ai_po_core_childSession.readPoChildSessionService)(context) },
6583
6861
  nativeRunProjection
6584
6862
  });
6863
+ const awaitedInline = createAwaitedInlineRunner({
6864
+ execution,
6865
+ planner: runtime.spawnPlanner,
6866
+ coordinator: runtime.nativeRuns,
6867
+ config: sessionConfig,
6868
+ emit: (event) => context.emit(_agimon_ai_po_core_delegation.PO_TEAM_INLINE_RUN_EVENT, event)
6869
+ });
6585
6870
  const scope = require_atomicJson.createSessionScope(execution.sessionId);
6586
6871
  runtime.management.bindSessionScope(scope);
6587
6872
  const jobs = runtime.asyncJobTracker.forSession(execution.sessionId, scope);
@@ -6591,7 +6876,7 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
6591
6876
  waiter: runtime.subagentWaiter,
6592
6877
  scheduler: runtime.pollScheduler,
6593
6878
  tracker: runtime.asyncJobTracker,
6594
- loadConfig: () => loadConfig().config
6879
+ loadConfig: () => sessionConfig
6595
6880
  });
6596
6881
  const fablePlan = createFablePlanBridge({
6597
6882
  spawner: runtime.asyncSubagentSpawner,
@@ -6707,6 +6992,7 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
6707
6992
  sessionId: execution.sessionId,
6708
6993
  channel,
6709
6994
  jobs,
6995
+ run: (input, signal) => awaitedInline.run(input, signal),
6710
6996
  assertAvailable: () => {
6711
6997
  if (disposing) throw new Error("Team session is disposing.");
6712
6998
  }
@@ -6795,7 +7081,7 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
6795
7081
  let restored = 0;
6796
7082
  for (const run of stored) {
6797
7083
  const identity = storedRunIdentity(run);
6798
- const intercom = run.settled ? void 0 : runtime.teamChannel.createNativeChildIntercom({
7084
+ const intercom = run.settled || identity?.awaited ? void 0 : runtime.teamChannel.createNativeChildIntercom({
6799
7085
  rootSessionId: run.request.scope.rootSessionId,
6800
7086
  agent: run.request.agent,
6801
7087
  ...identity ? {
@@ -6853,6 +7139,7 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
6853
7139
  activityAttached = false;
6854
7140
  let stoppedRuns;
6855
7141
  await (0, _agimon_ai_po_core_extensionFile.runCleanups)([
7142
+ () => awaitedInline.close(),
6856
7143
  () => stopPeerDiscovery?.(),
6857
7144
  () => sessionPeers.clear(),
6858
7145
  () => execution.client.setStatus(TEAM_COST_STATUS, void 0),