@agimon-ai/po-team 0.0.0-alpha.2 → 0.0.0-alpha.21
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/LICENSE +166 -5
- package/README.md +11 -12
- package/dist/{agentDiscovery-Whwzc4dP.cjs → agentDiscovery-DTTlM_LT.cjs} +246 -350
- package/dist/agentDiscovery-DTTlM_LT.cjs.map +1 -0
- package/dist/{agentDiscovery-ZQlFkKvB.mjs → agentDiscovery-ZNG8iZXV.mjs} +210 -279
- package/dist/agentDiscovery-ZNG8iZXV.mjs.map +1 -0
- package/dist/apiContracts.cjs +10 -3
- package/dist/apiContracts.cjs.map +1 -1
- package/dist/apiContracts.d.mts.map +1 -1
- package/dist/apiContracts.mjs +10 -3
- package/dist/apiContracts.mjs.map +1 -1
- package/dist/{externalProcessIpc-ojE0pvw0.cjs → atomicJson-DRT03Ql5.cjs} +155 -21
- package/dist/atomicJson-DRT03Ql5.cjs.map +1 -0
- package/dist/{externalProcessIpc-C-15lJrB.mjs → atomicJson-VVM1iAPu.mjs} +140 -12
- package/dist/atomicJson-VVM1iAPu.mjs.map +1 -0
- package/dist/{capabilityCeiling-CF7kAS18.mjs → capabilityCeiling-BaHT9v9S.mjs} +3 -3
- package/dist/capabilityCeiling-BaHT9v9S.mjs.map +1 -0
- package/dist/{capabilityCeiling-C-Y7H8oC.cjs → capabilityCeiling-CO3ZjYmY.cjs} +3 -3
- package/dist/capabilityCeiling-CO3ZjYmY.cjs.map +1 -0
- package/dist/capabilityCeiling.cjs +2 -2
- package/dist/capabilityCeiling.d.mts +2 -2
- package/dist/capabilityCeiling.mjs +2 -2
- package/dist/delegation.cjs +1 -1
- package/dist/delegation.cjs.map +1 -1
- package/dist/delegation.d.mts +1 -1
- package/dist/delegation.mjs +1 -1
- package/dist/delegation.mjs.map +1 -1
- package/dist/delegationApi.cjs +30 -30
- package/dist/delegationApi.d.mts +2 -2
- package/dist/delegationApi.mjs +1 -2
- package/dist/env.cjs +1 -1
- package/dist/env.d.mts +1 -1
- package/dist/env.mjs +1 -2
- package/dist/{environment-DrqhrxG_.mjs → environment-BtvJI2S-.mjs} +3 -3
- package/dist/environment-BtvJI2S-.mjs.map +1 -0
- package/dist/{environment-ma5oQ7uM.d.mts → environment-Bz1OlWIT.d.mts} +2 -2
- package/dist/{environment-ma5oQ7uM.d.mts.map → environment-Bz1OlWIT.d.mts.map} +1 -1
- package/dist/{environment-CaCW3SgT.cjs → environment-Cqs7vHJL.cjs} +3 -3
- package/dist/environment-Cqs7vHJL.cjs.map +1 -0
- package/dist/extensions/native.mjs +34 -12
- package/dist/extensions/native.mjs.map +1 -1
- package/dist/extensions/server.cjs +990 -786
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.d.mts +2 -2
- package/dist/extensions/server.d.mts.map +1 -1
- package/dist/extensions/server.mjs +975 -772
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/extensions/web.mjs +994 -807
- package/dist/extensions/web.mjs.map +1 -1
- package/dist/fablePlan.cjs +3 -3
- package/dist/fablePlan.d.mts +2 -2
- package/dist/fablePlan.mjs +1 -2
- package/dist/{fablePlanApi-CZ3uUcMi.d.mts → fablePlanApi-BTNKjLni.d.mts} +6 -6
- package/dist/{fablePlanApi-CZ3uUcMi.d.mts.map → fablePlanApi-BTNKjLni.d.mts.map} +1 -1
- package/dist/{fablePlanApi-wBu9bRXU.cjs → fablePlanApi-BhI4jnDP.cjs} +12 -12
- package/dist/fablePlanApi-BhI4jnDP.cjs.map +1 -0
- package/dist/{fablePlanApi-BsHhgVFV.mjs → fablePlanApi-DuMg43Hu.mjs} +5 -5
- package/dist/fablePlanApi-DuMg43Hu.mjs.map +1 -0
- package/dist/fablePlanApi.cjs +3 -3
- package/dist/fablePlanApi.d.mts +2 -2
- package/dist/fablePlanApi.mjs +1 -2
- package/dist/index.cjs +17 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +5 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +15 -5
- package/dist/index.mjs.map +1 -1
- package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
- package/dist/runs/background/cliRunnerEntry.cjs +26 -25
- package/dist/runs/background/cliRunnerEntry.cjs.map +1 -1
- package/dist/runs/background/cliRunnerEntry.mjs +14 -14
- package/dist/runs/background/cliRunnerEntry.mjs.map +1 -1
- package/dist/runtimeSubagentPolicy.cjs +3 -3
- package/dist/runtimeSubagentPolicy.d.mts +2 -2
- package/dist/runtimeSubagentPolicy.mjs +1 -2
- package/dist/runtimeSubagentTool.cjs +7 -2
- package/dist/runtimeSubagentTool.d.mts +1 -1
- package/dist/runtimeSubagentTool.mjs +1 -2
- package/dist/{subagentPolicy-ALJam4GN.d.mts → subagentPolicy-BE-OZoa-.d.mts} +6 -6
- package/dist/subagentPolicy-BE-OZoa-.d.mts.map +1 -0
- package/dist/{subagentPolicy-DQRyKDH-.cjs → subagentPolicy-DIpaKHO8.cjs} +8 -8
- package/dist/subagentPolicy-DIpaKHO8.cjs.map +1 -0
- package/dist/{subagentPolicy-DxjsKeyj.mjs → subagentPolicy-LfcXuqO5.mjs} +5 -5
- package/dist/subagentPolicy-LfcXuqO5.mjs.map +1 -0
- package/dist/subagentPolicy.cjs +3 -3
- package/dist/subagentPolicy.d.mts +2 -2
- package/dist/subagentPolicy.mjs +1 -2
- package/dist/{subagentTool-Ca2zQXKw.cjs → subagentTool-BueNPGHo.cjs} +5 -16
- package/dist/subagentTool-BueNPGHo.cjs.map +1 -0
- package/dist/{subagentTool-BTssGLw8.d.mts → subagentTool-UdB3s6Mn.d.mts} +2 -11
- package/dist/subagentTool-UdB3s6Mn.d.mts.map +1 -0
- package/dist/{subagentTool-WOYrjxgT.mjs → subagentTool-a2oh2v5B.mjs} +5 -16
- package/dist/subagentTool-a2oh2v5B.mjs.map +1 -0
- package/dist/subagentTool.cjs +7 -2
- package/dist/subagentTool.d.mts +1 -1
- package/dist/subagentTool.mjs +1 -2
- package/dist/teamSnapshot.d.mts +1 -0
- package/dist/teamSnapshot.d.mts.map +1 -1
- package/dist/teamSnapshot.mjs +1 -2
- package/package.json +25 -24
- package/dist/agentDiscovery-Whwzc4dP.cjs.map +0 -1
- package/dist/agentDiscovery-ZQlFkKvB.mjs.map +0 -1
- package/dist/atomicJson-D0346bt5.cjs +0 -178
- package/dist/atomicJson-D0346bt5.cjs.map +0 -1
- package/dist/atomicJson-D2t0CDh9.mjs +0 -137
- package/dist/atomicJson-D2t0CDh9.mjs.map +0 -1
- package/dist/capabilityCeiling-C-Y7H8oC.cjs.map +0 -1
- package/dist/capabilityCeiling-CF7kAS18.mjs.map +0 -1
- package/dist/environment-CaCW3SgT.cjs.map +0 -1
- package/dist/environment-DrqhrxG_.mjs.map +0 -1
- package/dist/externalProcessIpc-C-15lJrB.mjs.map +0 -1
- package/dist/externalProcessIpc-ojE0pvw0.cjs.map +0 -1
- package/dist/fablePlanApi-BsHhgVFV.mjs.map +0 -1
- package/dist/fablePlanApi-wBu9bRXU.cjs.map +0 -1
- package/dist/subagentPolicy-ALJam4GN.d.mts.map +0 -1
- package/dist/subagentPolicy-DQRyKDH-.cjs.map +0 -1
- package/dist/subagentPolicy-DxjsKeyj.mjs.map +0 -1
- package/dist/subagentTool-BTssGLw8.d.mts.map +0 -1
- package/dist/subagentTool-Ca2zQXKw.cjs.map +0 -1
- package/dist/subagentTool-WOYrjxgT.mjs.map +0 -1
|
@@ -2,32 +2,33 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const
|
|
6
|
-
const require_environment = require("../environment-
|
|
7
|
-
const require_capabilityCeiling = require("../capabilityCeiling-
|
|
8
|
-
const require_fablePlanApi = require("../fablePlanApi-
|
|
9
|
-
const require_agentDiscovery = require("../agentDiscovery-
|
|
10
|
-
const require_subagentPolicy = require("../subagentPolicy-
|
|
11
|
-
const require_subagentTool = require("../subagentTool-
|
|
5
|
+
const require_rolldown_runtime = require("../rolldown-runtime-VH7oDXx4.cjs");
|
|
6
|
+
const require_environment = require("../environment-Cqs7vHJL.cjs");
|
|
7
|
+
const require_capabilityCeiling = require("../capabilityCeiling-CO3ZjYmY.cjs");
|
|
8
|
+
const require_fablePlanApi = require("../fablePlanApi-BhI4jnDP.cjs");
|
|
9
|
+
const require_agentDiscovery = require("../agentDiscovery-DTTlM_LT.cjs");
|
|
10
|
+
const require_subagentPolicy = require("../subagentPolicy-DIpaKHO8.cjs");
|
|
11
|
+
const require_subagentTool = require("../subagentTool-BueNPGHo.cjs");
|
|
12
12
|
const require_teamSnapshot = require("../teamSnapshot-oKuGFdYc.cjs");
|
|
13
|
-
const
|
|
13
|
+
const require_atomicJson = require("../atomicJson-DRT03Ql5.cjs");
|
|
14
14
|
let node_buffer = require("node:buffer");
|
|
15
15
|
let _agimon_ai_po_core_childProcess = require("@agimon-ai/po-core/childProcess");
|
|
16
16
|
let _agimon_ai_po_core_delegation = require("@agimon-ai/po-core/delegation");
|
|
17
17
|
let typebox = require("typebox");
|
|
18
|
-
let node_fs = require("node:fs");
|
|
19
|
-
node_fs = require_atomicJson.__toESM(node_fs, 1);
|
|
20
18
|
let node_path = require("node:path");
|
|
21
|
-
node_path =
|
|
19
|
+
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
20
|
+
let _agimon_ai_po_core_platform = require("@agimon-ai/po-core/platform");
|
|
21
|
+
let node_fs = require("node:fs");
|
|
22
|
+
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
22
23
|
let node_os = require("node:os");
|
|
23
|
-
node_os =
|
|
24
|
-
let
|
|
24
|
+
node_os = require_rolldown_runtime.__toESM(node_os, 1);
|
|
25
|
+
let _agimon_ai_po_core_serverPlugin = require("@agimon-ai/po-core/serverPlugin");
|
|
25
26
|
let _agimon_ai_po_core_extensionFile = require("@agimon-ai/po-core/extensionFile");
|
|
27
|
+
let _agimon_ai_po_config = require("@agimon-ai/po-config");
|
|
26
28
|
let _agimon_ai_po_core_backgroundWork = require("@agimon-ai/po-core/backgroundWork");
|
|
27
29
|
let _agimon_ai_po_core_childSession = require("@agimon-ai/po-core/childSession");
|
|
28
30
|
let _agimon_ai_po_core_contextContributions = require("@agimon-ai/po-core/contextContributions");
|
|
29
31
|
let _agimon_ai_po_core_mcpToolResolver = require("@agimon-ai/po-core/mcpToolResolver");
|
|
30
|
-
let _agimon_ai_po_core_readiness = require("@agimon-ai/po-core/readiness");
|
|
31
32
|
let _agimon_ai_po_session = require("@agimon-ai/po-session");
|
|
32
33
|
let _agimon_ai_po_telemetry = require("@agimon-ai/po-telemetry");
|
|
33
34
|
let typebox_value = require("typebox/value");
|
|
@@ -35,7 +36,9 @@ let node_crypto = require("node:crypto");
|
|
|
35
36
|
let node_child_process = require("node:child_process");
|
|
36
37
|
let node_url = require("node:url");
|
|
37
38
|
let _agimon_ai_po_core_headless = require("@agimon-ai/po-core/headless");
|
|
39
|
+
let _agimon_ai_po_config_majorModes = require("@agimon-ai/po-config/majorModes");
|
|
38
40
|
require("@agimon-ai/po-core/cordisHost");
|
|
41
|
+
let _agimon_ai_po_core_hubChannel = require("@agimon-ai/po-core/hubChannel");
|
|
39
42
|
//#region src/services/config/index.ts
|
|
40
43
|
/**
|
|
41
44
|
* `subagent` tool config file: read/write, and the scoped `ExtensionConfig`
|
|
@@ -177,13 +180,13 @@ var AdmissionGate = class {
|
|
|
177
180
|
}
|
|
178
181
|
if (!waited) {
|
|
179
182
|
waited = true;
|
|
180
|
-
request.report?.("
|
|
183
|
+
request.report?.("po_team.admission_wait", {
|
|
181
184
|
"team.live_runs": live,
|
|
182
185
|
"team.max_live_runs": request.maxLiveRuns
|
|
183
186
|
});
|
|
184
187
|
}
|
|
185
188
|
if (this.now() >= deadline) {
|
|
186
|
-
request.report?.("
|
|
189
|
+
request.report?.("po_team.admission_timeout", {
|
|
187
190
|
"team.live_runs": live,
|
|
188
191
|
"team.max_live_runs": request.maxLiveRuns,
|
|
189
192
|
duration_ms: this.now() - waitStartedAt
|
|
@@ -420,7 +423,7 @@ const AGENT_NAMES = Object.freeze([
|
|
|
420
423
|
"fabia"
|
|
421
424
|
]);
|
|
422
425
|
function agentIdentitiesDir(scope) {
|
|
423
|
-
return node_path.join(
|
|
426
|
+
return node_path.join(require_atomicJson.sessionScopeDir(scope), IDENTITIES_DIR_NAME);
|
|
424
427
|
}
|
|
425
428
|
/**
|
|
426
429
|
* The role an identity advertises, taken from the last segment of the agent
|
|
@@ -515,26 +518,6 @@ function claimAgentIdentity(scope, input) {
|
|
|
515
518
|
}
|
|
516
519
|
return degraded;
|
|
517
520
|
}
|
|
518
|
-
/**
|
|
519
|
-
* Point an existing identity at a new run id.
|
|
520
|
-
*
|
|
521
|
-
* Restore mints a fresh run id for what is conceptually the same agent, so the
|
|
522
|
-
* identity has to be carried across rather than derived again. This is a
|
|
523
|
-
* single-writer rewrite of one claim, so the lost-update hazard that rules out
|
|
524
|
-
* a shared registry file does not apply.
|
|
525
|
-
*/
|
|
526
|
-
function adoptAgentIdentity(scope, identity, runId) {
|
|
527
|
-
const file = node_path.join(agentIdentitiesDir(scope), `${identity}.json`);
|
|
528
|
-
const existing = readClaim(file);
|
|
529
|
-
if (!existing) return;
|
|
530
|
-
try {
|
|
531
|
-
node_fs.writeFileSync(file, `${JSON.stringify({
|
|
532
|
-
...existing,
|
|
533
|
-
runId,
|
|
534
|
-
claimedAt: Date.now()
|
|
535
|
-
})}\n`, { mode: 384 });
|
|
536
|
-
} catch {}
|
|
537
|
-
}
|
|
538
521
|
/** Render an identity for display, marking the inline case that has no agent file on disk. */
|
|
539
522
|
function formatAgentIdentity(identity, inline) {
|
|
540
523
|
if (!identity) return void 0;
|
|
@@ -1070,7 +1053,7 @@ function preflightSubagentDepth(depth, config) {
|
|
|
1070
1053
|
}
|
|
1071
1054
|
//#endregion
|
|
1072
1055
|
//#region src/services/errors/index.ts
|
|
1073
|
-
var
|
|
1056
|
+
var PoTeamExpectedError = class extends Error {
|
|
1074
1057
|
code;
|
|
1075
1058
|
retryable;
|
|
1076
1059
|
recovery;
|
|
@@ -1079,11 +1062,11 @@ var DoomTeamExpectedError = class extends Error {
|
|
|
1079
1062
|
this.code = code;
|
|
1080
1063
|
this.retryable = retryable;
|
|
1081
1064
|
this.recovery = recovery;
|
|
1082
|
-
this.name = "
|
|
1065
|
+
this.name = "PoTeamExpectedError";
|
|
1083
1066
|
}
|
|
1084
1067
|
};
|
|
1085
1068
|
function invalidRequest(message, recovery) {
|
|
1086
|
-
return new
|
|
1069
|
+
return new PoTeamExpectedError("invalid_request", message, false, recovery);
|
|
1087
1070
|
}
|
|
1088
1071
|
//#endregion
|
|
1089
1072
|
//#region src/services/modelInfo/index.ts
|
|
@@ -1123,6 +1106,12 @@ function toModelInfo(model) {
|
|
|
1123
1106
|
thinkingLevelMap: model.thinkingLevelMap
|
|
1124
1107
|
};
|
|
1125
1108
|
}
|
|
1109
|
+
/** The parent's authenticated models as the host lists them now; only the parent model when it cannot list. */
|
|
1110
|
+
async function availableModelInfos(execution) {
|
|
1111
|
+
const models = await execution.getAvailableModels?.();
|
|
1112
|
+
if (models) return models.map(toModelInfo);
|
|
1113
|
+
return execution.model ? [toModelInfo(execution.model)] : [];
|
|
1114
|
+
}
|
|
1126
1115
|
function splitKnownThinkingSuffix(model) {
|
|
1127
1116
|
const colonIdx = model.lastIndexOf(THINKING_SUFFIX_SEPARATOR);
|
|
1128
1117
|
if (colonIdx === -1) return {
|
|
@@ -1406,6 +1395,205 @@ function selectAvailableModel(primaryModel, fallbackModels, availableModels, pre
|
|
|
1406
1395
|
}
|
|
1407
1396
|
}
|
|
1408
1397
|
//#endregion
|
|
1398
|
+
//#region src/services/nativeRunCoordinator/index.ts
|
|
1399
|
+
/**
|
|
1400
|
+
* The root session's agent. Every Team launcher except the browser's is one of
|
|
1401
|
+
* its tools, so it is who sent a task or steer that arrives through them.
|
|
1402
|
+
*/
|
|
1403
|
+
const MAIN_AGENT_SENDER = {
|
|
1404
|
+
kind: "agent",
|
|
1405
|
+
id: "main",
|
|
1406
|
+
name: "Main agent"
|
|
1407
|
+
};
|
|
1408
|
+
/** The person at the browser, who launches and guides runs from the Agents tab. */
|
|
1409
|
+
const HUMAN_SENDER = {
|
|
1410
|
+
kind: "human",
|
|
1411
|
+
name: "You"
|
|
1412
|
+
};
|
|
1413
|
+
function terminalState(event) {
|
|
1414
|
+
return event.state === "completed" || event.state === "failed" || event.state === "stopped" ? event.state : void 0;
|
|
1415
|
+
}
|
|
1416
|
+
function entryKey(sessionId, runId) {
|
|
1417
|
+
return JSON.stringify([sessionId, runId]);
|
|
1418
|
+
}
|
|
1419
|
+
/** A stored run's identity, as `start` put it in the request's `meta`. */
|
|
1420
|
+
function storedRunIdentity(run) {
|
|
1421
|
+
const meta = run.request.meta;
|
|
1422
|
+
if (typeof meta?.identity !== "string") return void 0;
|
|
1423
|
+
return {
|
|
1424
|
+
identity: meta.identity,
|
|
1425
|
+
inline: meta.inline === true,
|
|
1426
|
+
...typeof meta.agentDescription === "string" ? { agentDescription: meta.agentDescription } : {},
|
|
1427
|
+
...typeof meta.agentFilePath === "string" ? { agentFilePath: meta.agentFilePath } : {}
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
var NativeRunCoordinator = class {
|
|
1431
|
+
childSessions;
|
|
1432
|
+
tracker;
|
|
1433
|
+
notifier;
|
|
1434
|
+
projection;
|
|
1435
|
+
entries = /* @__PURE__ */ new Map();
|
|
1436
|
+
closed = false;
|
|
1437
|
+
closing;
|
|
1438
|
+
constructor(childSessions, tracker, notifier, projection) {
|
|
1439
|
+
this.childSessions = childSessions;
|
|
1440
|
+
this.tracker = tracker;
|
|
1441
|
+
this.notifier = notifier;
|
|
1442
|
+
this.projection = projection;
|
|
1443
|
+
}
|
|
1444
|
+
service() {
|
|
1445
|
+
if (this.closed) throw new Error("The native Team run coordinator is closed.");
|
|
1446
|
+
const service = this.childSessions?.get();
|
|
1447
|
+
if (!service) throw new Error("The in-process Pi child-session service is unavailable.");
|
|
1448
|
+
return service;
|
|
1449
|
+
}
|
|
1450
|
+
async start(sessionId, request, identity) {
|
|
1451
|
+
if (!sessionId.trim()) throw new Error("Native child runs require a session identity.");
|
|
1452
|
+
const handle = await this.service().start({
|
|
1453
|
+
...request,
|
|
1454
|
+
...identity ? { meta: {
|
|
1455
|
+
...request.meta,
|
|
1456
|
+
...JSON.parse(JSON.stringify(identity))
|
|
1457
|
+
} } : {}
|
|
1458
|
+
});
|
|
1459
|
+
return this.adopt(sessionId, request.scope, request, handle, identity);
|
|
1460
|
+
}
|
|
1461
|
+
async restore(sessionId, run, intercom) {
|
|
1462
|
+
const service = this.service();
|
|
1463
|
+
if (!service.restore) throw new Error("This child-session service cannot restore runs.");
|
|
1464
|
+
const handle = await service.restore(run.request.runId, intercom ? { intercom } : void 0);
|
|
1465
|
+
return this.adopt(sessionId, run.request.scope, run.request, handle, storedRunIdentity(run));
|
|
1466
|
+
}
|
|
1467
|
+
async adopt(sessionId, scope, request, handle, identity) {
|
|
1468
|
+
if (this.closed) {
|
|
1469
|
+
await handle.dispose();
|
|
1470
|
+
throw new Error("The native Team run coordinator closed during child startup.");
|
|
1471
|
+
}
|
|
1472
|
+
const entry = {
|
|
1473
|
+
sessionId,
|
|
1474
|
+
scope,
|
|
1475
|
+
request,
|
|
1476
|
+
...identity ? { identity } : {},
|
|
1477
|
+
handle,
|
|
1478
|
+
terminal: false
|
|
1479
|
+
};
|
|
1480
|
+
const key = entryKey(sessionId, request.runId);
|
|
1481
|
+
this.entries.set(key, entry);
|
|
1482
|
+
try {
|
|
1483
|
+
const unsubscribe = handle.subscribe((event) => this.onEvent(entry, event));
|
|
1484
|
+
if (entry.terminal) unsubscribe();
|
|
1485
|
+
else entry.unsubscribe = unsubscribe;
|
|
1486
|
+
return handle;
|
|
1487
|
+
} catch (error) {
|
|
1488
|
+
this.entries.delete(key);
|
|
1489
|
+
await handle.dispose().catch(() => void 0);
|
|
1490
|
+
throw error;
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
get(sessionId, runId) {
|
|
1494
|
+
return this.entries.get(entryKey(sessionId, runId))?.handle;
|
|
1495
|
+
}
|
|
1496
|
+
/**
|
|
1497
|
+
* The newest entries of a run this session's child service stored, from its durable conversation, also once the
|
|
1498
|
+
* run finished or the session restarted; undefined for a run it cannot read, such as an external one.
|
|
1499
|
+
*/
|
|
1500
|
+
async readTranscript(sessionId, runId, limit) {
|
|
1501
|
+
const service = this.service();
|
|
1502
|
+
if (!service.readTranscriptPage) return void 0;
|
|
1503
|
+
try {
|
|
1504
|
+
return (await service.readTranscriptPage(runId, { limit })).entries;
|
|
1505
|
+
} catch (error) {
|
|
1506
|
+
if (this.entries.has(entryKey(sessionId, runId))) throw error;
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
status(sessionId, runId) {
|
|
1511
|
+
return this.tracker.getNative(sessionId, runId);
|
|
1512
|
+
}
|
|
1513
|
+
async reported(runId) {
|
|
1514
|
+
return this.service().reported?.(runId);
|
|
1515
|
+
}
|
|
1516
|
+
async steer(sessionId, runId, message, signal) {
|
|
1517
|
+
const handle = this.get(sessionId, runId);
|
|
1518
|
+
if (!handle) throw new Error(`No active native run matches '${runId}'.`);
|
|
1519
|
+
await handle.steer(message, signal);
|
|
1520
|
+
}
|
|
1521
|
+
async stop(sessionId, runId, reason) {
|
|
1522
|
+
const handle = this.get(sessionId, runId);
|
|
1523
|
+
if (!handle) throw new Error(`No active native run matches '${runId}'.`);
|
|
1524
|
+
await handle.stop(reason);
|
|
1525
|
+
}
|
|
1526
|
+
async close() {
|
|
1527
|
+
this.closed = true;
|
|
1528
|
+
this.closing ??= (async () => {
|
|
1529
|
+
const active = [...this.entries.values()];
|
|
1530
|
+
for (const entry of active) {
|
|
1531
|
+
entry.unsubscribe?.();
|
|
1532
|
+
this.entries.delete(entryKey(entry.sessionId, entry.request.runId));
|
|
1533
|
+
}
|
|
1534
|
+
const failures = (await Promise.allSettled(active.map((entry) => entry.handle.dispose()))).filter((outcome) => outcome.status === "rejected").map((outcome) => outcome.reason);
|
|
1535
|
+
if (failures.length) throw new AggregateError(failures, "Native Team run shutdown failed.");
|
|
1536
|
+
})();
|
|
1537
|
+
return this.closing;
|
|
1538
|
+
}
|
|
1539
|
+
onEvent(entry, event) {
|
|
1540
|
+
entry.startedAt ??= event.timestamp;
|
|
1541
|
+
const status = terminalState(event);
|
|
1542
|
+
const projection = {
|
|
1543
|
+
runId: event.runId,
|
|
1544
|
+
agent: entry.request.agent,
|
|
1545
|
+
...entry.identity ? {
|
|
1546
|
+
identity: entry.identity.identity,
|
|
1547
|
+
inline: entry.identity.inline
|
|
1548
|
+
} : {},
|
|
1549
|
+
...entry.identity?.agentDescription ? { agentDescription: entry.identity.agentDescription } : {},
|
|
1550
|
+
...entry.identity?.agentFilePath ? { agentFilePath: entry.identity.agentFilePath } : {},
|
|
1551
|
+
task: entry.request.task,
|
|
1552
|
+
cwd: entry.request.cwd,
|
|
1553
|
+
runtime: "pi",
|
|
1554
|
+
status: event.state === "starting" ? "queued" : event.state === "running" ? "running" : event.state,
|
|
1555
|
+
startedAt: entry.startedAt,
|
|
1556
|
+
updatedAt: event.timestamp,
|
|
1557
|
+
...event.cost === void 0 ? {} : { cost: event.cost },
|
|
1558
|
+
...event.tokens === void 0 ? {} : { tokens: event.tokens },
|
|
1559
|
+
...event.toolCount === void 0 ? {} : { toolCount: event.toolCount },
|
|
1560
|
+
...event.model === void 0 ? {} : { model: event.model },
|
|
1561
|
+
...event.thinking === void 0 ? {} : { thinking: event.thinking },
|
|
1562
|
+
...event.message ? {
|
|
1563
|
+
error: status === "failed" || status === "stopped" ? event.message : void 0,
|
|
1564
|
+
summary: event.message
|
|
1565
|
+
} : {}
|
|
1566
|
+
};
|
|
1567
|
+
this.tracker.upsertNative(entry.sessionId, entry.scope, projection);
|
|
1568
|
+
this.projection?.publish(entry.sessionId, projection);
|
|
1569
|
+
if (!status || entry.terminal) return;
|
|
1570
|
+
entry.terminal = true;
|
|
1571
|
+
entry.unsubscribe?.();
|
|
1572
|
+
this.entries.delete(entryKey(entry.sessionId, entry.request.runId));
|
|
1573
|
+
const result = {
|
|
1574
|
+
runId: entry.request.runId,
|
|
1575
|
+
agent: entry.request.agent,
|
|
1576
|
+
...entry.identity ? {
|
|
1577
|
+
identity: entry.identity.identity,
|
|
1578
|
+
inline: entry.identity.inline
|
|
1579
|
+
} : {},
|
|
1580
|
+
task: entry.request.task,
|
|
1581
|
+
cwd: entry.request.cwd,
|
|
1582
|
+
runtime: "pi",
|
|
1583
|
+
state: status,
|
|
1584
|
+
success: status === "completed",
|
|
1585
|
+
summary: event.message ?? (status === "completed" ? "Native child run completed." : `Native child run ${status}.`),
|
|
1586
|
+
durationMs: Math.max(0, event.timestamp - (this.tracker.getNative(entry.sessionId, entry.request.runId)?.startedAt ?? event.timestamp)),
|
|
1587
|
+
sessionId: entry.sessionId
|
|
1588
|
+
};
|
|
1589
|
+
if (this.notifier) this.notifier.deliver(result).then(async (delivered) => {
|
|
1590
|
+
if (!delivered) return;
|
|
1591
|
+
this.tracker.acknowledgeHandoff(entry.sessionId, entry.request.runId);
|
|
1592
|
+
await this.childSessions?.get()?.markReported?.(entry.request.runId);
|
|
1593
|
+
}).catch(() => void 0);
|
|
1594
|
+
}
|
|
1595
|
+
};
|
|
1596
|
+
//#endregion
|
|
1409
1597
|
//#region src/services/runtimeRegistry/index.ts
|
|
1410
1598
|
/**
|
|
1411
1599
|
* Which agent runtime executes a run, and how to invoke it.
|
|
@@ -1522,12 +1710,12 @@ async function runWithConcurrency(factories, concurrency, report) {
|
|
|
1522
1710
|
}
|
|
1523
1711
|
}
|
|
1524
1712
|
}
|
|
1525
|
-
report?.("
|
|
1713
|
+
report?.("po_team.concurrency_started", {
|
|
1526
1714
|
"team.task_count": factories.length,
|
|
1527
1715
|
"team.concurrency": effectiveConcurrency
|
|
1528
1716
|
});
|
|
1529
1717
|
await Promise.all(Array.from({ length: effectiveConcurrency }, () => worker()));
|
|
1530
|
-
report?.("
|
|
1718
|
+
report?.("po_team.concurrency_finished", {
|
|
1531
1719
|
"team.task_count": factories.length,
|
|
1532
1720
|
"team.concurrency": effectiveConcurrency,
|
|
1533
1721
|
"team.failure_count": results.filter((result) => result?.status === "rejected").length,
|
|
@@ -1574,8 +1762,8 @@ async function runWithConcurrency(factories, concurrency, report) {
|
|
|
1574
1762
|
* be worse than not checking at all (false confidence). Wiring this needs
|
|
1575
1763
|
* a real session-scoped store owned by a lifecycle-bound service - a
|
|
1576
1764
|
* follow-up, not guessed here.
|
|
1577
|
-
* - Fork context is resolved here and requires
|
|
1578
|
-
* unavailable
|
|
1765
|
+
* - Fork context is resolved here and requires the parent session's branch;
|
|
1766
|
+
* unavailable fork requests fail closed rather than becoming fresh
|
|
1579
1767
|
* launches.
|
|
1580
1768
|
* - Per-task overrides with no direct `BuildPiArgsInput` field confirmed yet
|
|
1581
1769
|
* (`skill`, `toolBudget`, `turnBudget`, `outputSchema`/structured output,
|
|
@@ -1611,9 +1799,8 @@ function describeForkFailure(reason) {
|
|
|
1611
1799
|
/**
|
|
1612
1800
|
* Map a captured parent branch onto the spawn request's fork fields.
|
|
1613
1801
|
*
|
|
1614
|
-
*
|
|
1615
|
-
*
|
|
1616
|
-
* those fields would describe it in the wrong vocabulary and lose the branch.
|
|
1802
|
+
* A headless host's branch forks a native child inside its own Harness. A
|
|
1803
|
+
* terminal Pi capture describes a branch for an external runtime only.
|
|
1617
1804
|
*/
|
|
1618
1805
|
function forkRequestFields(captured) {
|
|
1619
1806
|
if (!captured) return { parentForkFailure: "no-capture-installed" };
|
|
@@ -1621,7 +1808,6 @@ function forkRequestFields(captured) {
|
|
|
1621
1808
|
if (!captured.ok) return { parentForkFailure: captured.reason };
|
|
1622
1809
|
const { source } = captured;
|
|
1623
1810
|
return {
|
|
1624
|
-
parentForkSource: source.terminalSource,
|
|
1625
1811
|
...source.sessionFile ? { parentSessionFile: source.sessionFile } : {},
|
|
1626
1812
|
parentLeafId: source.leafId
|
|
1627
1813
|
};
|
|
@@ -1643,34 +1829,25 @@ function captureSessionForkSource(manager, mode) {
|
|
|
1643
1829
|
ok: false,
|
|
1644
1830
|
reason: "unsupported-version"
|
|
1645
1831
|
};
|
|
1646
|
-
|
|
1647
|
-
if (branch.at(-1)?.id !== leafId) return {
|
|
1832
|
+
if (manager.getBranch(leafId).at(-1)?.id !== leafId) return {
|
|
1648
1833
|
ok: false,
|
|
1649
1834
|
reason: "branch-mismatch"
|
|
1650
1835
|
};
|
|
1651
|
-
|
|
1652
|
-
if (!sourceSessionId.trim()) return {
|
|
1836
|
+
if (!manager.getSessionId().trim()) return {
|
|
1653
1837
|
ok: false,
|
|
1654
1838
|
reason: "no-session-id"
|
|
1655
1839
|
};
|
|
1656
|
-
const terminalSource = Object.freeze({
|
|
1657
|
-
kind: "terminal-pi-fork",
|
|
1658
|
-
sourceSessionId,
|
|
1659
|
-
sourceLeafId: leafId,
|
|
1660
|
-
snapshotJsonl: `${[header, ...branch].map((record) => JSON.stringify(record)).join("\n")}\n`
|
|
1661
|
-
});
|
|
1662
1840
|
const sessionFile = manager.getSessionFile();
|
|
1663
1841
|
return {
|
|
1664
1842
|
ok: true,
|
|
1665
1843
|
source: {
|
|
1666
1844
|
leafId,
|
|
1667
|
-
terminalSource,
|
|
1668
1845
|
...readableSessionFile(sessionFile) ? { sessionFile } : {}
|
|
1669
1846
|
}
|
|
1670
1847
|
};
|
|
1671
1848
|
}
|
|
1672
1849
|
function resolveEffectiveContext(taskInput, agent) {
|
|
1673
|
-
return taskInput.
|
|
1850
|
+
return taskInput.context ?? agent.defaultContext ?? CONTEXT_FRESH;
|
|
1674
1851
|
}
|
|
1675
1852
|
const DEFAULT_PARALLEL_CONCURRENCY = 4;
|
|
1676
1853
|
/**
|
|
@@ -1680,14 +1857,13 @@ const DEFAULT_PARALLEL_CONCURRENCY = 4;
|
|
|
1680
1857
|
* soon as its child confirms it started, and the child then runs detached. So
|
|
1681
1858
|
* `runWithConcurrency` throttles how fast children are STARTED, not how many
|
|
1682
1859
|
* are running - `{tasks: [8], concurrency: 4}` ends up with eight live model
|
|
1683
|
-
* processes, not four.
|
|
1684
|
-
* `PI_TEAM_MATE_MAX_PARALLEL`.
|
|
1860
|
+
* processes, not four. 30 lets one call fan a whole swarm out.
|
|
1685
1861
|
*
|
|
1686
1862
|
* This is a per-call declaration limit and nothing more. What actually bounds
|
|
1687
1863
|
* live children across concurrent calls is `AdmissionGate`
|
|
1688
1864
|
* (`runs/shared/admissionGate.ts`), which every spawn passes through.
|
|
1689
1865
|
*/
|
|
1690
|
-
const DEFAULT_PARALLEL_MAX_TASKS =
|
|
1866
|
+
const DEFAULT_PARALLEL_MAX_TASKS = 30;
|
|
1691
1867
|
/**
|
|
1692
1868
|
* Process-wide ceiling on children ALIVE at once.
|
|
1693
1869
|
*
|
|
@@ -1718,14 +1894,14 @@ function bestEffortRuntimeWarnings(runtime, agentConfig, excludeTools) {
|
|
|
1718
1894
|
...agentConfig.skills?.length || agentConfig.skillPath?.length ? ["skills"] : [],
|
|
1719
1895
|
...agentConfig.extensions !== void 0 || agentConfig.subagentOnlyExtensions?.length ? ["extensions"] : []
|
|
1720
1896
|
];
|
|
1721
|
-
if (unsupportedResources.length > 0) warnings.push(`
|
|
1897
|
+
if (unsupportedResources.length > 0) warnings.push(`Po Team cannot project or enforce configured Pi ${unsupportedResources.join(", ")} on runtime '${runtime}'.`);
|
|
1722
1898
|
if (agentConfig.skills?.length) warnings.push(`Configured skills were not injected: ${agentConfig.skills.join(", ")}.`);
|
|
1723
1899
|
if (excludeTools?.length) warnings.push(`Runtime '${runtime}' cannot enforce Team package tool exclusions; launched best effort for: ${excludeTools.join(", ")}.`);
|
|
1724
1900
|
return warnings;
|
|
1725
1901
|
}
|
|
1726
1902
|
function readWorkflowPreferences(payload) {
|
|
1727
1903
|
if (payload === void 0) return {};
|
|
1728
|
-
const invalid = (detail) => new
|
|
1904
|
+
const invalid = (detail) => new PoTeamExpectedError(ERROR_CODE_INVALID_REQUEST, `WORKFLOW_RUN_CONFIG ${detail}`, false, "Provide a JSON object with optional nonblank subagentModel and recognized subagentThinking.");
|
|
1729
1905
|
let value;
|
|
1730
1906
|
try {
|
|
1731
1907
|
value = JSON.parse(payload);
|
|
@@ -1743,29 +1919,40 @@ function readWorkflowPreferences(payload) {
|
|
|
1743
1919
|
if (preferences.subagentThinking && !THINKING_LEVELS.some((level) => level === preferences.subagentThinking)) throw invalid(`subagentThinking must be one of: ${THINKING_LEVELS.join(", ")}.`);
|
|
1744
1920
|
return preferences;
|
|
1745
1921
|
}
|
|
1746
|
-
function resolvedModelSelection(taskInput, agentConfig, runtime, parentModel, availableModels, teamPackageModels, preferences) {
|
|
1922
|
+
function resolvedModelSelection(taskInput, agentConfig, runtime, parentModel, availableModels, teamPackageModels, preferences, planning = {}, teamThinking) {
|
|
1747
1923
|
const parentModelId = isPiRuntime(runtime) && parentModel ? `${parentModel.provider}/${parentModel.id}` : void 0;
|
|
1748
1924
|
const agentModels = [...agentConfig.modelSource?.scope === "package" ? [] : [agentConfig.model], ...agentConfig.fallbackModels ?? []];
|
|
1749
1925
|
const candidates = (isPiRuntime(runtime) ? [
|
|
1750
1926
|
taskInput.model,
|
|
1751
1927
|
preferences.subagentModel,
|
|
1928
|
+
planning.subagentModel,
|
|
1752
1929
|
...agentModels,
|
|
1753
1930
|
...teamPackageModels ?? [],
|
|
1754
1931
|
parentModelId
|
|
1755
1932
|
] : [
|
|
1756
1933
|
taskInput.model,
|
|
1757
1934
|
preferences.subagentModel,
|
|
1935
|
+
planning.subagentModel,
|
|
1758
1936
|
...agentModels,
|
|
1759
1937
|
...teamPackageModels ?? []
|
|
1760
1938
|
]).filter((candidate) => Boolean(candidate?.trim()));
|
|
1761
1939
|
const [primaryModel, ...fallbackModels] = candidates;
|
|
1762
1940
|
const agentThinking = typeof agentConfig.thinking === "string" ? agentConfig.thinking : void 0;
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
thinking: agentThinking
|
|
1941
|
+
const teamThinkingFor = (model) => {
|
|
1942
|
+
if (agentConfig.thinking === false || !teamThinking) return void 0;
|
|
1943
|
+
const info = findModelInfo(model, availableModels);
|
|
1944
|
+
return info && !getSupportedThinkingLevels(info).some((level) => level === teamThinking) ? void 0 : teamThinking;
|
|
1768
1945
|
};
|
|
1946
|
+
if (!preferences.subagentModel && !preferences.subagentThinking && !planning.subagentModel && !planning.subagentThinking) {
|
|
1947
|
+
const model = selectAvailableModel(primaryModel, fallbackModels, availableModels);
|
|
1948
|
+
const selectedSuffix = model ? splitKnownThinkingSuffix(model).thinkingSuffix.slice(1) : void 0;
|
|
1949
|
+
return {
|
|
1950
|
+
primaryModel,
|
|
1951
|
+
fallbackModels,
|
|
1952
|
+
model,
|
|
1953
|
+
thinking: agentThinking ?? (selectedSuffix || void 0) ?? teamThinkingFor(model)
|
|
1954
|
+
};
|
|
1955
|
+
}
|
|
1769
1956
|
let model;
|
|
1770
1957
|
let selectedCandidate;
|
|
1771
1958
|
for (const candidate of candidates) {
|
|
@@ -1777,11 +1964,13 @@ function resolvedModelSelection(taskInput, agentConfig, runtime, parentModel, av
|
|
|
1777
1964
|
}
|
|
1778
1965
|
const selectedSuffix = model ? splitKnownThinkingSuffix(model).thinkingSuffix.slice(1) : void 0;
|
|
1779
1966
|
const explicitThinking = selectedCandidate === taskInput.model ? selectedSuffix : void 0;
|
|
1780
|
-
const
|
|
1781
|
-
const
|
|
1967
|
+
const planningThinking = !planning.subagentModel || selectedCandidate === planning.subagentModel ? planning.subagentThinking : void 0;
|
|
1968
|
+
const preferredThinking = (!preferences.subagentModel || selectedCandidate === preferences.subagentModel || selectedCandidate === taskInput.model ? preferences.subagentThinking : void 0) || planningThinking;
|
|
1969
|
+
const thinking = explicitThinking || preferredThinking || selectedSuffix || agentThinking || teamThinkingFor(model);
|
|
1970
|
+
const workflowThinking = !explicitThinking && (preferredThinking || selectedCandidate === preferences.subagentModel && selectedSuffix);
|
|
1782
1971
|
const modelInfo = findModelInfo(model, availableModels);
|
|
1783
|
-
if (isPiRuntime(runtime) && workflowThinking && modelInfo && !getSupportedThinkingLevels(modelInfo).some((level) => level === thinking)) throw new
|
|
1784
|
-
if (model && selectedSuffix && !explicitThinking &&
|
|
1972
|
+
if (isPiRuntime(runtime) && workflowThinking && modelInfo && !getSupportedThinkingLevels(modelInfo).some((level) => level === thinking)) throw new PoTeamExpectedError(ERROR_CODE_INVALID_REQUEST, `Subagent thinking '${thinking}' is unsupported by model '${modelInfo.fullId}'.`, false, `Choose a supported thinking level: ${getSupportedThinkingLevels(modelInfo).join(", ")}.`);
|
|
1973
|
+
if (model && selectedSuffix && !explicitThinking && preferredThinking) model = splitKnownThinkingSuffix(model).baseModel;
|
|
1785
1974
|
return {
|
|
1786
1975
|
primaryModel,
|
|
1787
1976
|
fallbackModels,
|
|
@@ -1807,7 +1996,8 @@ var SpawnPlanner = class {
|
|
|
1807
1996
|
nativeRuns;
|
|
1808
1997
|
teamChannel;
|
|
1809
1998
|
environment;
|
|
1810
|
-
|
|
1999
|
+
agentConfig;
|
|
2000
|
+
constructor(agents, spawner, policies = new require_capabilityCeiling.SubagentCapabilityPolicyStore(), skills, reportConcurrencyEvent, _mcpToolResolver, admission, childSessions, nativeRuns, teamChannel, environment = {}, agentConfig) {
|
|
1811
2001
|
this.agents = agents;
|
|
1812
2002
|
this.spawner = spawner;
|
|
1813
2003
|
this.policies = policies;
|
|
@@ -1818,6 +2008,7 @@ var SpawnPlanner = class {
|
|
|
1818
2008
|
this.nativeRuns = nativeRuns;
|
|
1819
2009
|
this.teamChannel = teamChannel;
|
|
1820
2010
|
this.environment = environment;
|
|
2011
|
+
this.agentConfig = agentConfig;
|
|
1821
2012
|
}
|
|
1822
2013
|
generateRunId() {
|
|
1823
2014
|
return crypto.randomUUID();
|
|
@@ -1827,15 +2018,9 @@ var SpawnPlanner = class {
|
|
|
1827
2018
|
try {
|
|
1828
2019
|
stat = node_fs.statSync(cwd);
|
|
1829
2020
|
} catch {
|
|
1830
|
-
throw new
|
|
2021
|
+
throw new PoTeamExpectedError(ERROR_CODE_INVALID_REQUEST, `Working directory '${cwd}' does not exist.`, false, "Retry with an existing directory.");
|
|
1831
2022
|
}
|
|
1832
|
-
if (!stat.isDirectory()) throw new
|
|
1833
|
-
}
|
|
1834
|
-
resolveTeamPackageExcludeTools() {
|
|
1835
|
-
return require_agentDiscovery.resolveActiveTeamPackageConfig()?.config.excludeTools;
|
|
1836
|
-
}
|
|
1837
|
-
resolveTeamPackageModels() {
|
|
1838
|
-
return require_agentDiscovery.resolveActiveTeamModelSpecs();
|
|
2023
|
+
if (!stat.isDirectory()) throw new PoTeamExpectedError(ERROR_CODE_INVALID_REQUEST, `Working directory '${cwd}' is not a directory.`, false, "Retry with an existing directory.");
|
|
1839
2024
|
}
|
|
1840
2025
|
executableAvailable(command) {
|
|
1841
2026
|
if (node_path.isAbsolute(command) || command.includes(node_path.sep)) try {
|
|
@@ -1855,17 +2040,17 @@ var SpawnPlanner = class {
|
|
|
1855
2040
|
}
|
|
1856
2041
|
resolveTaskList(request) {
|
|
1857
2042
|
const hasSingle = request.single !== void 0;
|
|
1858
|
-
if (hasSingle === (request.tasks !== void 0)) throw new
|
|
2043
|
+
if (hasSingle === (request.tasks !== void 0)) throw new PoTeamExpectedError(ERROR_CODE_INVALID_REQUEST, "A run requires exactly one of internal single or tasks representations.", false, "Submit a non-empty requests array.");
|
|
1859
2044
|
if (hasSingle) return [request.single];
|
|
1860
|
-
if (!request.tasks || request.tasks.length === 0) throw new
|
|
2045
|
+
if (!request.tasks || request.tasks.length === 0) throw new PoTeamExpectedError(ERROR_CODE_INVALID_REQUEST, "A run requires at least one entry in its requests collection.", false, "Submit a non-empty requests array.");
|
|
1861
2046
|
return request.tasks;
|
|
1862
2047
|
}
|
|
1863
|
-
resolveAgentOrThrow(name, cwd, scope) {
|
|
1864
|
-
const resolved = this.agents.find(cwd, scope, name);
|
|
1865
|
-
if (!resolved) throw new
|
|
2048
|
+
async resolveAgentOrThrow(name, cwd, scope) {
|
|
2049
|
+
const resolved = await this.agents.find(cwd, scope, name);
|
|
2050
|
+
if (!resolved) throw new PoTeamExpectedError(ERROR_CODE_AGENT_NOT_FOUND, `Unknown agent '${name}'.`, false, "Call subagent({\"action\":\"agents\"}) and retry with an exact name.");
|
|
1866
2051
|
return resolved;
|
|
1867
2052
|
}
|
|
1868
|
-
resolveExecutableAgent(taskInput, cwd, scope) {
|
|
2053
|
+
async resolveExecutableAgent(taskInput, cwd, scope) {
|
|
1869
2054
|
if (!taskInput.inlineAgent) return this.resolveAgentOrThrow(taskInput.agent, cwd, scope);
|
|
1870
2055
|
return {
|
|
1871
2056
|
name: taskInput.agent.trim(),
|
|
@@ -1959,12 +2144,12 @@ var SpawnPlanner = class {
|
|
|
1959
2144
|
* the module header.
|
|
1960
2145
|
*/
|
|
1961
2146
|
async spawnOneChild(input) {
|
|
1962
|
-
const { runId, operationId, agentConfig, identity, capabilityCeiling, excludeTools, teamPackageModels, workflowPreferences, taskInput, childIndex, fanout, fallbackCwd, parentSessionId, parentForkSource, sessionScope, environment, parentSessionFile, maxLiveRuns, admissionTimeoutMs, handshakeTimeoutMs, artifacts, artifactDir, availableModels, parentModel, runtime, runtimes, skillProjectionCache } = input;
|
|
2147
|
+
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;
|
|
1963
2148
|
const cwd = taskInput.cwd ?? fallbackCwd;
|
|
1964
2149
|
const task = taskInput.task ?? "";
|
|
1965
2150
|
const effectiveContext = resolveEffectiveContext(taskInput, agentConfig);
|
|
1966
2151
|
const effectiveRuntime = taskInput.runtime ?? runtime ?? agentConfig.runtime ?? "pi";
|
|
1967
|
-
const modelSelection = resolvedModelSelection(taskInput, agentConfig, effectiveRuntime, parentModel, availableModels, teamPackageModels, workflowPreferences);
|
|
2152
|
+
const modelSelection = resolvedModelSelection(taskInput, agentConfig, effectiveRuntime, parentModel, availableModels, teamPackageModels, workflowPreferences, planningPreferences, teamThinking);
|
|
1968
2153
|
if (modelSelection.primaryModel && availableModels !== void 0 && !modelSelection.model) return {
|
|
1969
2154
|
agent: agentConfig.name,
|
|
1970
2155
|
identity: identity.identity,
|
|
@@ -1986,7 +2171,11 @@ var SpawnPlanner = class {
|
|
|
1986
2171
|
error: error instanceof Error ? error.message : String(error)
|
|
1987
2172
|
};
|
|
1988
2173
|
}
|
|
1989
|
-
const warnings = [
|
|
2174
|
+
const warnings = [
|
|
2175
|
+
...modelSelection.primaryModel && modelSelection.model && !selectAvailableModel(modelSelection.primaryModel, [], availableModels) ? [`[fallback] ${modelSelection.primaryModel} is unavailable. Using ${modelSelection.model}.`] : [],
|
|
2176
|
+
...skillProjection.warnings,
|
|
2177
|
+
...bestEffortRuntimeWarnings(effectiveRuntime, agentConfig, excludeTools)
|
|
2178
|
+
];
|
|
1990
2179
|
const warning = warnings.length > 0 ? warnings.join(" ") : void 0;
|
|
1991
2180
|
const spawnInput = {
|
|
1992
2181
|
runId,
|
|
@@ -2001,7 +2190,6 @@ var SpawnPlanner = class {
|
|
|
2001
2190
|
sessionScope,
|
|
2002
2191
|
...parentSessionFile ? { parentSessionFile } : {},
|
|
2003
2192
|
piArgs: {
|
|
2004
|
-
...taskInput.sessionFile ? { sessionFile: taskInput.sessionFile } : {},
|
|
2005
2193
|
...modelSelection.model ? { model: modelSelection.model } : {},
|
|
2006
2194
|
...capabilityCeiling ? { capabilityCeiling } : {},
|
|
2007
2195
|
...effectiveContext === CONTEXT_FORK && parentSessionId ? { parentSessionId } : {}
|
|
@@ -2013,7 +2201,7 @@ var SpawnPlanner = class {
|
|
|
2013
2201
|
runtimes
|
|
2014
2202
|
};
|
|
2015
2203
|
const admission = this.admission;
|
|
2016
|
-
if (!admission) throw new Error("
|
|
2204
|
+
if (!admission) throw new Error("Po Team spawn admission is not configured.");
|
|
2017
2205
|
let ticket;
|
|
2018
2206
|
try {
|
|
2019
2207
|
ticket = await admission.admit({
|
|
@@ -2035,11 +2223,8 @@ var SpawnPlanner = class {
|
|
|
2035
2223
|
if (isPiRuntime(effectiveRuntime)) {
|
|
2036
2224
|
if (!this.nativeRuns || !this.childSessions?.get()) throw new Error("The native Team run coordinator is unavailable.");
|
|
2037
2225
|
const scope = sessionScope;
|
|
2038
|
-
const source =
|
|
2039
|
-
|
|
2040
|
-
sessionFile: taskInput.sessionFile
|
|
2041
|
-
} : effectiveContext === CONTEXT_FORK ? parentForkSource ?? (() => {
|
|
2042
|
-
throw new Error("Native fork input requires an immutable terminal Pi snapshot.");
|
|
2226
|
+
const source = effectiveContext === CONTEXT_FORK ? parentForkSource ?? (() => {
|
|
2227
|
+
throw new Error("Native fork input requires the parent session's branch.");
|
|
2043
2228
|
})() : { kind: "fresh" };
|
|
2044
2229
|
const intercom = this.teamChannel?.createNativeChildIntercom({
|
|
2045
2230
|
rootSessionId: scope.rootSessionId,
|
|
@@ -2062,6 +2247,8 @@ var SpawnPlanner = class {
|
|
|
2062
2247
|
source,
|
|
2063
2248
|
agent: agentConfig.name,
|
|
2064
2249
|
task,
|
|
2250
|
+
...warning ? { meta: { warning } } : {},
|
|
2251
|
+
sender: sender ?? MAIN_AGENT_SENDER,
|
|
2065
2252
|
cwd,
|
|
2066
2253
|
...modelSelection.model ? { model: modelSelection.model } : {},
|
|
2067
2254
|
...typeof modelSelection.thinking === "string" ? { thinking: modelSelection.thinking } : {},
|
|
@@ -2078,7 +2265,9 @@ var SpawnPlanner = class {
|
|
|
2078
2265
|
environment
|
|
2079
2266
|
}, {
|
|
2080
2267
|
identity: identity.identity,
|
|
2081
|
-
inline: identity.inline
|
|
2268
|
+
inline: identity.inline,
|
|
2269
|
+
...agentConfig.description ? { agentDescription: agentConfig.description } : {},
|
|
2270
|
+
...agentConfig.filePath ? { agentFilePath: agentConfig.filePath } : {}
|
|
2082
2271
|
});
|
|
2083
2272
|
} catch (error) {
|
|
2084
2273
|
intercom?.dispose?.();
|
|
@@ -2120,71 +2309,67 @@ var SpawnPlanner = class {
|
|
|
2120
2309
|
}
|
|
2121
2310
|
}
|
|
2122
2311
|
async spawn(request, config) {
|
|
2312
|
+
if (!this.agentConfig) throw new PoTeamExpectedError("runtime_unavailable", "Team agent configuration is not loaded yet.", true, "Retry after the session configuration is ready.");
|
|
2313
|
+
const team = await this.agentConfig.current();
|
|
2123
2314
|
const tasks = this.resolveTaskList(request);
|
|
2124
2315
|
const workflowPreferences = readWorkflowPreferences(request.environment?.WORKFLOW_RUN_CONFIG ?? this.environment.WORKFLOW_RUN_CONFIG);
|
|
2316
|
+
const planningConfig = request.parentSelection?.state?.["minor-mode"]?.includes("plan") ? team.planningSubagents : void 0;
|
|
2317
|
+
const planningPreferences = {
|
|
2318
|
+
subagentModel: planningConfig?.model,
|
|
2319
|
+
subagentThinking: planningConfig?.thinking
|
|
2320
|
+
};
|
|
2125
2321
|
const fanout = tasks.length > 1;
|
|
2126
|
-
const teamPackageExcludeTools =
|
|
2127
|
-
const teamPackageModels =
|
|
2322
|
+
const teamPackageExcludeTools = team.excludeTools ? [...team.excludeTools] : void 0;
|
|
2323
|
+
const teamPackageModels = team.models;
|
|
2128
2324
|
const capabilityCeiling = this.policies.resolve();
|
|
2129
2325
|
const depthCheck = preflightSubagentDepth(request.currentDepth ?? resolveCurrentSubagentDepth(), config);
|
|
2130
|
-
if (depthCheck.error) throw new
|
|
2326
|
+
if (depthCheck.error) throw new PoTeamExpectedError(ERROR_CODE_UNSUPPORTED_OPERATION, depthCheck.error, false, "Give each child a self-contained task within the Team package policy.");
|
|
2131
2327
|
const maxTasks = config.parallel?.maxTasks ?? DEFAULT_PARALLEL_MAX_TASKS;
|
|
2132
|
-
if (tasks.length > maxTasks) throw new
|
|
2328
|
+
if (tasks.length > maxTasks) throw new PoTeamExpectedError(ERROR_CODE_INVALID_REQUEST, `Run requested ${tasks.length} tasks, but at most ${maxTasks} may be declared in one call. Concurrency throttles how fast they start, not how many run.`, false, "Send at most that many requests in this call and wait for them, or raise parallel.maxTasks in the subagent config. Splitting the same width across extra calls does not raise the live-child ceiling.");
|
|
2133
2329
|
for (const taskInput of tasks) {
|
|
2134
|
-
if (!taskInput.task?.trim()) throw new
|
|
2135
|
-
if (taskInput.inlineAgent && !taskInput.inlineAgent.systemPrompt.trim()) throw new
|
|
2330
|
+
if (!taskInput.task?.trim()) throw new PoTeamExpectedError(ERROR_CODE_INVALID_REQUEST, `Run request for '${taskInput.agent}' requires a nonblank task.`, false, "Provide a self-contained nonblank task.");
|
|
2331
|
+
if (taskInput.inlineAgent && !taskInput.inlineAgent.systemPrompt.trim()) throw new PoTeamExpectedError(ERROR_CODE_INVALID_REQUEST, `Inline agent '${taskInput.agent}' requires a nonblank system prompt.`, false, "Provide a focused read-only exploration role.");
|
|
2136
2332
|
}
|
|
2137
2333
|
const resolvedAgentCache = /* @__PURE__ */ new Map();
|
|
2138
|
-
const resolvedAgents =
|
|
2139
|
-
|
|
2334
|
+
const resolvedAgents = [];
|
|
2335
|
+
for (const taskInput of tasks) {
|
|
2140
2336
|
const cacheKey = [
|
|
2141
2337
|
request.agentScope,
|
|
2142
2338
|
require_agentDiscovery.canonicalizeDiscoveryCwd(taskInput.cwd ?? request.cwd),
|
|
2143
2339
|
taskInput.agent
|
|
2144
2340
|
].join("\0");
|
|
2145
|
-
|
|
2146
|
-
if (
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2341
|
+
let resolved = taskInput.inlineAgent ? void 0 : resolvedAgentCache.get(cacheKey);
|
|
2342
|
+
if (!resolved) {
|
|
2343
|
+
resolved = await this.resolveExecutableAgent(taskInput, taskInput.cwd ?? request.cwd, request.agentScope);
|
|
2344
|
+
if (!taskInput.inlineAgent) resolvedAgentCache.set(cacheKey, resolved);
|
|
2345
|
+
}
|
|
2346
|
+
resolvedAgents.push(resolved);
|
|
2347
|
+
}
|
|
2151
2348
|
for (const [index, taskInput] of tasks.entries()) {
|
|
2152
2349
|
const effectiveContext = resolveEffectiveContext(taskInput, resolvedAgents[index]);
|
|
2153
2350
|
const runtime = taskInput.runtime ?? request.runtime ?? resolvedAgents[index].runtime ?? "pi";
|
|
2154
2351
|
if (effectiveContext === CONTEXT_FORK) {
|
|
2155
|
-
if (!isPiRuntime(runtime)) throw new
|
|
2156
|
-
if (!request.parentForkSource) throw new
|
|
2352
|
+
if (!isPiRuntime(runtime)) throw new PoTeamExpectedError(ERROR_CODE_UNSUPPORTED_CONTEXT, `Fork context requires ${PI_RUNTIME_REQUIREMENT} for '${taskInput.agent}'.`, false, "Use a Pi agent for fork context or explicitly request a fresh run.");
|
|
2353
|
+
if (!request.parentForkSource) throw new PoTeamExpectedError(ERROR_CODE_UNSUPPORTED_CONTEXT, `Fork context is unavailable for '${taskInput.agent}': ${describeForkFailure(request.parentForkFailure)}.`, false, "Use an active Pi session with a completed parent turn or explicitly request a fresh run.");
|
|
2157
2354
|
}
|
|
2158
2355
|
}
|
|
2159
|
-
if (request.preallocatedRunIds && request.preallocatedRunIds.length !== tasks.length) throw new
|
|
2356
|
+
if (request.preallocatedRunIds && request.preallocatedRunIds.length !== tasks.length) throw new PoTeamExpectedError(ERROR_CODE_OPERATION_CONFLICT, "The operation journal run-id count does not match the request count.", false, "Submit the run as a new tool call.");
|
|
2160
2357
|
const runIds = request.preallocatedRunIds ?? tasks.map(() => this.generateRunId());
|
|
2161
|
-
const identities = tasks.map((taskInput, index) => {
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
runId: runIds[index]
|
|
2167
|
-
});
|
|
2168
|
-
adoptAgentIdentity(request.sessionScope, taskInput.identity, runIds[index]);
|
|
2169
|
-
return {
|
|
2170
|
-
identity: taskInput.identity,
|
|
2171
|
-
name: "",
|
|
2172
|
-
role: roleFromAgent(resolvedAgents[index].name),
|
|
2173
|
-
number: 0,
|
|
2174
|
-
inline,
|
|
2175
|
-
persisted: true
|
|
2176
|
-
};
|
|
2177
|
-
});
|
|
2358
|
+
const identities = tasks.map((taskInput, index) => claimAgentIdentity(request.sessionScope, {
|
|
2359
|
+
agent: resolvedAgents[index].name,
|
|
2360
|
+
inline: taskInput.inlineAgent !== void 0,
|
|
2361
|
+
runId: runIds[index]
|
|
2362
|
+
}));
|
|
2178
2363
|
const runtimes = resolveRuntimeTable(config.runtimes);
|
|
2179
2364
|
for (const [index, taskInput] of tasks.entries()) {
|
|
2180
2365
|
const agent = resolvedAgents[index];
|
|
2181
2366
|
const cwd = taskInput.cwd ?? request.cwd;
|
|
2182
2367
|
this.validateCwd(cwd);
|
|
2183
2368
|
const runtime = taskInput.runtime ?? request.runtime ?? agent.runtime ?? "pi";
|
|
2184
|
-
const modelSelection = resolvedModelSelection(taskInput, agent, runtime, request.parentModel, request.availableModels, teamPackageModels, workflowPreferences);
|
|
2185
|
-
if (modelSelection.primaryModel && request.availableModels !== void 0 && !modelSelection.model) throw new
|
|
2186
|
-
if (taskInput.inlineAgent && !isPiRuntime(runtime)) throw new
|
|
2187
|
-
if (capabilityCeiling && !isPiRuntime(runtime)) throw new
|
|
2369
|
+
const modelSelection = resolvedModelSelection(taskInput, agent, runtime, request.parentModel, request.availableModels, teamPackageModels, workflowPreferences, planningPreferences, team.thinking);
|
|
2370
|
+
if (modelSelection.primaryModel && request.availableModels !== void 0 && !modelSelection.model) throw new PoTeamExpectedError(ERROR_CODE_MODEL_UNAVAILABLE, `No authenticated model is available for '${agent.name}'.`, false, "Authenticate the requested model or choose an available model.");
|
|
2371
|
+
if (taskInput.inlineAgent && !isPiRuntime(runtime)) throw new PoTeamExpectedError(ERROR_CODE_UNSUPPORTED_OPERATION, `Inline agent '${taskInput.agent}' requires ${PI_RUNTIME_REQUIREMENT} to enforce its read-only tools.`, false, "Remove the runtime override or use a discovered external-runtime agent without inlineAgent.");
|
|
2372
|
+
if (capabilityCeiling && !isPiRuntime(runtime)) throw new PoTeamExpectedError(ERROR_CODE_UNSUPPORTED_OPERATION, `Runtime '${runtime}' cannot enforce the active capability ceiling.`, false, `Use ${PI_RUNTIME_REQUIREMENT} while plan mode or another capability ceiling is active.`);
|
|
2188
2373
|
if (!isPiRuntime(runtime)) {
|
|
2189
2374
|
let command;
|
|
2190
2375
|
try {
|
|
@@ -2193,9 +2378,9 @@ var SpawnPlanner = class {
|
|
|
2193
2378
|
cwd
|
|
2194
2379
|
}).command;
|
|
2195
2380
|
} catch (error) {
|
|
2196
|
-
throw new
|
|
2381
|
+
throw new PoTeamExpectedError(ERROR_CODE_RUNTIME_UNAVAILABLE, error instanceof Error ? error.message : String(error), false, `Configure a valid external runtime or use ${PI_RUNTIME_REQUIREMENT}.`);
|
|
2197
2382
|
}
|
|
2198
|
-
if (!this.executableAvailable(command)) throw new
|
|
2383
|
+
if (!this.executableAvailable(command)) throw new PoTeamExpectedError(ERROR_CODE_RUNTIME_UNAVAILABLE, `Executable '${command}' for runtime '${runtime}' is unavailable.`, false, `Install the executable, configure its absolute path, or use ${PI_RUNTIME_REQUIREMENT}.`);
|
|
2199
2384
|
}
|
|
2200
2385
|
}
|
|
2201
2386
|
const concurrency = fanout ? request.concurrency ?? config.parallel?.concurrency ?? DEFAULT_PARALLEL_CONCURRENCY : 1;
|
|
@@ -2209,7 +2394,9 @@ var SpawnPlanner = class {
|
|
|
2209
2394
|
identity: identities[childIndex],
|
|
2210
2395
|
excludeTools: teamPackageExcludeTools,
|
|
2211
2396
|
teamPackageModels,
|
|
2397
|
+
teamThinking: team.thinking,
|
|
2212
2398
|
workflowPreferences,
|
|
2399
|
+
planningPreferences,
|
|
2213
2400
|
capabilityCeiling,
|
|
2214
2401
|
taskInput,
|
|
2215
2402
|
childIndex,
|
|
@@ -2218,6 +2405,7 @@ var SpawnPlanner = class {
|
|
|
2218
2405
|
parentSessionId: request.parentSessionId,
|
|
2219
2406
|
parentForkSource: request.parentForkSource,
|
|
2220
2407
|
sessionScope: request.sessionScope,
|
|
2408
|
+
...request.sender ? { sender: request.sender } : {},
|
|
2221
2409
|
environment: request.environment ?? {},
|
|
2222
2410
|
parentSessionFile: request.parentSessionFile,
|
|
2223
2411
|
maxLiveRuns,
|
|
@@ -2243,7 +2431,7 @@ var SpawnPlanner = class {
|
|
|
2243
2431
|
//#endregion
|
|
2244
2432
|
//#region src/services/delegationBridge/index.ts
|
|
2245
2433
|
/**
|
|
2246
|
-
* Serves `
|
|
2434
|
+
* Serves `po-task` through Team's session-bound delegation service: turn a
|
|
2247
2435
|
* request into a spawned run, report its progress, and settle it exactly once.
|
|
2248
2436
|
*
|
|
2249
2437
|
* WHY THIS IS NOT IN `pi.ts`:
|
|
@@ -2273,7 +2461,7 @@ const DELEGATION_PROGRESS_INTERVAL_MS = 250;
|
|
|
2273
2461
|
const SETTLED_DELEGATION_WINDOW = 256;
|
|
2274
2462
|
/**
|
|
2275
2463
|
* Terminal states, named because they are an external contract with
|
|
2276
|
-
* `
|
|
2464
|
+
* `po-task`'s `DelegationManager`, which branches on the exact strings.
|
|
2277
2465
|
*/
|
|
2278
2466
|
const STATUS_COMPLETED = "completed";
|
|
2279
2467
|
const STATUS_CANCELLED = "cancelled";
|
|
@@ -2295,7 +2483,7 @@ function createDelegationBridge(deps) {
|
|
|
2295
2483
|
entry.disposeProgress?.();
|
|
2296
2484
|
active.delete(entry.requestId);
|
|
2297
2485
|
rememberSettled(entry.requestId);
|
|
2298
|
-
ctx.emit(_agimon_ai_po_core_delegation.
|
|
2486
|
+
ctx.emit(_agimon_ai_po_core_delegation.PO_DELEGATION_FINISHED_EVENT, result);
|
|
2299
2487
|
};
|
|
2300
2488
|
/** Ask the run to stop. Returns the failure message when the request itself failed. */
|
|
2301
2489
|
const stop = (entry, reason) => {
|
|
@@ -2326,7 +2514,13 @@ function createDelegationBridge(deps) {
|
|
|
2326
2514
|
timeoutWarningSent = true;
|
|
2327
2515
|
const secondsRemaining = Math.max(1, Math.ceil(warningLeadMs / 1e3));
|
|
2328
2516
|
const secondsLabel = `${secondsRemaining} second${secondsRemaining === 1 ? "" : "s"}`;
|
|
2329
|
-
deps.management.steer(runId,
|
|
2517
|
+
deps.management.steer(runId, {
|
|
2518
|
+
text: `This delegation will time out in about ${secondsLabel}. Stop exploring now, complete the highest-value remaining work, and return a concise result before the deadline. If you cannot finish, return verified findings and blockers immediately.`,
|
|
2519
|
+
sender: {
|
|
2520
|
+
kind: "system",
|
|
2521
|
+
name: "Po"
|
|
2522
|
+
}
|
|
2523
|
+
}).catch(() => void 0);
|
|
2330
2524
|
worked = true;
|
|
2331
2525
|
}
|
|
2332
2526
|
const progressKey = [
|
|
@@ -2339,7 +2533,7 @@ function createDelegationBridge(deps) {
|
|
|
2339
2533
|
].map((value) => String(value)).join(":");
|
|
2340
2534
|
if (progressKey === lastProgress) return worked;
|
|
2341
2535
|
lastProgress = progressKey;
|
|
2342
|
-
ctx.emit(_agimon_ai_po_core_delegation.
|
|
2536
|
+
ctx.emit(_agimon_ai_po_core_delegation.PO_DELEGATION_UPDATED_EVENT, {
|
|
2343
2537
|
requestId: entry.requestId,
|
|
2344
2538
|
runId,
|
|
2345
2539
|
...job.status !== void 0 ? { status: job.status } : {},
|
|
@@ -2414,7 +2608,7 @@ function createDelegationBridge(deps) {
|
|
|
2414
2608
|
settled: false
|
|
2415
2609
|
};
|
|
2416
2610
|
active.set(request.requestId, entry);
|
|
2417
|
-
ctx.emit(_agimon_ai_po_core_delegation.
|
|
2611
|
+
ctx.emit(_agimon_ai_po_core_delegation.PO_DELEGATION_ACCEPTED_EVENT, { requestId: request.requestId });
|
|
2418
2612
|
try {
|
|
2419
2613
|
const forkSource = await session.captureForkSource?.();
|
|
2420
2614
|
const outcome = (await deps.planner.spawn({
|
|
@@ -2429,8 +2623,10 @@ function createDelegationBridge(deps) {
|
|
|
2429
2623
|
agentScope: "both",
|
|
2430
2624
|
sessionScope: session.sessionScope,
|
|
2431
2625
|
parentSessionId: session.sessionId,
|
|
2626
|
+
parentSelection: session.parentSelection,
|
|
2627
|
+
environment: session.environment,
|
|
2432
2628
|
...forkRequestFields(forkSource),
|
|
2433
|
-
availableModels: session.availableModels,
|
|
2629
|
+
availableModels: await session.availableModels(),
|
|
2434
2630
|
...session.parentModel ? { parentModel: session.parentModel } : {}
|
|
2435
2631
|
}, deps.loadConfig())).outcomes[0];
|
|
2436
2632
|
if (!outcome?.runId) {
|
|
@@ -2453,10 +2649,15 @@ function createDelegationBridge(deps) {
|
|
|
2453
2649
|
return;
|
|
2454
2650
|
}
|
|
2455
2651
|
entry.runtimeStartedAt = Date.now();
|
|
2456
|
-
ctx.emit(_agimon_ai_po_core_delegation.
|
|
2652
|
+
ctx.emit(_agimon_ai_po_core_delegation.PO_DELEGATION_STARTED_EVENT, {
|
|
2457
2653
|
requestId: request.requestId,
|
|
2458
2654
|
runId: outcome.runId
|
|
2459
2655
|
});
|
|
2656
|
+
if (outcome.warning) try {
|
|
2657
|
+
await session.reportWarning?.(outcome.warning);
|
|
2658
|
+
} catch (error) {
|
|
2659
|
+
process.emitWarning(`Delegation warning could not be delivered: ${error instanceof Error ? error.message : String(error)}`);
|
|
2660
|
+
}
|
|
2460
2661
|
await monitor(entry, request, ctx, jobs, session.sessionId, session.sessionScope);
|
|
2461
2662
|
} catch (error) {
|
|
2462
2663
|
finish(entry, {
|
|
@@ -2484,15 +2685,15 @@ function createDelegationBridge(deps) {
|
|
|
2484
2685
|
createService(ctx, session) {
|
|
2485
2686
|
const service = {
|
|
2486
2687
|
sessionId: session.sessionId,
|
|
2487
|
-
generation: `
|
|
2688
|
+
generation: `po-delegation:${crypto.randomUUID()}`,
|
|
2488
2689
|
async request(request) {
|
|
2489
2690
|
if (!(0, typebox_value.Check)(_agimon_ai_po_core_delegation.DelegationRequestSchema, request)) throw new TypeError("Invalid delegation request.");
|
|
2490
|
-
ctx.emit(_agimon_ai_po_core_delegation.
|
|
2691
|
+
ctx.emit(_agimon_ai_po_core_delegation.PO_DELEGATION_REQUESTED_EVENT, request);
|
|
2491
2692
|
await onRequested(request, ctx, session);
|
|
2492
2693
|
},
|
|
2493
2694
|
cancel(request) {
|
|
2494
2695
|
if (!(0, typebox_value.Check)(_agimon_ai_po_core_delegation.DelegationCancelSchema, request)) throw new TypeError("Invalid delegation cancel request.");
|
|
2495
|
-
ctx.emit(_agimon_ai_po_core_delegation.
|
|
2696
|
+
ctx.emit(_agimon_ai_po_core_delegation.PO_DELEGATION_CANCELLED_EVENT, request);
|
|
2496
2697
|
onCancelled(request.requestId, request.reason, ctx);
|
|
2497
2698
|
}
|
|
2498
2699
|
};
|
|
@@ -2541,7 +2742,7 @@ var SpawnHandshake = class {
|
|
|
2541
2742
|
resolve(outcome);
|
|
2542
2743
|
};
|
|
2543
2744
|
removeMessage = options.child.onMessage((raw) => {
|
|
2544
|
-
const message =
|
|
2745
|
+
const message = require_atomicJson.parseExternalRunnerMessage(raw, {
|
|
2545
2746
|
runId: options.runId,
|
|
2546
2747
|
scopeKey: options.scopeKey
|
|
2547
2748
|
});
|
|
@@ -2580,7 +2781,7 @@ const FABLE_PROFILE_RESULT_FILE_NAME = "fable-profile-result.json";
|
|
|
2580
2781
|
const DEFAULT_HANDSHAKE_TIMEOUT_MS = 1e4;
|
|
2581
2782
|
/** `runs/<runId>` under the explicit session scope. */
|
|
2582
2783
|
function runDirFor(scope, runId) {
|
|
2583
|
-
return node_path.join(
|
|
2784
|
+
return node_path.join(require_atomicJson.scopeRunsDir(scope), runId);
|
|
2584
2785
|
}
|
|
2585
2786
|
function fableProfileResultPathFor(scope, runId) {
|
|
2586
2787
|
return node_path.join(runDirFor(scope, runId), FABLE_PROFILE_RESULT_FILE_NAME);
|
|
@@ -2595,10 +2796,10 @@ function resolveRunnerEntry(builtRelativePath, sourceRelativePath, stem) {
|
|
|
2595
2796
|
if (node_fs.existsSync(builtCandidate)) return builtCandidate;
|
|
2596
2797
|
const sourceCandidate = node_path.join(directory, "src", `${sourceRelativePath}.ts`);
|
|
2597
2798
|
if (node_fs.existsSync(sourceCandidate)) return sourceCandidate;
|
|
2598
|
-
throw new Error(`
|
|
2799
|
+
throw new Error(`Po Team runner '${stem}' is unavailable at '${builtCandidate}' or '${sourceCandidate}'.`);
|
|
2599
2800
|
}
|
|
2600
2801
|
const parent = node_path.dirname(directory);
|
|
2601
|
-
if (parent === directory) throw new Error(`Could not locate the
|
|
2802
|
+
if (parent === directory) throw new Error(`Could not locate the Po Team package root for runner '${stem}'.`);
|
|
2602
2803
|
directory = parent;
|
|
2603
2804
|
}
|
|
2604
2805
|
}
|
|
@@ -2653,7 +2854,7 @@ var AsyncSubagentSpawner = class {
|
|
|
2653
2854
|
}
|
|
2654
2855
|
child.unref();
|
|
2655
2856
|
child.channel?.unref();
|
|
2656
|
-
const endpoint =
|
|
2857
|
+
const endpoint = require_atomicJson.childProcessEndpoint(child);
|
|
2657
2858
|
return {
|
|
2658
2859
|
pid: child.pid,
|
|
2659
2860
|
onError: (handler) => child.on("error", handler),
|
|
@@ -2676,23 +2877,23 @@ var AsyncSubagentSpawner = class {
|
|
|
2676
2877
|
const runDir = runDirFor(scope, runId);
|
|
2677
2878
|
const env = {
|
|
2678
2879
|
...input.environment,
|
|
2679
|
-
...
|
|
2880
|
+
...require_atomicJson.sessionScopeEnvironment(scope),
|
|
2680
2881
|
[require_environment.SUBAGENT_RUN_ID_ENV]: runId
|
|
2681
2882
|
};
|
|
2682
2883
|
let fableLaunch;
|
|
2683
2884
|
let launchConfig;
|
|
2684
2885
|
const fail = (message) => {
|
|
2685
|
-
if (fableLaunch)
|
|
2886
|
+
if (fableLaunch) require_atomicJson.cleanupClaudeFableLaunch(fableLaunch);
|
|
2686
2887
|
node_fs.rmSync(fableProfileResultPathFor(scope, runId), { force: true });
|
|
2687
2888
|
throw new Error(message);
|
|
2688
2889
|
};
|
|
2689
2890
|
const ceiling = input.piArgs.capabilityCeiling;
|
|
2690
2891
|
if (ceiling && (!input.externalProfile || !(ceiling.allowedExternalProfiles ?? []).includes(input.externalProfile))) return fail(`External profile '${input.externalProfile ?? "none"}' is denied by the active capability ceiling.`);
|
|
2691
|
-
if (input.externalProfile !== void 0 && input.externalProfile !==
|
|
2692
|
-
if (input.externalProfile ===
|
|
2892
|
+
if (input.externalProfile !== void 0 && input.externalProfile !== require_atomicJson.CLAUDE_FABLE_PROFILE) return fail(`External profile '${input.externalProfile}' is not trusted.`);
|
|
2893
|
+
if (input.externalProfile === require_atomicJson.CLAUDE_FABLE_PROFILE) {
|
|
2693
2894
|
if (runtime !== "claude" || input.piArgs.model !== "fable") return fail("The Fable profile requires runtime claude and model fable.");
|
|
2694
2895
|
if (input.inlineAgent || input.piArgs.sessionFile || input.piArgs.parentSessionId) return fail("The Fable profile requires a fresh isolated context.");
|
|
2695
|
-
fableLaunch =
|
|
2896
|
+
fableLaunch = require_atomicJson.prepareClaudeFableLaunch({
|
|
2696
2897
|
runId,
|
|
2697
2898
|
prompt: task,
|
|
2698
2899
|
repositoryCwd: cwd,
|
|
@@ -2713,7 +2914,7 @@ var AsyncSubagentSpawner = class {
|
|
|
2713
2914
|
stdinPath: fableLaunch.stdinPath,
|
|
2714
2915
|
cleanupPaths: fableLaunch.cleanupPaths,
|
|
2715
2916
|
profileResultPath: fableProfileResultPathFor(scope, runId),
|
|
2716
|
-
resultPath: node_path.join(
|
|
2917
|
+
resultPath: node_path.join(require_atomicJson.scopeResultsDir(scope), `${runId}.json`),
|
|
2717
2918
|
internal: input.internal === true
|
|
2718
2919
|
};
|
|
2719
2920
|
} else launchConfig = {
|
|
@@ -2729,7 +2930,7 @@ var AsyncSubagentSpawner = class {
|
|
|
2729
2930
|
}),
|
|
2730
2931
|
cwd,
|
|
2731
2932
|
env: Object.fromEntries(Object.entries(env).filter((entry) => typeof entry[1] === "string")),
|
|
2732
|
-
resultPath: node_path.join(
|
|
2933
|
+
resultPath: node_path.join(require_atomicJson.scopeResultsDir(scope), `${runId}.json`),
|
|
2733
2934
|
internal: input.internal === true
|
|
2734
2935
|
};
|
|
2735
2936
|
const child = this.spawnChild(scope, process.execPath, [resolveCliRunnerEntry()], {
|
|
@@ -2795,8 +2996,8 @@ const FABLE_STAGE = {
|
|
|
2795
2996
|
interrupted: "interrupted"
|
|
2796
2997
|
};
|
|
2797
2998
|
const FABLE_EVENT = {
|
|
2798
|
-
stageStarted: "
|
|
2799
|
-
finished: "
|
|
2999
|
+
stageStarted: "po_team.fable_stage_started",
|
|
3000
|
+
finished: "po_team.fable_finished"
|
|
2800
3001
|
};
|
|
2801
3002
|
const SESSION_ENDED_REASON = "Fable bridge session ended.";
|
|
2802
3003
|
const FABLE_ERROR = {
|
|
@@ -2986,7 +3187,7 @@ function createFablePlanBridge(deps) {
|
|
|
2986
3187
|
return Object.freeze({
|
|
2987
3188
|
...provider,
|
|
2988
3189
|
sessionId: session.sessionId,
|
|
2989
|
-
generation: `
|
|
3190
|
+
generation: `po-fable-plan:${crypto.randomUUID()}`
|
|
2990
3191
|
});
|
|
2991
3192
|
},
|
|
2992
3193
|
abandonAll() {
|
|
@@ -3174,7 +3375,7 @@ function parseTeamToolParams(raw) {
|
|
|
3174
3375
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) throw invalidRequest("Intercom params must be an object.", "Use one documented intercom action shape.");
|
|
3175
3376
|
const params = raw;
|
|
3176
3377
|
const action = TEAM_ACTIONS.find((candidate) => candidate === params.action);
|
|
3177
|
-
if (!action) throw new
|
|
3378
|
+
if (!action) throw new PoTeamExpectedError("unsupported_operation", `Unsupported intercom action: ${String(params.action)}.`, false, "Use members, send, ask, pending, or reply.");
|
|
3178
3379
|
if (!isOptionalString(params.to) || !isOptionalString(params.message) || !isOptionalString(params.requestId)) throw invalidRequest("Intercom to, message and requestId values must be strings.", "Correct the action fields and retry.");
|
|
3179
3380
|
const allowed = new Set(action === "members" || action === "pending" ? ["action"] : action === "reply" ? [
|
|
3180
3381
|
"action",
|
|
@@ -3287,7 +3488,14 @@ var NativeTeamDirectChannel = class {
|
|
|
3287
3488
|
bindRuntime: (runtime) => {
|
|
3288
3489
|
const member = this.members.get(memberId);
|
|
3289
3490
|
if (!member || disposed) throw new Error(`Native team member '${memberId}' is no longer active.`);
|
|
3290
|
-
member.deliver = (
|
|
3491
|
+
member.deliver = ({ content, details: { from } }) => runtime.steer({
|
|
3492
|
+
text: content,
|
|
3493
|
+
sender: from.role === "main" ? MAIN_AGENT_SENDER : {
|
|
3494
|
+
kind: "agent",
|
|
3495
|
+
id: from.runId ?? from.name,
|
|
3496
|
+
name: from.name
|
|
3497
|
+
}
|
|
3498
|
+
});
|
|
3291
3499
|
return {
|
|
3292
3500
|
name: NATIVE_TEAM_TOOL_NAME,
|
|
3293
3501
|
description: "Communicate with active native agents in this root session.",
|
|
@@ -3385,7 +3593,7 @@ var NativeTeamDirectChannel = class {
|
|
|
3385
3593
|
if (params.action === "reply") {
|
|
3386
3594
|
const request = this.asks.get(params.requestId ?? "");
|
|
3387
3595
|
const asker = request && this.members.get(request.fromMemberId);
|
|
3388
|
-
if (!request || request.toMemberId !== memberId || !asker) throw new
|
|
3596
|
+
if (!request || request.toMemberId !== memberId || !asker) throw new PoTeamExpectedError("recipient_not_found", `No open intercom ask matches requestId '${params.requestId}'. It may already be answered, or its asker has finished.`, false, "Call intercom({\"action\":\"pending\"}) and retry with an exact requestId, or continue without replying.");
|
|
3389
3597
|
await this.deliver(asker, formatDirectMessage(member.context, "reply", request.id, message));
|
|
3390
3598
|
this.closeAsk(request);
|
|
3391
3599
|
return {
|
|
@@ -3400,7 +3608,7 @@ var NativeTeamDirectChannel = class {
|
|
|
3400
3608
|
};
|
|
3401
3609
|
}
|
|
3402
3610
|
const target = this.findMember(params.to);
|
|
3403
|
-
if (!target) throw new
|
|
3611
|
+
if (!target) throw new PoTeamExpectedError("recipient_not_found", `Active intercom member '${params.to}' was not found.`, true, "Call intercom({\"action\":\"members\"}) and retry with an active member id.");
|
|
3404
3612
|
const messageId = operationMessageId(memberId, operationId);
|
|
3405
3613
|
const isAsk = params.action === "ask";
|
|
3406
3614
|
const result = () => ({
|
|
@@ -3470,15 +3678,15 @@ var NativeTeamDirectChannel = class {
|
|
|
3470
3678
|
}
|
|
3471
3679
|
async deliver(target, message) {
|
|
3472
3680
|
const id = target.context.memberId;
|
|
3473
|
-
if (this.members.get(id) !== target) throw new
|
|
3474
|
-
if (!target.deliver) throw new
|
|
3681
|
+
if (this.members.get(id) !== target) throw new PoTeamExpectedError("communication_unavailable", `Intercom member '${id}' has finished.`, false, "Call intercom({\"action\":\"members\"}) to see who is active.");
|
|
3682
|
+
if (!target.deliver) throw new PoTeamExpectedError("communication_unavailable", `Intercom member '${id}' is not ready.`, true, "Retry after the child session starts.");
|
|
3475
3683
|
target.inFlight += 1;
|
|
3476
3684
|
try {
|
|
3477
3685
|
await target.deliver(message);
|
|
3478
3686
|
target.delivered = true;
|
|
3479
3687
|
} catch (error) {
|
|
3480
|
-
if (error instanceof
|
|
3481
|
-
throw new
|
|
3688
|
+
if (error instanceof PoTeamExpectedError) throw error;
|
|
3689
|
+
throw new PoTeamExpectedError("communication_unavailable", `Intercom member '${id}' could not receive the message: ${error instanceof Error ? error.message : String(error)}`, true, "Retry shortly, or continue without it.");
|
|
3482
3690
|
} finally {
|
|
3483
3691
|
target.inFlight -= 1;
|
|
3484
3692
|
target.release?.(true);
|
|
@@ -3505,7 +3713,7 @@ var TeamChannelRuntime = class {
|
|
|
3505
3713
|
}
|
|
3506
3714
|
execute(operationId, rawParams) {
|
|
3507
3715
|
const context = this.context;
|
|
3508
|
-
if (!context || !this.directChannel) throw new
|
|
3716
|
+
if (!context || !this.directChannel) throw new PoTeamExpectedError("communication_unavailable", "Intercom is not active for this session.", true, "Wait for session startup or reload Po Team.");
|
|
3509
3717
|
return this.directChannel.execute(context.memberId, operationId, rawParams);
|
|
3510
3718
|
}
|
|
3511
3719
|
bindMainSession(rootSessionId) {
|
|
@@ -3562,51 +3770,80 @@ var NativeTeamChannelService = class {
|
|
|
3562
3770
|
};
|
|
3563
3771
|
//#endregion
|
|
3564
3772
|
//#region src/services/headlessIntercomTool/index.ts
|
|
3773
|
+
/**
|
|
3774
|
+
* Finds the peer a `to` value names: its session ID first, then its session
|
|
3775
|
+
* name, ignoring case, so an agent can use the name a person typed. A name two
|
|
3776
|
+
* peers share is refused with their IDs rather than guessed.
|
|
3777
|
+
*/
|
|
3778
|
+
function resolvePeer(peers, to) {
|
|
3779
|
+
const byId = peers.find((peer) => peer.sessionId === to);
|
|
3780
|
+
if (byId !== void 0) return byId;
|
|
3781
|
+
const wanted = to.toLowerCase();
|
|
3782
|
+
const named = peers.filter((peer) => peer.name.trim().toLowerCase() === wanted);
|
|
3783
|
+
if (named.length > 1) throw invalidRequest(`${String(named.length)} sessions are named "${to}".`, `Send to one session ID: ${named.map((peer) => peer.sessionId).join(", ")}.`);
|
|
3784
|
+
return named[0];
|
|
3785
|
+
}
|
|
3786
|
+
function describePeerLine(peer) {
|
|
3787
|
+
const details = [
|
|
3788
|
+
`session ${peer.sessionId}`,
|
|
3789
|
+
...peer.profile === void 0 ? [] : [`profile ${peer.profile}`],
|
|
3790
|
+
...peer.sharedGroups.length === 0 ? [] : [`shared groups: ${peer.sharedGroups.join(", ")}`]
|
|
3791
|
+
];
|
|
3792
|
+
return `- ${peer.name.trim() === "" ? peer.sessionId : peer.name} (${details.join("; ")}): use send; it can reply to you the same way`;
|
|
3793
|
+
}
|
|
3565
3794
|
function createHeadlessIntercomTool(channel, sessions) {
|
|
3566
3795
|
return {
|
|
3567
3796
|
name: "intercom",
|
|
3568
3797
|
label: "Intercom",
|
|
3569
3798
|
description: "Communicate with active agents and related live sessions.",
|
|
3570
3799
|
parameters: TeamToolParamsSchema,
|
|
3571
|
-
promptGuidelines: ["Send only new progress, blockers, or decisions. Do not repeat task briefs or delegation instructions.", "Use members to find related sessions
|
|
3800
|
+
promptGuidelines: ["Send only new progress, blockers, or decisions. Do not repeat task briefs or delegation instructions.", "Use members to find related sessions by the names people give them, then send to that name or its session ID. Session peers use send, not ask/reply, and can send back."],
|
|
3572
3801
|
executionMode: "serial",
|
|
3573
3802
|
async execute(toolCallId, parameters, signal, onUpdate) {
|
|
3574
3803
|
const params = parseTeamToolParams(parameters);
|
|
3575
3804
|
const peers = channel.current() === void 0 ? [] : sessions?.peers() ?? [];
|
|
3576
3805
|
const to = params.to?.trim();
|
|
3577
|
-
|
|
3578
|
-
|
|
3806
|
+
const knownId = channel.current() !== void 0 && to !== void 0 && sessions?.canCommunicate(to) === true;
|
|
3807
|
+
const teamMember = to !== void 0 && channel.snapshot().members.some((member) => member.name === to) && !knownId && !peers.some((peer) => peer.sessionId === to);
|
|
3808
|
+
const peer = sessions === void 0 || to === void 0 || teamMember ? void 0 : knownId ? peers.find((candidate) => candidate.sessionId === to) : resolvePeer(peers, to);
|
|
3809
|
+
const recipientId = knownId ? to : peer?.sessionId;
|
|
3810
|
+
if (sessions !== void 0 && recipientId !== void 0) {
|
|
3811
|
+
if (params.action !== "send") throw invalidRequest("Session peers support send only.", "Use send with the session name or ID.");
|
|
3579
3812
|
const message = validateMessage(params.message);
|
|
3580
3813
|
const delivery = sessions.delivery();
|
|
3581
3814
|
if (delivery === void 0) throw new Error("Session delivery is unavailable.");
|
|
3815
|
+
const senderName = sessions.name?.()?.trim() || sessions.sessionId;
|
|
3816
|
+
const toName = peer?.name.trim() || recipientId;
|
|
3582
3817
|
const receipt = await delivery.deliver({
|
|
3583
3818
|
deliveryId: `intercom:${sessions.sessionId}:${toolCallId}`,
|
|
3584
|
-
recipientKey:
|
|
3819
|
+
recipientKey: recipientId,
|
|
3585
3820
|
kind: "intercom_message",
|
|
3586
|
-
prompt: `Message from session ${
|
|
3821
|
+
prompt: `Message from session ${senderName} via intercom.\n\n${message}\n\nReply using intercom({ action: "send", to: ${JSON.stringify(senderName)}, message: "..." }).`,
|
|
3587
3822
|
delivery: "steer"
|
|
3588
3823
|
});
|
|
3589
3824
|
return {
|
|
3590
3825
|
content: [{
|
|
3591
3826
|
type: "text",
|
|
3592
|
-
text: `Message queued for session ${
|
|
3827
|
+
text: `Message queued for session ${toName}.`
|
|
3593
3828
|
}],
|
|
3594
3829
|
details: {
|
|
3595
3830
|
...receipt,
|
|
3596
|
-
to
|
|
3831
|
+
to: recipientId,
|
|
3832
|
+
toName
|
|
3597
3833
|
}
|
|
3598
3834
|
};
|
|
3599
3835
|
}
|
|
3600
|
-
const result = (0, _agimon_ai_po_core_headless.
|
|
3836
|
+
const result = (0, _agimon_ai_po_core_headless.toPoHeadlessToolResult)(await channel.execute(toolCallId, parameters, signal, onUpdate && ((partial) => onUpdate((0, _agimon_ai_po_core_headless.toPoHeadlessToolResult)(partial)))));
|
|
3601
3837
|
if (params.action !== "members" || peers.length === 0) return result;
|
|
3602
3838
|
return {
|
|
3603
3839
|
...result,
|
|
3604
3840
|
content: [...result.content, {
|
|
3605
3841
|
type: "text",
|
|
3606
|
-
text: peers.map(
|
|
3842
|
+
text: peers.map(describePeerLine).join("\n")
|
|
3607
3843
|
}],
|
|
3608
|
-
details: { members: [...channel.snapshot().members, ...peers.map((
|
|
3609
|
-
name:
|
|
3844
|
+
details: { members: [...channel.snapshot().members, ...peers.map((peer) => ({
|
|
3845
|
+
name: peer.name || peer.sessionId,
|
|
3846
|
+
sessionId: peer.sessionId,
|
|
3610
3847
|
role: "session"
|
|
3611
3848
|
}))] }
|
|
3612
3849
|
};
|
|
@@ -3728,6 +3965,7 @@ var AsyncJobTracker = class {
|
|
|
3728
3965
|
startedAt: projection.startedAt,
|
|
3729
3966
|
updatedAt: projection.updatedAt,
|
|
3730
3967
|
...projection.error === void 0 ? {} : { error: projection.error },
|
|
3968
|
+
...projection.promptWithheld ? { promptWithheld: true } : {},
|
|
3731
3969
|
...projection.summary === void 0 ? {} : { summary: projection.summary },
|
|
3732
3970
|
...projection.tokens === void 0 ? {} : { tokens: projection.tokens },
|
|
3733
3971
|
...projection.cost === void 0 ? {} : { cost: projection.cost },
|
|
@@ -3939,7 +4177,7 @@ function formatDuration(ms) {
|
|
|
3939
4177
|
*/
|
|
3940
4178
|
const MAX_RETAINED_EVENTS = 1e3;
|
|
3941
4179
|
const NEWLINE_BYTE = 10;
|
|
3942
|
-
function isRecord$
|
|
4180
|
+
function isRecord$2(value) {
|
|
3943
4181
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3944
4182
|
}
|
|
3945
4183
|
function parseLine(line) {
|
|
@@ -3947,7 +4185,7 @@ function parseLine(line) {
|
|
|
3947
4185
|
if (!trimmed) return void 0;
|
|
3948
4186
|
try {
|
|
3949
4187
|
const parsed = JSON.parse(trimmed);
|
|
3950
|
-
return isRecord$
|
|
4188
|
+
return isRecord$2(parsed) ? parsed : void 0;
|
|
3951
4189
|
} catch {
|
|
3952
4190
|
return;
|
|
3953
4191
|
}
|
|
@@ -3982,7 +4220,7 @@ function parseArgsPayload(payload) {
|
|
|
3982
4220
|
if (!payload) return void 0;
|
|
3983
4221
|
try {
|
|
3984
4222
|
const parsed = JSON.parse(payload);
|
|
3985
|
-
return isRecord$
|
|
4223
|
+
return isRecord$2(parsed) ? parsed : void 0;
|
|
3986
4224
|
} catch {
|
|
3987
4225
|
return;
|
|
3988
4226
|
}
|
|
@@ -4177,125 +4415,63 @@ function readFleetTranscript(transcriptPath) {
|
|
|
4177
4415
|
warning: tail.warning
|
|
4178
4416
|
} : { events: tail.events };
|
|
4179
4417
|
}
|
|
4180
|
-
|
|
4181
|
-
|
|
4418
|
+
function contentText(content) {
|
|
4419
|
+
if (typeof content === "string") return content;
|
|
4420
|
+
if (!Array.isArray(content)) return "";
|
|
4421
|
+
return content.flatMap((part) => isRecord$2(part) && part.type === "text" && typeof part.text === "string" ? [part.text] : []).join("\n");
|
|
4422
|
+
}
|
|
4182
4423
|
/**
|
|
4183
|
-
*
|
|
4184
|
-
*
|
|
4185
|
-
* WHY EVERY SHUTDOWN SUSPENDS, WITH NO SPECIAL CASE FOR `reload`:
|
|
4186
|
-
* Pi emits `session_shutdown` for `quit`, `reload`, `new`, `resume` and `fork`.
|
|
4187
|
-
* An earlier design kept children alive across `reload` alone, on the grounds
|
|
4188
|
-
* that `/domains`, `/major-mode` and `/profile` reload the extension rather than
|
|
4189
|
-
* change the session. That is true, and it still makes `reload` the one case
|
|
4190
|
-
* behaving differently from the other four - which is a rule someone has to
|
|
4191
|
-
* remember, and a branch that silently does the wrong thing if Pi ever adds a
|
|
4192
|
-
* sixth reason. Suspending uniformly costs a respawn on reload and removes the
|
|
4193
|
-
* special case; restore is cheap because the child continues its own transcript
|
|
4194
|
-
* rather than starting over.
|
|
4195
|
-
*
|
|
4196
|
-
* WHY RESTORE IS OFFERED AND NEVER AUTOMATIC:
|
|
4197
|
-
* Reopening a session would otherwise spawn N processes and start spending
|
|
4198
|
-
* tokens on tasks that may be days stale. `session_start` reports what is
|
|
4199
|
-
* suspended; something explicit has to ask for it back.
|
|
4200
|
-
*
|
|
4201
|
-
* AVOID:
|
|
4202
|
-
* - Auto-restoring from any lifecycle event
|
|
4203
|
-
* - Recording a suspended run without its `sessionFile`; without it a restore
|
|
4204
|
-
* restarts the work instead of continuing it
|
|
4424
|
+
* Events of a native run's durable transcript page, so a native run renders through the same tail as a file
|
|
4425
|
+
* transcript. Entries are projected messages: `{ type: 'message', timestamp, message }` with Pi message roles.
|
|
4205
4426
|
*/
|
|
4206
|
-
|
|
4207
|
-
const
|
|
4208
|
-
|
|
4209
|
-
return node_path.join(require_externalProcessIpc.scopeSuspendedDir(scope), `${runId}${JSON_SUFFIX}`);
|
|
4210
|
-
}
|
|
4211
|
-
function suspendRun(scope, record) {
|
|
4212
|
-
require_atomicJson.writeAtomicJson(suspendedPath(scope, record.runId), {
|
|
4213
|
-
version: SUSPENDED_RUN_VERSION,
|
|
4214
|
-
...record
|
|
4215
|
-
});
|
|
4216
|
-
}
|
|
4217
|
-
function parseSuspendedRun(raw) {
|
|
4218
|
-
let parsed;
|
|
4219
|
-
try {
|
|
4220
|
-
parsed = JSON.parse(raw);
|
|
4221
|
-
} catch {
|
|
4222
|
-
return;
|
|
4223
|
-
}
|
|
4224
|
-
const result = parseVersioned(parsed, [SUSPENDED_RUN_VERSION]);
|
|
4225
|
-
return result.ok && typeof result.value.runId === "string" ? result.value : void 0;
|
|
4226
|
-
}
|
|
4227
|
-
function listSuspendedRuns(scope) {
|
|
4228
|
-
let entries;
|
|
4229
|
-
try {
|
|
4230
|
-
entries = node_fs.readdirSync(require_externalProcessIpc.scopeSuspendedDir(scope));
|
|
4231
|
-
} catch {
|
|
4232
|
-
return [];
|
|
4233
|
-
}
|
|
4234
|
-
const runs = [];
|
|
4427
|
+
function fleetEventsFromEntries(entries) {
|
|
4428
|
+
const events = [];
|
|
4429
|
+
const calls = /* @__PURE__ */ new Map();
|
|
4235
4430
|
for (const entry of entries) {
|
|
4236
|
-
if (!entry.
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4431
|
+
if (!isRecord$2(entry) || entry.type !== "message" || !isRecord$2(entry.message)) continue;
|
|
4432
|
+
const message = entry.message;
|
|
4433
|
+
const at = typeof entry.timestamp === "number" ? entry.timestamp : 0;
|
|
4434
|
+
if (message.role === "user") {
|
|
4435
|
+
const text = contentText(message.content);
|
|
4436
|
+
if (text.trim()) events.push({
|
|
4437
|
+
kind: "user",
|
|
4438
|
+
at,
|
|
4439
|
+
text
|
|
4440
|
+
});
|
|
4441
|
+
} else if (message.role === "assistant") {
|
|
4442
|
+
const parts = splitAssistantContent(message.content);
|
|
4443
|
+
for (const thinking of parts?.thinking ?? []) events.push({
|
|
4444
|
+
kind: "thinking",
|
|
4445
|
+
at,
|
|
4446
|
+
text: thinking
|
|
4447
|
+
});
|
|
4448
|
+
if (parts?.text.trim()) events.push({
|
|
4449
|
+
kind: "assistant",
|
|
4450
|
+
at,
|
|
4451
|
+
text: parts.text,
|
|
4452
|
+
...typeof message.model === "string" ? { model: message.model } : {}
|
|
4453
|
+
});
|
|
4454
|
+
for (const part of Array.isArray(message.content) ? message.content : []) {
|
|
4455
|
+
if (!isRecord$2(part) || part.type !== "toolCall" || typeof part.id !== "string") continue;
|
|
4456
|
+
const event = {
|
|
4457
|
+
kind: "tool",
|
|
4458
|
+
at,
|
|
4459
|
+
text: "",
|
|
4460
|
+
...typeof part.name === "string" ? { name: part.name } : {},
|
|
4461
|
+
status: "running",
|
|
4462
|
+
...isRecord$2(part.arguments) ? { args: part.arguments } : {}
|
|
4463
|
+
};
|
|
4464
|
+
calls.set(part.id, event);
|
|
4465
|
+
events.push(event);
|
|
4466
|
+
}
|
|
4467
|
+
} else if (message.role === "toolResult" && typeof message.toolCallId === "string") {
|
|
4468
|
+
const call = calls.get(message.toolCallId);
|
|
4469
|
+
if (!call) continue;
|
|
4470
|
+
call.result = contentText(message.content);
|
|
4471
|
+
call.status = message.isError === true ? "error" : "ok";
|
|
4242
4472
|
}
|
|
4243
|
-
if (run) runs.push(run);
|
|
4244
|
-
}
|
|
4245
|
-
return runs.sort((left, right) => left.suspendedAt - right.suspendedAt);
|
|
4246
|
-
}
|
|
4247
|
-
async function listSuspendedRunsAsync(scope) {
|
|
4248
|
-
let entries;
|
|
4249
|
-
try {
|
|
4250
|
-
entries = await node_fs.promises.readdir(require_externalProcessIpc.scopeSuspendedDir(scope));
|
|
4251
|
-
} catch {
|
|
4252
|
-
return [];
|
|
4253
|
-
}
|
|
4254
|
-
const runs = [];
|
|
4255
|
-
for (const entry of entries) {
|
|
4256
|
-
if (!entry.endsWith(JSON_SUFFIX)) continue;
|
|
4257
|
-
try {
|
|
4258
|
-
const run = parseSuspendedRun(await node_fs.promises.readFile(node_path.join(require_externalProcessIpc.scopeSuspendedDir(scope), entry), "utf-8"));
|
|
4259
|
-
if (run) runs.push(run);
|
|
4260
|
-
} catch {}
|
|
4261
|
-
}
|
|
4262
|
-
return runs.sort((left, right) => left.suspendedAt - right.suspendedAt);
|
|
4263
|
-
}
|
|
4264
|
-
/** Drop a record once its run has been restored, or explicitly discarded. */
|
|
4265
|
-
function clearSuspendedRun(scope, runId) {
|
|
4266
|
-
try {
|
|
4267
|
-
node_fs.rmSync(suspendedPath(scope, runId), { force: true });
|
|
4268
|
-
} catch {}
|
|
4269
|
-
}
|
|
4270
|
-
/** Whether an explicit restore can safely continue this exact run. */
|
|
4271
|
-
function isSuspendedRunResumable(run) {
|
|
4272
|
-
if (run.runtime !== "pi" || !run.agent.trim() || !run.task.trim() || !run.cwd.trim() || !run.sessionFile) return false;
|
|
4273
|
-
try {
|
|
4274
|
-
node_fs.accessSync(run.sessionFile, node_fs.constants.R_OK);
|
|
4275
|
-
return true;
|
|
4276
|
-
} catch {
|
|
4277
|
-
return false;
|
|
4278
4473
|
}
|
|
4279
|
-
|
|
4280
|
-
/** The identity prefix for a suspended line, empty for a record written before identities existed. */
|
|
4281
|
-
function suspendedLabel(run) {
|
|
4282
|
-
const label = formatAgentIdentity(run.identity, run.inline);
|
|
4283
|
-
return label ? `${label}, ` : "";
|
|
4284
|
-
}
|
|
4285
|
-
/** One line per suspended run, for the report `session_start` prints. */
|
|
4286
|
-
function formatSuspendedRuns(runs) {
|
|
4287
|
-
if (runs.length === 0) return "";
|
|
4288
|
-
const lines = runs.map((run) => {
|
|
4289
|
-
const continues = isSuspendedRunResumable(run) ? "resumable" : "not resumable";
|
|
4290
|
-
return `- ${run.runId} (${suspendedLabel(run)}${run.agent}, ${run.runtime}, ${continues}): ${run.task.split("\n")[0]}`;
|
|
4291
|
-
});
|
|
4292
|
-
const noun = runs.length === 1 ? "subagent" : "subagents";
|
|
4293
|
-
return [
|
|
4294
|
-
`${runs.length} suspended ${noun} from this session:`,
|
|
4295
|
-
...lines,
|
|
4296
|
-
"",
|
|
4297
|
-
"They are stopped. Restore one with subagent {\"action\":\"restore\",\"id\":\"<run-id>\"}, or leave them."
|
|
4298
|
-
].join("\n");
|
|
4474
|
+
return events;
|
|
4299
4475
|
}
|
|
4300
4476
|
function age(job, now) {
|
|
4301
4477
|
return job.startedAt ? formatDuration(Math.max(0, now - job.startedAt)) : "unknown";
|
|
@@ -4306,8 +4482,8 @@ function age(job, now) {
|
|
|
4306
4482
|
* Takes `now` rather than calling `Date.now()` so a test asserting rendered
|
|
4307
4483
|
* ages does not have to freeze global time.
|
|
4308
4484
|
*/
|
|
4309
|
-
function formatFleetView(jobs, now = Date.now()
|
|
4310
|
-
if (jobs.length === 0
|
|
4485
|
+
function formatFleetView(jobs, now = Date.now()) {
|
|
4486
|
+
if (jobs.length === 0) return "No runs tracked in this session. A run appears here once it has been launched from this session.";
|
|
4311
4487
|
const lines = [`${jobs.length} active run${jobs.length === 1 ? "" : "s"}:`];
|
|
4312
4488
|
for (const job of jobs) {
|
|
4313
4489
|
const parts = [`- ${job.runId}`];
|
|
@@ -4318,18 +4494,8 @@ function formatFleetView(jobs, now = Date.now(), suspended = []) {
|
|
|
4318
4494
|
if (job.error) parts.push(`error: ${job.error}`);
|
|
4319
4495
|
lines.push(parts.join(" · "));
|
|
4320
4496
|
}
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
for (const run of suspended) {
|
|
4324
|
-
const recovery = isSuspendedRunResumable(run) ? `restore with { action: "restore", id: "${run.runId}" }` : "not resumable; submit a new explicit run";
|
|
4325
|
-
const label = formatAgentIdentity(run.identity, run.inline);
|
|
4326
|
-
lines.push(`- ${run.runId} (${label ? `${label}, ` : ""}${run.agent}, ${run.runtime}): ${recovery}`);
|
|
4327
|
-
}
|
|
4328
|
-
}
|
|
4329
|
-
if (jobs.length > 0) {
|
|
4330
|
-
lines.push("");
|
|
4331
|
-
lines.push(`Inspect one with { action: "status", id: "<run id>", transcriptLines: 80 }.`);
|
|
4332
|
-
}
|
|
4497
|
+
lines.push("");
|
|
4498
|
+
lines.push(`Inspect one with { action: "status", id: "<run id>", transcriptLines: 80 }.`);
|
|
4333
4499
|
return lines.join("\n");
|
|
4334
4500
|
}
|
|
4335
4501
|
/** Tool output shown to the model, bounded so one long result cannot crowd out the rest of the tail. */
|
|
@@ -4362,11 +4528,25 @@ function formatEvent(event) {
|
|
|
4362
4528
|
*/
|
|
4363
4529
|
function formatRunTranscript(status, maxLines) {
|
|
4364
4530
|
const transcriptPath = status?.transcriptPath;
|
|
4365
|
-
if (!transcriptPath) return status ? "This run has no transcript
|
|
4531
|
+
if (!transcriptPath) return status ? "This run has no transcript to read." : "No status found for this run, so there is no transcript to read.";
|
|
4366
4532
|
const transcript = readFleetTranscript(transcriptPath);
|
|
4367
4533
|
if (transcript.warning) return `Transcript at '${transcriptPath}' could not be read: ${transcript.warning}`;
|
|
4368
4534
|
if (transcript.events.length === 0) return `Transcript at '${transcriptPath}' is empty. The run has not written anything yet.`;
|
|
4369
|
-
|
|
4535
|
+
return formatTail(transcript.events, maxLines);
|
|
4536
|
+
}
|
|
4537
|
+
/**
|
|
4538
|
+
* A native run's transcript tail, read from its durable conversation rather than a file.
|
|
4539
|
+
*
|
|
4540
|
+
* ponytail: `entries` is one page of the newest entries, so the "of N lines" count covers that page, not the
|
|
4541
|
+
* whole run; read older pages first if a caller needs the full count.
|
|
4542
|
+
*/
|
|
4543
|
+
function formatNativeRunTranscript(entries, maxLines) {
|
|
4544
|
+
const events = fleetEventsFromEntries(entries);
|
|
4545
|
+
if (events.length === 0) return "The run has no transcript entries yet.";
|
|
4546
|
+
return formatTail(events, maxLines);
|
|
4547
|
+
}
|
|
4548
|
+
function formatTail(events, maxLines) {
|
|
4549
|
+
const rendered = events.flatMap((event) => formatEvent(event).split("\n"));
|
|
4370
4550
|
const kept = rendered.slice(-maxLines);
|
|
4371
4551
|
const dropped = rendered.length - kept.length;
|
|
4372
4552
|
return [
|
|
@@ -4384,7 +4564,7 @@ function hashArguments(args) {
|
|
|
4384
4564
|
}
|
|
4385
4565
|
function journalPath(scope, operationId) {
|
|
4386
4566
|
const safeId = (0, node_crypto.createHash)(HASH_ALGORITHM).update(operationId).digest(HASH_ENCODING);
|
|
4387
|
-
return node_path.join(
|
|
4567
|
+
return node_path.join(require_atomicJson.scopeRunsDir(scope), "..", "operations", `${safeId}.json`);
|
|
4388
4568
|
}
|
|
4389
4569
|
function readRecord(file) {
|
|
4390
4570
|
return JSON.parse(node_fs.readFileSync(file, "utf8"));
|
|
@@ -4414,7 +4594,7 @@ function startOperation(scope, operationId, args, runIds) {
|
|
|
4414
4594
|
} catch (error) {
|
|
4415
4595
|
if (!(error instanceof Error && "code" in error && error.code === "EEXIST")) throw error;
|
|
4416
4596
|
const existing = readRecord(file);
|
|
4417
|
-
if (existing.argumentHash !== argumentHash) throw new
|
|
4597
|
+
if (existing.argumentHash !== argumentHash) throw new PoTeamExpectedError("operation_conflict", `Operation '${operationId}' was already used with different arguments.`, false, "Submit the operation as a new tool call.");
|
|
4418
4598
|
return {
|
|
4419
4599
|
kind: "replay",
|
|
4420
4600
|
record: existing
|
|
@@ -4451,7 +4631,6 @@ function progressMessage(params) {
|
|
|
4451
4631
|
case require_subagentTool.SUBAGENT_ACTIONS.run: return `Starting ${params.requests.length} subagent${params.requests.length === 1 ? "" : "s"}...`;
|
|
4452
4632
|
case require_subagentTool.SUBAGENT_ACTIONS.steer: return `Steering subagent ${params.id}...`;
|
|
4453
4633
|
case require_subagentTool.SUBAGENT_ACTIONS.stop: return `Requesting stop for subagent ${params.id}...`;
|
|
4454
|
-
case require_subagentTool.SUBAGENT_ACTIONS.restore: return `Restoring subagent ${params.id}...`;
|
|
4455
4634
|
default: return;
|
|
4456
4635
|
}
|
|
4457
4636
|
}
|
|
@@ -4479,12 +4658,6 @@ function publicAgent(agent) {
|
|
|
4479
4658
|
...tools.length ? { tools } : {}
|
|
4480
4659
|
};
|
|
4481
4660
|
}
|
|
4482
|
-
function publicSuspendedRun(run) {
|
|
4483
|
-
return {
|
|
4484
|
-
...run,
|
|
4485
|
-
resumable: isSuspendedRunResumable(run)
|
|
4486
|
-
};
|
|
4487
|
-
}
|
|
4488
4661
|
/** One agent in full, as the model reads it. Shared with the headless tool. */
|
|
4489
4662
|
function formatAgentDetail(agent) {
|
|
4490
4663
|
const detail = publicAgent(agent);
|
|
@@ -4514,7 +4687,7 @@ function validateParams(input) {
|
|
|
4514
4687
|
requireNonblank(record, "id", action);
|
|
4515
4688
|
requireNonblank(record, "message", action);
|
|
4516
4689
|
}
|
|
4517
|
-
if (action === require_subagentTool.SUBAGENT_ACTIONS.stop
|
|
4690
|
+
if (action === require_subagentTool.SUBAGENT_ACTIONS.stop) requireNonblank(record, "id", action);
|
|
4518
4691
|
return raw;
|
|
4519
4692
|
}
|
|
4520
4693
|
var SubagentToolService = class {
|
|
@@ -4531,7 +4704,7 @@ var SubagentToolService = class {
|
|
|
4531
4704
|
this.environment = environment;
|
|
4532
4705
|
}
|
|
4533
4706
|
sessionScope(ctx) {
|
|
4534
|
-
return
|
|
4707
|
+
return require_atomicJson.createSessionScope((0, _agimon_ai_po_core_childProcess.resolveRootSessionId)(ctx.sessionManager.getSessionId(), this.environment));
|
|
4535
4708
|
}
|
|
4536
4709
|
trackOutcomes(result, ctx) {
|
|
4537
4710
|
const scope = this.sessionScope(ctx);
|
|
@@ -4579,7 +4752,7 @@ var SubagentToolService = class {
|
|
|
4579
4752
|
const operation = startOperation(scope, operationId, params, params.requests.map(() => (0, node_crypto.randomUUID)()));
|
|
4580
4753
|
if (operation.kind === "replay") {
|
|
4581
4754
|
if (operation.record.state === "completed" && operation.record.result) return operation.record.result;
|
|
4582
|
-
throw new
|
|
4755
|
+
throw new PoTeamExpectedError("delivery_unconfirmed", `Operation '${operationId}' is already pending for runs: ${operation.record.runIds.join(", ")}.`, true, "Call subagent({\"action\":\"status\"}) and do not submit the run again.");
|
|
4583
4756
|
}
|
|
4584
4757
|
const result = this.trackOutcomes(await this.planner.spawn(this.buildSpawnRequest(operationId, params, ctx, operation.record.runIds), loadConfig().config), ctx);
|
|
4585
4758
|
const started = result.outcomes.filter((outcome) => outcome.runId);
|
|
@@ -4587,7 +4760,7 @@ var SubagentToolService = class {
|
|
|
4587
4760
|
const outcomeLines = result.outcomes.map((outcome) => {
|
|
4588
4761
|
return `- ${formatAgentIdentity(outcome.identity, outcome.inline) ?? outcome.agent}: ${outcome.runId ? outcome.runId : `failed: ${outcome.error ?? "unknown error"}`}${outcome.warning ? `\n Warning: ${outcome.warning}` : ""}`;
|
|
4589
4762
|
});
|
|
4590
|
-
if (started.length === 0 && failed.length > 0) throw new
|
|
4763
|
+
if (started.length === 0 && failed.length > 0) throw new PoTeamExpectedError("runtime_unavailable", `No requested subagent started.\n${outcomeLines.join("\n")}`, true, "Correct the reported launch failures. If an agent name is uncertain, call subagent({\"action\":\"agents\"}) before retrying only corrected requests.");
|
|
4591
4764
|
const subagentLabel = result.outcomes.length === 1 ? "subagent" : "subagents";
|
|
4592
4765
|
const summary = failed.length === 0 ? `Started ${started.length} ${subagentLabel}:` : `Started ${started.length}/${result.outcomes.length} ${subagentLabel}; ${failed.length} failed:`;
|
|
4593
4766
|
const next = failed.length === 0 ? "Completion will arrive asynchronously. Continue only non-overlapping work, or end your turn." : "Completion will arrive asynchronously for started runs. Do not resubmit them; retry only corrected failed entries.";
|
|
@@ -4604,44 +4777,35 @@ var SubagentToolService = class {
|
|
|
4604
4777
|
completeOperation(scope, operationId, operation.record, response);
|
|
4605
4778
|
return response;
|
|
4606
4779
|
}
|
|
4607
|
-
executeAgents(params, ctx) {
|
|
4780
|
+
async executeAgents(params, ctx) {
|
|
4608
4781
|
const cwd = params.cwd ?? ctx.cwd;
|
|
4609
4782
|
const scope = scopeOrDefault(params.scope);
|
|
4610
4783
|
if (!params.name) {
|
|
4611
|
-
const result = this.discovery.discover(cwd, scope);
|
|
4784
|
+
const result = await this.discovery.discover(cwd, scope);
|
|
4612
4785
|
return textResult(formatAgentList(result.agents), { agents: result.agents.map(publicAgent) });
|
|
4613
4786
|
}
|
|
4614
|
-
const agent = this.discovery.find(cwd, scope, params.name);
|
|
4787
|
+
const agent = await this.discovery.find(cwd, scope, params.name);
|
|
4615
4788
|
if (!agent) {
|
|
4616
|
-
const candidates = this.discovery.discover(cwd, scope).agents.map((candidate) => candidate.name).toSorted();
|
|
4617
|
-
throw new
|
|
4789
|
+
const candidates = (await this.discovery.discover(cwd, scope)).agents.map((candidate) => candidate.name).toSorted();
|
|
4790
|
+
throw new PoTeamExpectedError("agent_not_found", `No executable agent matches '${params.name}'.${candidates.length ? ` Available: ${candidates.join(", ")}.` : ""}`, false, "Call subagent({\"action\":\"agents\"}) and retry with an exact name.");
|
|
4618
4791
|
}
|
|
4619
4792
|
return textResult(formatAgentDetail(agent), { agent: publicAgent(agent) });
|
|
4620
4793
|
}
|
|
4621
|
-
async executeManagement(params, ctx, signal
|
|
4794
|
+
async executeManagement(params, ctx, signal) {
|
|
4622
4795
|
const scope = this.sessionScope(ctx);
|
|
4623
4796
|
this.management.bindSessionScope(scope);
|
|
4624
4797
|
const jobs = this.tracker.forSession(ctx.sessionManager.getSessionId(), scope);
|
|
4625
4798
|
switch (params.action) {
|
|
4626
4799
|
case require_subagentTool.SUBAGENT_ACTIONS.status: {
|
|
4627
|
-
const suspendedRuns = listSuspendedRuns(scope);
|
|
4628
4800
|
if (!("id" in params)) {
|
|
4629
4801
|
if ("transcriptLines" in params && params.transcriptLines !== void 0) throw invalidRequest("transcriptLines requires a run id.", "Add id or omit transcriptLines for fleet status.");
|
|
4630
4802
|
const runs = jobs.list();
|
|
4631
|
-
return textResult(formatFleetView(runs, Date.now()
|
|
4632
|
-
fleet: runs,
|
|
4633
|
-
suspended: suspendedRuns.map(publicSuspendedRun)
|
|
4634
|
-
});
|
|
4803
|
+
return textResult(formatFleetView(runs, Date.now()), { fleet: runs });
|
|
4635
4804
|
}
|
|
4636
4805
|
const runId = params.id;
|
|
4637
4806
|
if (!runId) throw invalidRequest("transcriptLines requires a run id.", "Add id or omit transcriptLines for fleet status.");
|
|
4638
|
-
const suspended = suspendedRuns.find((run) => run.runId === runId);
|
|
4639
|
-
if (suspended && params.transcriptLines === void 0) {
|
|
4640
|
-
const recovery = isSuspendedRunResumable(suspended) ? `Restore it with { action: "restore", id: "${suspended.runId}" }.` : "It is not resumable; submit a new explicit run.";
|
|
4641
|
-
return textResult(`Run '${suspended.runId}' is suspended. ${recovery}`, { suspended: publicSuspendedRun(suspended) });
|
|
4642
|
-
}
|
|
4643
4807
|
const result = this.management.status(runId);
|
|
4644
|
-
if (!result.status && !result.runDir && !result.resultPath
|
|
4808
|
+
if (!result.status && !result.runDir && !result.resultPath) throw new PoTeamExpectedError("run_not_found", `No run matches '${runId}'.`, false, "Call subagent({\"action\":\"status\"}) and retry with an exact id.");
|
|
4645
4809
|
if (params.transcriptLines !== void 0) return textResult(formatRunTranscript(result.status, params.transcriptLines ?? 80), { transcript: { runId: result.runId } });
|
|
4646
4810
|
return textResult(result.status ? `Run '${result.runId}': ${result.status.state}` : `Run '${result.runId}' has no status yet.`, { status: result });
|
|
4647
4811
|
}
|
|
@@ -4653,44 +4817,13 @@ var SubagentToolService = class {
|
|
|
4653
4817
|
case require_subagentTool.SUBAGENT_ACTIONS.steer: {
|
|
4654
4818
|
const id = resolveTrackedRunId(jobs, params.id);
|
|
4655
4819
|
const runtime = jobs.get(id)?.runtime;
|
|
4656
|
-
if (runtime && !isPiRuntime(runtime)) throw new
|
|
4657
|
-
const result = await this.management.steer(id,
|
|
4820
|
+
if (runtime && !isPiRuntime(runtime)) throw new PoTeamExpectedError("unsupported_operation", `Run '${id}' uses '${runtime}', which does not support steering.`, false, `Use subagent({"action":"stop","id":"${id}"}) to terminate it.`);
|
|
4821
|
+
const result = await this.management.steer(id, {
|
|
4822
|
+
text: params.message,
|
|
4823
|
+
sender: MAIN_AGENT_SENDER
|
|
4824
|
+
}, void 0, signal);
|
|
4658
4825
|
return textResult(`Steer request '${result.requestId}' for '${id}' is ${result.state}: ${result.message}`, { steer: result });
|
|
4659
4826
|
}
|
|
4660
|
-
case require_subagentTool.SUBAGENT_ACTIONS.suspended: {
|
|
4661
|
-
const runs = listSuspendedRuns(scope);
|
|
4662
|
-
return textResult(runs.length ? formatSuspendedRuns(runs) : "No suspended subagents in this session.", { suspended: runs.map(publicSuspendedRun) });
|
|
4663
|
-
}
|
|
4664
|
-
case require_subagentTool.SUBAGENT_ACTIONS.restore: {
|
|
4665
|
-
const record = listSuspendedRuns(scope).find((run) => run.runId === params.id);
|
|
4666
|
-
if (!record) throw new DoomTeamExpectedError("run_not_found", `No suspended run matches '${params.id}'.`, false, "Call subagent({\"action\":\"suspended\"}) and retry with an exact id.");
|
|
4667
|
-
if (!isSuspendedRunResumable(record)) throw new DoomTeamExpectedError("not_resumable", `Suspended run '${params.id}' does not have complete, readable Pi recovery state.`, false, "Submit a new explicit run request instead of restoring this record.");
|
|
4668
|
-
const outcome = this.trackOutcomes(await this.planner.spawn({
|
|
4669
|
-
single: {
|
|
4670
|
-
agent: record.agent,
|
|
4671
|
-
...record.inlineAgent ? { inlineAgent: record.inlineAgent } : {},
|
|
4672
|
-
task: record.task,
|
|
4673
|
-
cwd: record.cwd,
|
|
4674
|
-
...record.model ? { model: record.model } : {},
|
|
4675
|
-
sessionFile: record.sessionFile,
|
|
4676
|
-
...record.identity ? { identity: record.identity } : {}
|
|
4677
|
-
},
|
|
4678
|
-
cwd: record.cwd,
|
|
4679
|
-
agentScope: "both",
|
|
4680
|
-
sessionScope: scope,
|
|
4681
|
-
parentSessionId: ctx.sessionManager.getSessionId(),
|
|
4682
|
-
availableModels: authenticatedModelInfos(ctx.modelRegistry),
|
|
4683
|
-
...operationId ? { operationId } : {},
|
|
4684
|
-
...preallocatedRunIds ? { preallocatedRunIds } : {}
|
|
4685
|
-
}, loadConfig().config), ctx).outcomes[0];
|
|
4686
|
-
if (!outcome?.runId) throw new DoomTeamExpectedError("not_resumable", `Could not restore '${params.id}': ${outcome?.error ?? "the spawn produced no run."}`, true, "Inspect suspended state, then submit a new explicit run if recovery is not possible.");
|
|
4687
|
-
clearSuspendedRun(scope, params.id);
|
|
4688
|
-
const restoredAs = formatAgentIdentity(outcome.identity, outcome.inline) ?? outcome.runId;
|
|
4689
|
-
return textResult(`Restored '${params.id}' as '${restoredAs}' (${outcome.runId}), continuing its transcript.`, { restore: {
|
|
4690
|
-
...outcome,
|
|
4691
|
-
restoredFrom: params.id
|
|
4692
|
-
} });
|
|
4693
|
-
}
|
|
4694
4827
|
}
|
|
4695
4828
|
}
|
|
4696
4829
|
async execute(id, rawParams, signal, onUpdate, ctx) {
|
|
@@ -4699,22 +4832,22 @@ var SubagentToolService = class {
|
|
|
4699
4832
|
if (progress) onUpdate?.(progressResult(progress, params.action));
|
|
4700
4833
|
if (params.action === require_subagentTool.SUBAGENT_ACTIONS.run) return this.executeRun(id, params, ctx);
|
|
4701
4834
|
if (params.action === require_subagentTool.SUBAGENT_ACTIONS.agents) return this.executeAgents(params, ctx);
|
|
4702
|
-
if (!(params.action === require_subagentTool.SUBAGENT_ACTIONS.steer || params.action === require_subagentTool.SUBAGENT_ACTIONS.stop
|
|
4835
|
+
if (!(params.action === require_subagentTool.SUBAGENT_ACTIONS.steer || params.action === require_subagentTool.SUBAGENT_ACTIONS.stop)) return this.executeManagement(params, ctx, signal);
|
|
4703
4836
|
const scope = this.sessionScope(ctx);
|
|
4704
4837
|
this.management.bindSessionScope(scope);
|
|
4705
|
-
const operation = startOperation(scope, id, params,
|
|
4838
|
+
const operation = startOperation(scope, id, params, []);
|
|
4706
4839
|
if (operation.kind === "replay") {
|
|
4707
4840
|
if (operation.record.state === "completed" && operation.record.result) return operation.record.result;
|
|
4708
|
-
throw new
|
|
4841
|
+
throw new PoTeamExpectedError("delivery_unconfirmed", `Operation '${id}' is already pending.`, true, "Inspect run status before retrying this control operation.");
|
|
4709
4842
|
}
|
|
4710
|
-
const response = await this.executeManagement(params, ctx, signal
|
|
4843
|
+
const response = await this.executeManagement(params, ctx, signal);
|
|
4711
4844
|
completeOperation(scope, id, operation.record, response);
|
|
4712
4845
|
return response;
|
|
4713
4846
|
}
|
|
4714
4847
|
};
|
|
4715
4848
|
//#endregion
|
|
4716
4849
|
//#region src/services/headlessSubagentTool/index.ts
|
|
4717
|
-
const SUBAGENT_DESCRIPTION = "Discover agents, start and manage persistent background subagent runs
|
|
4850
|
+
const SUBAGENT_DESCRIPTION = "Discover agents, start and manage persistent background subagent runs.";
|
|
4718
4851
|
/**
|
|
4719
4852
|
* Every result carries the text the MODEL reads and the structured details the
|
|
4720
4853
|
* cockpit card reads. The text is always given explicitly: a serialized detail
|
|
@@ -4750,25 +4883,24 @@ function scopeOf(value) {
|
|
|
4750
4883
|
return value === "user" || value === "project" ? value : "both";
|
|
4751
4884
|
}
|
|
4752
4885
|
function createHeadlessSubagentTool(runtime, initialExecution) {
|
|
4753
|
-
const scope =
|
|
4886
|
+
const scope = require_atomicJson.createSessionScope(initialExecution.sessionId);
|
|
4754
4887
|
const jobs = runtime.asyncJobTracker.forSession(initialExecution.sessionId, scope);
|
|
4755
4888
|
return {
|
|
4756
4889
|
name: "subagent",
|
|
4757
4890
|
label: "Subagent",
|
|
4758
4891
|
description: SUBAGENT_DESCRIPTION,
|
|
4759
4892
|
parameters: require_subagentTool.SubagentToolSchema,
|
|
4760
|
-
promptSnippet: "Discover, run, inspect, steer,
|
|
4761
|
-
promptGuidelines: ["Runs are persistent background work. Do not resubmit a run that already returned an id.", "Use status
|
|
4893
|
+
promptSnippet: "Discover, run, inspect, steer, and stop persistent subagents",
|
|
4894
|
+
promptGuidelines: ["Runs are persistent background work. Do not resubmit a run that already returned an id.", "Use status before retrying a failed or interrupted operation."],
|
|
4762
4895
|
executionMode: "serial",
|
|
4763
4896
|
async execute(_toolCallId, parameters, signal, onUpdate, execution = initialExecution) {
|
|
4764
4897
|
try {
|
|
4765
4898
|
const params = validateParams(parameters);
|
|
4766
|
-
const availableModels = execution.getAvailableModels?.().map(toModelInfo) ?? (execution.model ? [toModelInfo(execution.model)] : []);
|
|
4767
4899
|
if (params.action === require_subagentTool.SUBAGENT_ACTIONS.agents) {
|
|
4768
4900
|
const scope = scopeOf(params.scope);
|
|
4769
|
-
const agents = runtime.discovery.discover(params.cwd ?? execution.cwd, scope).agents;
|
|
4770
|
-
const selected = params.name ? runtime.discovery.find(params.cwd ?? execution.cwd, scope, params.name) : void 0;
|
|
4771
|
-
if (params.name && !selected) throw new
|
|
4901
|
+
const agents = (await runtime.discovery.discover(params.cwd ?? execution.cwd, scope)).agents;
|
|
4902
|
+
const selected = params.name ? await runtime.discovery.find(params.cwd ?? execution.cwd, scope, params.name) : void 0;
|
|
4903
|
+
if (params.name && !selected) throw new PoTeamExpectedError("agent_not_found", `No executable agent matches '${params.name}'.`, false, "Call subagent({\"action\":\"agents\"}) and retry with an exact agent name.");
|
|
4772
4904
|
if (selected) return result(formatAgentDetail(selected), { agents: [publicAgent(selected)] });
|
|
4773
4905
|
return result(formatAgentList(agents), { agents: agents.map((agent) => ({
|
|
4774
4906
|
name: agent.name,
|
|
@@ -4794,12 +4926,13 @@ function createHeadlessSubagentTool(runtime, initialExecution) {
|
|
|
4794
4926
|
})),
|
|
4795
4927
|
cwd: execution.cwd,
|
|
4796
4928
|
agentScope: scopeOf(params.scope),
|
|
4797
|
-
sessionScope:
|
|
4929
|
+
sessionScope: require_atomicJson.createSessionScope(execution.sessionId),
|
|
4798
4930
|
environment: execution.environment,
|
|
4799
4931
|
parentSessionId: execution.sessionId,
|
|
4932
|
+
parentSelection: execution.selection,
|
|
4800
4933
|
...params.concurrency === void 0 ? {} : { concurrency: params.concurrency },
|
|
4801
4934
|
...params.artifacts === void 0 ? {} : { artifacts: params.artifacts },
|
|
4802
|
-
availableModels,
|
|
4935
|
+
availableModels: await availableModelInfos(execution),
|
|
4803
4936
|
...execution.model ? { parentModel: execution.model } : {},
|
|
4804
4937
|
...parentForkSource ? { parentForkSource } : {}
|
|
4805
4938
|
}, loadConfig().config);
|
|
@@ -4815,19 +4948,13 @@ function createHeadlessSubagentTool(runtime, initialExecution) {
|
|
|
4815
4948
|
return result(formatFleetView(runs), { runs });
|
|
4816
4949
|
}
|
|
4817
4950
|
const status = runtime.management.statusAsync ? await runtime.management.statusAsync(params.id) : runtime.management.status(params.id);
|
|
4818
|
-
|
|
4951
|
+
const statusText = status.status ? [`Run '${status.runId}': ${status.status.state}`, status.status.summary ? `Summary: ${status.status.summary}` : void 0].filter((line) => line !== void 0).join("\n") : `Run '${status.runId}' has no status yet.`;
|
|
4952
|
+
const nativeEntries = params.transcriptLines === void 0 || status.status?.transcriptPath !== void 0 ? void 0 : await runtime.nativeRuns.readTranscript(execution.sessionId, status.runId, params.transcriptLines);
|
|
4953
|
+
return result([statusText, params.transcriptLines === void 0 ? void 0 : nativeEntries !== void 0 ? formatNativeRunTranscript(nativeEntries, params.transcriptLines) : formatRunTranscript(status.status, params.transcriptLines)].filter((text) => text !== void 0).join("\n\n"), {
|
|
4819
4954
|
runId: status.runId,
|
|
4820
4955
|
status: status.status
|
|
4821
4956
|
});
|
|
4822
4957
|
}
|
|
4823
|
-
if (params.action === require_subagentTool.SUBAGENT_ACTIONS.suspended) {
|
|
4824
|
-
const suspended = listSuspendedRuns(require_externalProcessIpc.createSessionScope(execution.sessionId));
|
|
4825
|
-
const text = suspended.length ? formatSuspendedRuns(suspended) : "No suspended subagents in this session.";
|
|
4826
|
-
return result(text, {
|
|
4827
|
-
suspended,
|
|
4828
|
-
text
|
|
4829
|
-
});
|
|
4830
|
-
}
|
|
4831
4958
|
const id = resolveTrackedRunId(jobs, params.id);
|
|
4832
4959
|
if (params.action === require_subagentTool.SUBAGENT_ACTIONS.stop) {
|
|
4833
4960
|
const control = await runtime.management.stop(id, params.reason);
|
|
@@ -4836,40 +4963,14 @@ function createHeadlessSubagentTool(runtime, initialExecution) {
|
|
|
4836
4963
|
control
|
|
4837
4964
|
});
|
|
4838
4965
|
}
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
if (!suspended) throw new Error(`No suspended run matches '${params.id}'.`);
|
|
4848
|
-
if (!isSuspendedRunResumable(suspended)) throw new Error(`Suspended run '${params.id}' is not resumable.`);
|
|
4849
|
-
const outcome = (await runtime.spawnPlanner.spawn({
|
|
4850
|
-
single: {
|
|
4851
|
-
agent: suspended.agent,
|
|
4852
|
-
...suspended.inlineAgent ? { inlineAgent: suspended.inlineAgent } : {},
|
|
4853
|
-
task: suspended.task,
|
|
4854
|
-
cwd: suspended.cwd,
|
|
4855
|
-
...suspended.model ? { model: suspended.model } : {},
|
|
4856
|
-
sessionFile: suspended.sessionFile,
|
|
4857
|
-
...suspended.identity ? { identity: suspended.identity } : {}
|
|
4858
|
-
},
|
|
4859
|
-
cwd: suspended.cwd,
|
|
4860
|
-
agentScope: "both",
|
|
4861
|
-
sessionScope: require_externalProcessIpc.createSessionScope(execution.sessionId),
|
|
4862
|
-
environment: execution.environment,
|
|
4863
|
-
runtime: "pi",
|
|
4864
|
-
parentSessionId: execution.sessionId,
|
|
4865
|
-
availableModels
|
|
4866
|
-
}, loadConfig().config)).outcomes[0];
|
|
4867
|
-
if (!outcome?.runId) throw new Error(`Could not restore '${params.id}': ${outcome?.error ?? "the spawn produced no run."}`);
|
|
4868
|
-
clearSuspendedRun(require_externalProcessIpc.createSessionScope(execution.sessionId), params.id);
|
|
4869
|
-
return result(`Restored '${params.id}' as '${outcome.runId}', continuing its transcript.`, { restore: {
|
|
4870
|
-
...outcome,
|
|
4871
|
-
restoredFrom: params.id
|
|
4872
|
-
} });
|
|
4966
|
+
const steer = await runtime.management.steer(id, {
|
|
4967
|
+
text: params.message,
|
|
4968
|
+
sender: MAIN_AGENT_SENDER
|
|
4969
|
+
}, void 0, signal);
|
|
4970
|
+
return result(`Steer request '${steer.requestId}' for '${id}' is ${steer.state}: ${steer.message}`, {
|
|
4971
|
+
runId: id,
|
|
4972
|
+
steer
|
|
4973
|
+
});
|
|
4873
4974
|
} catch (error) {
|
|
4874
4975
|
const message = error instanceof Error ? error.message : String(error);
|
|
4875
4976
|
return result(message, message, true);
|
|
@@ -4879,7 +4980,7 @@ function createHeadlessSubagentTool(runtime, initialExecution) {
|
|
|
4879
4980
|
}
|
|
4880
4981
|
//#endregion
|
|
4881
4982
|
//#region src/services/mcpTools/index.ts
|
|
4882
|
-
const TEAM_MCP_TOOLS_SERVICE = "
|
|
4983
|
+
const TEAM_MCP_TOOLS_SERVICE = "po/team-mcp-tools";
|
|
4883
4984
|
function mountMcpTools(tools) {
|
|
4884
4985
|
return (context) => {
|
|
4885
4986
|
context.plugin((providerContext) => {
|
|
@@ -4929,7 +5030,7 @@ function subscribeNativeRunProjection(sessionId, listener) {
|
|
|
4929
5030
|
if (closed) return;
|
|
4930
5031
|
closed = true;
|
|
4931
5032
|
projection.listeners.delete(listener);
|
|
4932
|
-
if (projection.listeners.size === 0 && projection.runs.size === 0) sessions.delete(sessionId);
|
|
5033
|
+
if (projection.listeners.size === 0 && projection.runs.size === 0 && sessions.get(sessionId) === projection) sessions.delete(sessionId);
|
|
4933
5034
|
};
|
|
4934
5035
|
}
|
|
4935
5036
|
//#endregion
|
|
@@ -5145,7 +5246,7 @@ function formatGroupedCompletion(details) {
|
|
|
5145
5246
|
*
|
|
5146
5247
|
* Separate from `formatSingleCompletion` because the two have different
|
|
5147
5248
|
* readers. That one is written for the model and embeds the run's full result
|
|
5148
|
-
* preview; this one goes to `
|
|
5249
|
+
* preview; this one goes to `PoHeadlessClient.notify`, which collapses every
|
|
5149
5250
|
* newline to a space and truncates at 4096 characters
|
|
5150
5251
|
* (`packages/core/po-core/src/schemas/notification.ts`), and on the web
|
|
5151
5252
|
* additionally drives a browser notification. Feeding the model-facing text to
|
|
@@ -5218,7 +5319,7 @@ function buildCompletionDetails(result) {
|
|
|
5218
5319
|
* The custom-message type the parent renders completions under. The literal is
|
|
5219
5320
|
* shared by the producer here and the TUI renderer registered for it
|
|
5220
5321
|
* (`(frontend)/message/_lib/subagent-notify.cli.ts`, which draws through
|
|
5221
|
-
* `completionNotice.ts`), and by the
|
|
5322
|
+
* `completionNotice.ts`), and by the server plugin, which persists the same
|
|
5222
5323
|
* type as a session entry so a cockpit transcript records what was delivered.
|
|
5223
5324
|
*/
|
|
5224
5325
|
const SUBAGENT_NOTIFY_MESSAGE_TYPE = "subagent-notify";
|
|
@@ -5344,41 +5445,149 @@ function active(job) {
|
|
|
5344
5445
|
"stopped"
|
|
5345
5446
|
])).has(job.status);
|
|
5346
5447
|
}
|
|
5347
|
-
|
|
5448
|
+
/**
|
|
5449
|
+
* Stops the live external runs of a session that ends. A native run is a conversation of the session's own
|
|
5450
|
+
* Harness and resumes with it, so it is left alone.
|
|
5451
|
+
*/
|
|
5452
|
+
async function stopScopeRuns(options) {
|
|
5453
|
+
const jobs = options.jobs.filter((job) => !job.native && active(job));
|
|
5454
|
+
const outcomes = await Promise.allSettled(jobs.map((job) => options.stop(job.runId, options.reason)));
|
|
5348
5455
|
return {
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
...job.identity === void 0 ? {} : { identity: job.identity },
|
|
5352
|
-
...job.inline === void 0 ? {} : { inline: job.inline },
|
|
5353
|
-
runtime: job.runtime ?? (job.native ? "pi" : "external"),
|
|
5354
|
-
task: job.task ?? "",
|
|
5355
|
-
cwd: job.cwd ?? "",
|
|
5356
|
-
...job.status === void 0 ? {} : { lastStatus: job.status },
|
|
5357
|
-
...job.sessionFile === void 0 ? {} : { sessionFile: job.sessionFile },
|
|
5358
|
-
suspendedAt,
|
|
5359
|
-
reason
|
|
5456
|
+
stopped: jobs.map((job) => job.runId),
|
|
5457
|
+
unstoppable: jobs.filter((_, index) => outcomes[index]?.status === "rejected").map((job) => job.runId)
|
|
5360
5458
|
};
|
|
5361
5459
|
}
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5460
|
+
//#endregion
|
|
5461
|
+
//#region src/schemas/team/packageConfig.ts
|
|
5462
|
+
const PO_TEAM_PACKAGE = "@agimon-ai/po-team";
|
|
5463
|
+
const TEAM_CONFIG_KEYS = ["models", "excludeTools"];
|
|
5464
|
+
const TEAM_MODEL_KEYS = ["model", "thinking"];
|
|
5465
|
+
const THINKING_VALUES = /* @__PURE__ */ new Set([
|
|
5466
|
+
"off",
|
|
5467
|
+
"minimal",
|
|
5468
|
+
"low",
|
|
5469
|
+
"medium",
|
|
5470
|
+
"high",
|
|
5471
|
+
"xhigh",
|
|
5472
|
+
"max"
|
|
5473
|
+
]);
|
|
5474
|
+
function isRecord$1(value) {
|
|
5475
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5476
|
+
}
|
|
5477
|
+
function assertKnownKeys(value, keys, location) {
|
|
5478
|
+
const unsupported = Object.keys(value).filter((key) => !keys.includes(key));
|
|
5479
|
+
if (unsupported.length > 0) throw new Error(`${location} has unsupported field(s): ${unsupported.join(", ")}`);
|
|
5480
|
+
}
|
|
5481
|
+
/** Validate and normalize one Team-owned package configuration mapping. */
|
|
5482
|
+
function parseTeamPackageConfig(value, location) {
|
|
5483
|
+
if (!isRecord$1(value)) throw new Error(`${location} must be a mapping`);
|
|
5484
|
+
assertKnownKeys(value, TEAM_CONFIG_KEYS, location);
|
|
5485
|
+
const hasModels = Object.hasOwn(value, "models");
|
|
5486
|
+
const hasExcludeTools = Object.hasOwn(value, "excludeTools");
|
|
5487
|
+
if (!hasModels && !hasExcludeTools) throw new Error(`${location} must define models or excludeTools`);
|
|
5488
|
+
let models;
|
|
5489
|
+
if (hasModels) {
|
|
5490
|
+
if (!Array.isArray(value.models) || value.models.length === 0) throw new Error(`${location}.models must be a non-empty array`);
|
|
5491
|
+
models = value.models.map((entry, index) => {
|
|
5492
|
+
const entryLocation = `${location}.models[${index}]`;
|
|
5493
|
+
if (!isRecord$1(entry)) throw new Error(`${entryLocation} must be a mapping`);
|
|
5494
|
+
assertKnownKeys(entry, TEAM_MODEL_KEYS, entryLocation);
|
|
5495
|
+
if (typeof entry.model !== "string" || !entry.model.trim()) throw new Error(`${entryLocation}.model must be a non-empty string`);
|
|
5496
|
+
if (entry.thinking !== void 0 && (typeof entry.thinking !== "string" || !THINKING_VALUES.has(entry.thinking))) throw new Error(`${entryLocation}.thinking must be one of: ${[...THINKING_VALUES].join(", ")}`);
|
|
5497
|
+
return {
|
|
5498
|
+
model: entry.model.trim(),
|
|
5499
|
+
...entry.thinking ? { thinking: entry.thinking } : {}
|
|
5500
|
+
};
|
|
5501
|
+
});
|
|
5502
|
+
}
|
|
5503
|
+
let excludeTools;
|
|
5504
|
+
if (hasExcludeTools) {
|
|
5505
|
+
if (!Array.isArray(value.excludeTools) || value.excludeTools.length === 0) throw new Error(`${location}.excludeTools must be a non-empty array`);
|
|
5506
|
+
excludeTools = [...new Set(value.excludeTools.map((entry, index) => {
|
|
5507
|
+
if (typeof entry !== "string" || !entry.trim()) throw new Error(`${location}.excludeTools[${index}] must be a non-empty string`);
|
|
5508
|
+
return entry.trim();
|
|
5509
|
+
}))];
|
|
5510
|
+
}
|
|
5368
5511
|
return {
|
|
5369
|
-
|
|
5370
|
-
|
|
5512
|
+
...models ? { models } : {},
|
|
5513
|
+
...excludeTools ? { excludeTools } : {}
|
|
5371
5514
|
};
|
|
5372
5515
|
}
|
|
5373
|
-
/**
|
|
5374
|
-
|
|
5516
|
+
/** Merge Team configurations contributed by selected layers in selection order. */
|
|
5517
|
+
function mergeTeamPackageConfigurations(entries) {
|
|
5518
|
+
let models;
|
|
5519
|
+
const excludeTools = /* @__PURE__ */ new Set();
|
|
5520
|
+
let hasExcludeTools = false;
|
|
5521
|
+
for (const entry of entries) {
|
|
5522
|
+
const location = `Package "${entry.specifier}" config in layer "${entry.layer}" of .po/modes.yaml`;
|
|
5523
|
+
const next = parseTeamPackageConfig(entry.config, location);
|
|
5524
|
+
if (next.models) models = next.models.map((model) => ({ ...model }));
|
|
5525
|
+
if (next.excludeTools) {
|
|
5526
|
+
hasExcludeTools = true;
|
|
5527
|
+
for (const tool of next.excludeTools) excludeTools.add(tool);
|
|
5528
|
+
}
|
|
5529
|
+
}
|
|
5530
|
+
if (!models && !hasExcludeTools) return void 0;
|
|
5375
5531
|
return {
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
suspended: await listSuspendedRunsAsync(scope)
|
|
5532
|
+
...models ? { models } : {},
|
|
5533
|
+
...hasExcludeTools ? { excludeTools: [...excludeTools] } : {}
|
|
5379
5534
|
};
|
|
5380
5535
|
}
|
|
5381
5536
|
//#endregion
|
|
5537
|
+
//#region src/services/teamAgentConfig/index.ts
|
|
5538
|
+
const PO_TEAM_AGENT_CONFIG_SERVICE = "po/team-agent-config";
|
|
5539
|
+
/** Normalize Team's ordered models without duplicating a known thinking suffix. */
|
|
5540
|
+
function teamModelSpecs(config) {
|
|
5541
|
+
return config?.models?.map(({ model, thinking }) => thinking ? `${model.replace(/:(?:off|minimal|low|medium|high|xhigh|max)$/, "")}:${thinking}` : model);
|
|
5542
|
+
}
|
|
5543
|
+
/** Session-local Team policy, loaded once for each injected config snapshot. */
|
|
5544
|
+
var TeamAgentConfigService = class {
|
|
5545
|
+
io;
|
|
5546
|
+
snapshot;
|
|
5547
|
+
loads = /* @__PURE__ */ new WeakMap();
|
|
5548
|
+
constructor(io) {
|
|
5549
|
+
this.io = io;
|
|
5550
|
+
}
|
|
5551
|
+
bind(snapshot) {
|
|
5552
|
+
this.snapshot = snapshot;
|
|
5553
|
+
return () => {
|
|
5554
|
+
if (this.snapshot === snapshot) this.snapshot = void 0;
|
|
5555
|
+
};
|
|
5556
|
+
}
|
|
5557
|
+
current() {
|
|
5558
|
+
if (!this.snapshot) return Promise.reject(new PoTeamExpectedError("runtime_unavailable", "Team agent configuration is not loaded yet.", true, "Retry after the session configuration is ready."));
|
|
5559
|
+
const snapshot = this.snapshot();
|
|
5560
|
+
const cached = this.loads.get(snapshot);
|
|
5561
|
+
if (cached) return cached;
|
|
5562
|
+
const load = this.load(snapshot).catch((error) => {
|
|
5563
|
+
this.loads.delete(snapshot);
|
|
5564
|
+
throw error;
|
|
5565
|
+
});
|
|
5566
|
+
this.loads.set(snapshot, load);
|
|
5567
|
+
return load;
|
|
5568
|
+
}
|
|
5569
|
+
currentOrUndefined() {
|
|
5570
|
+
return this.snapshot ? this.current() : Promise.resolve(void 0);
|
|
5571
|
+
}
|
|
5572
|
+
async load(snapshot) {
|
|
5573
|
+
const { fs, homeDirectory, environment } = this.io;
|
|
5574
|
+
if (!snapshot.harness.root) return { planningSubagents: snapshot.settings.modes?.planning?.subagents };
|
|
5575
|
+
const modes = await (0, _agimon_ai_po_config_majorModes.readMajorModesConfig)(fs, snapshot.harness.root, _agimon_ai_po_core_platform.BACKGROUND_CONTEXT, {
|
|
5576
|
+
homeDirectory,
|
|
5577
|
+
environment
|
|
5578
|
+
});
|
|
5579
|
+
const configurations = await (0, _agimon_ai_po_config_majorModes.readPackageConfigurations)(fs, modes, [...snapshot.harness.layers], PO_TEAM_PACKAGE, _agimon_ai_po_core_platform.BACKGROUND_CONTEXT);
|
|
5580
|
+
const config = mergeTeamPackageConfigurations(configurations);
|
|
5581
|
+
return {
|
|
5582
|
+
models: teamModelSpecs(config),
|
|
5583
|
+
thinking: config?.models?.[0]?.thinking,
|
|
5584
|
+
excludeTools: config?.excludeTools,
|
|
5585
|
+
planningSubagents: snapshot.settings.modes?.planning?.subagents,
|
|
5586
|
+
...config ? { path: configurations.at(-1)?.filePath ?? node_path.join(snapshot.harness.root, ".po", "modes.yaml") } : {}
|
|
5587
|
+
};
|
|
5588
|
+
}
|
|
5589
|
+
};
|
|
5590
|
+
//#endregion
|
|
5382
5591
|
//#region src/services/directRunBackgroundWork/index.ts
|
|
5383
5592
|
const PROVIDER_NAME = "team-direct-runs";
|
|
5384
5593
|
/** Publish direct Team runs owned by exactly one Pi session. */
|
|
@@ -5406,7 +5615,7 @@ function assertPolicy(policy) {
|
|
|
5406
5615
|
/** Publishes Team's capability intersection store through a Cordis service. */
|
|
5407
5616
|
function createSubagentPolicyService(store) {
|
|
5408
5617
|
const service = {
|
|
5409
|
-
generation: `
|
|
5618
|
+
generation: `po-subagent-policy:${crypto.randomUUID()}`,
|
|
5410
5619
|
register(initialPolicy) {
|
|
5411
5620
|
assertPolicy(initialPolicy);
|
|
5412
5621
|
const owner = initialPolicy.owner;
|
|
@@ -5438,7 +5647,7 @@ function createSubagentPolicyService(store) {
|
|
|
5438
5647
|
//#region src/services/teamCollaboration/index.ts
|
|
5439
5648
|
/** Mount every Team-owned collaboration capability in one session fiber. */
|
|
5440
5649
|
function teamCollaborationPlugin(ctx, config) {
|
|
5441
|
-
const backgroundWork = (0, _agimon_ai_po_core_backgroundWork.
|
|
5650
|
+
const backgroundWork = (0, _agimon_ai_po_core_backgroundWork.readPoBackgroundWorkService)(ctx);
|
|
5442
5651
|
if (backgroundWork === void 0) throw new Error("Team requires the Po Session foundation.");
|
|
5443
5652
|
const subagentPolicy = createSubagentPolicyService(config.policies);
|
|
5444
5653
|
const delegation = config.delegation.createService(ctx, config.session);
|
|
@@ -5448,28 +5657,28 @@ function teamCollaborationPlugin(ctx, config) {
|
|
|
5448
5657
|
cwd: config.session.cwd,
|
|
5449
5658
|
environment: config.session.environment
|
|
5450
5659
|
});
|
|
5451
|
-
ctx.provide(require_subagentPolicy.
|
|
5452
|
-
ctx.provide(_agimon_ai_po_core_delegation.
|
|
5453
|
-
ctx.provide(require_fablePlanApi.
|
|
5660
|
+
ctx.provide(require_subagentPolicy.PO_SUBAGENT_POLICY_SERVICE, subagentPolicy);
|
|
5661
|
+
ctx.provide(_agimon_ai_po_core_delegation.PO_DELEGATION_SERVICE, delegation);
|
|
5662
|
+
ctx.provide(require_fablePlanApi.PO_FABLE_PLAN_SERVICE, fablePlan);
|
|
5454
5663
|
registerDirectRunBackgroundWork(ctx, backgroundWork, config.session.sessionId, config.directRunTracker);
|
|
5455
5664
|
if (config.observeDelegation) {
|
|
5456
|
-
ctx.on(_agimon_ai_po_core_delegation.
|
|
5665
|
+
ctx.on(_agimon_ai_po_core_delegation.PO_DELEGATION_REQUESTED_EVENT, (event) => config.observeDelegation?.({
|
|
5457
5666
|
kind: "requested",
|
|
5458
5667
|
event
|
|
5459
5668
|
}));
|
|
5460
|
-
ctx.on(_agimon_ai_po_core_delegation.
|
|
5669
|
+
ctx.on(_agimon_ai_po_core_delegation.PO_DELEGATION_STARTED_EVENT, (event) => config.observeDelegation?.({
|
|
5461
5670
|
kind: "started",
|
|
5462
5671
|
event
|
|
5463
5672
|
}));
|
|
5464
|
-
ctx.on(_agimon_ai_po_core_delegation.
|
|
5673
|
+
ctx.on(_agimon_ai_po_core_delegation.PO_DELEGATION_UPDATED_EVENT, (event) => config.observeDelegation?.({
|
|
5465
5674
|
kind: "updated",
|
|
5466
5675
|
event
|
|
5467
5676
|
}));
|
|
5468
|
-
ctx.on(_agimon_ai_po_core_delegation.
|
|
5677
|
+
ctx.on(_agimon_ai_po_core_delegation.PO_DELEGATION_FINISHED_EVENT, (event) => config.observeDelegation?.({
|
|
5469
5678
|
kind: "finished",
|
|
5470
5679
|
event
|
|
5471
5680
|
}));
|
|
5472
|
-
ctx.on(_agimon_ai_po_core_delegation.
|
|
5681
|
+
ctx.on(_agimon_ai_po_core_delegation.PO_DELEGATION_CANCELLED_EVENT, (event) => config.observeDelegation?.({
|
|
5473
5682
|
kind: "cancelled",
|
|
5474
5683
|
event
|
|
5475
5684
|
}));
|
|
@@ -5540,11 +5749,11 @@ var ManagementActions = class {
|
|
|
5540
5749
|
if (exact) return exact;
|
|
5541
5750
|
const matches = runs.filter((run) => run.runId.startsWith(id));
|
|
5542
5751
|
if (matches.length === 1) return matches[0];
|
|
5543
|
-
if (matches.length > 1) throw new
|
|
5752
|
+
if (matches.length > 1) throw new PoTeamExpectedError("run_not_found", `Multiple current-session runs match '${id}'.`, false, "Retry with a longer run id.");
|
|
5544
5753
|
}
|
|
5545
5754
|
requireActiveJob(id) {
|
|
5546
5755
|
const job = this.resolveJob(id);
|
|
5547
|
-
if (!job) throw new
|
|
5756
|
+
if (!job) throw new PoTeamExpectedError("run_not_found", `No active run matches '${id}'.`, false, "Call subagent({\"action\":\"status\"}) and retry with an exact run id.");
|
|
5548
5757
|
return job;
|
|
5549
5758
|
}
|
|
5550
5759
|
status(id) {
|
|
@@ -5558,7 +5767,20 @@ var ManagementActions = class {
|
|
|
5558
5767
|
};
|
|
5559
5768
|
}
|
|
5560
5769
|
async statusAsync(id) {
|
|
5561
|
-
|
|
5770
|
+
const live = this.status(id);
|
|
5771
|
+
if (live.status || !this.nativeRuns?.reported) return live;
|
|
5772
|
+
const run = await this.nativeRuns.reported(id);
|
|
5773
|
+
if (!run?.state) return live;
|
|
5774
|
+
return {
|
|
5775
|
+
...live,
|
|
5776
|
+
status: statusProjection({
|
|
5777
|
+
runId: id,
|
|
5778
|
+
agent: run.agent,
|
|
5779
|
+
task: run.task,
|
|
5780
|
+
status: run.state,
|
|
5781
|
+
native: true
|
|
5782
|
+
})
|
|
5783
|
+
};
|
|
5562
5784
|
}
|
|
5563
5785
|
list() {
|
|
5564
5786
|
return { runs: this.sessionJobs().list() };
|
|
@@ -5574,11 +5796,11 @@ var ManagementActions = class {
|
|
|
5574
5796
|
const job = this.requireActiveJob(id);
|
|
5575
5797
|
const requestId = (0, node_crypto.randomUUID)();
|
|
5576
5798
|
if (job.native) {
|
|
5577
|
-
if (!this.nativeRuns?.get(scope.rootSessionId, job.runId)) throw new
|
|
5799
|
+
if (!this.nativeRuns?.get(scope.rootSessionId, job.runId)) throw new PoTeamExpectedError("run_not_found", `Native run '${job.runId}' is no longer active.`, false, "List active runs and retry with a current run id.");
|
|
5578
5800
|
await this.nativeRuns.stop(scope.rootSessionId, job.runId, reason);
|
|
5579
5801
|
return { requestId };
|
|
5580
5802
|
}
|
|
5581
|
-
if (!this.externalProcesses?.has(scope, job.runId)) throw new
|
|
5803
|
+
if (!this.externalProcesses?.has(scope, job.runId)) throw new PoTeamExpectedError("run_not_found", `External run '${job.runId}' is no longer active.`, false, "List active runs and retry with a current run id.");
|
|
5582
5804
|
await this.externalProcesses.control(scope, job.runId, {
|
|
5583
5805
|
command,
|
|
5584
5806
|
requestId,
|
|
@@ -5592,7 +5814,7 @@ var ManagementActions = class {
|
|
|
5592
5814
|
const requestId = (0, node_crypto.randomUUID)();
|
|
5593
5815
|
const index = targetIndex ?? 0;
|
|
5594
5816
|
if (job.native) {
|
|
5595
|
-
if (!this.nativeRuns?.get(scope.rootSessionId, job.runId)) throw new
|
|
5817
|
+
if (!this.nativeRuns?.get(scope.rootSessionId, job.runId)) throw new PoTeamExpectedError("run_not_found", `Native run '${job.runId}' is no longer active.`, false, "List active runs and retry with a current run id.");
|
|
5596
5818
|
await this.nativeRuns.steer(scope.rootSessionId, job.runId, message, signal);
|
|
5597
5819
|
return {
|
|
5598
5820
|
requestId,
|
|
@@ -5601,11 +5823,11 @@ var ManagementActions = class {
|
|
|
5601
5823
|
message: "Native child accepted the steer request."
|
|
5602
5824
|
};
|
|
5603
5825
|
}
|
|
5604
|
-
if (!this.externalProcesses?.has(scope, job.runId)) throw new
|
|
5826
|
+
if (!this.externalProcesses?.has(scope, job.runId)) throw new PoTeamExpectedError("run_not_found", `External run '${job.runId}' is no longer active.`, false, "List active runs and retry with a current run id.");
|
|
5605
5827
|
const acknowledgement = await this.externalProcesses.control(scope, job.runId, {
|
|
5606
5828
|
command: "steer",
|
|
5607
5829
|
requestId,
|
|
5608
|
-
message,
|
|
5830
|
+
message: typeof message === "string" ? message : message.text,
|
|
5609
5831
|
targetIndex: index
|
|
5610
5832
|
});
|
|
5611
5833
|
if (!acknowledgement) return {
|
|
@@ -5652,140 +5874,6 @@ var McpDirectToolResolverBinding = class {
|
|
|
5652
5874
|
}
|
|
5653
5875
|
};
|
|
5654
5876
|
//#endregion
|
|
5655
|
-
//#region src/services/nativeRunCoordinator/index.ts
|
|
5656
|
-
function terminalState(event) {
|
|
5657
|
-
return event.state === "completed" || event.state === "failed" || event.state === "stopped" ? event.state : void 0;
|
|
5658
|
-
}
|
|
5659
|
-
function entryKey(sessionId, runId) {
|
|
5660
|
-
return JSON.stringify([sessionId, runId]);
|
|
5661
|
-
}
|
|
5662
|
-
var NativeRunCoordinator = class {
|
|
5663
|
-
childSessions;
|
|
5664
|
-
tracker;
|
|
5665
|
-
notifier;
|
|
5666
|
-
projection;
|
|
5667
|
-
entries = /* @__PURE__ */ new Map();
|
|
5668
|
-
closed = false;
|
|
5669
|
-
closing;
|
|
5670
|
-
constructor(childSessions, tracker, notifier, projection) {
|
|
5671
|
-
this.childSessions = childSessions;
|
|
5672
|
-
this.tracker = tracker;
|
|
5673
|
-
this.notifier = notifier;
|
|
5674
|
-
this.projection = projection;
|
|
5675
|
-
}
|
|
5676
|
-
async start(sessionId, request, identity) {
|
|
5677
|
-
if (this.closed) throw new Error("The native Team run coordinator is closed.");
|
|
5678
|
-
if (!sessionId.trim()) throw new Error("Native child runs require a session identity.");
|
|
5679
|
-
const service = this.childSessions?.get();
|
|
5680
|
-
if (!service) throw new Error("The in-process Pi child-session service is unavailable.");
|
|
5681
|
-
const handle = await service.start(request);
|
|
5682
|
-
if (this.closed) {
|
|
5683
|
-
await handle.dispose();
|
|
5684
|
-
throw new Error("The native Team run coordinator closed during child startup.");
|
|
5685
|
-
}
|
|
5686
|
-
const entry = {
|
|
5687
|
-
sessionId,
|
|
5688
|
-
scope: request.scope,
|
|
5689
|
-
request,
|
|
5690
|
-
...identity ? { identity } : {},
|
|
5691
|
-
handle,
|
|
5692
|
-
terminal: false
|
|
5693
|
-
};
|
|
5694
|
-
const key = entryKey(sessionId, request.runId);
|
|
5695
|
-
this.entries.set(key, entry);
|
|
5696
|
-
try {
|
|
5697
|
-
const unsubscribe = handle.subscribe((event) => this.onEvent(entry, event));
|
|
5698
|
-
if (entry.terminal) unsubscribe();
|
|
5699
|
-
else entry.unsubscribe = unsubscribe;
|
|
5700
|
-
return handle;
|
|
5701
|
-
} catch (error) {
|
|
5702
|
-
this.entries.delete(key);
|
|
5703
|
-
await handle.dispose().catch(() => void 0);
|
|
5704
|
-
throw error;
|
|
5705
|
-
}
|
|
5706
|
-
}
|
|
5707
|
-
get(sessionId, runId) {
|
|
5708
|
-
return this.entries.get(entryKey(sessionId, runId))?.handle;
|
|
5709
|
-
}
|
|
5710
|
-
status(sessionId, runId) {
|
|
5711
|
-
return this.tracker.getNative(sessionId, runId);
|
|
5712
|
-
}
|
|
5713
|
-
async steer(sessionId, runId, message, signal) {
|
|
5714
|
-
const handle = this.get(sessionId, runId);
|
|
5715
|
-
if (!handle) throw new Error(`No active native run matches '${runId}'.`);
|
|
5716
|
-
await handle.steer(message, signal);
|
|
5717
|
-
}
|
|
5718
|
-
async stop(sessionId, runId, reason) {
|
|
5719
|
-
const handle = this.get(sessionId, runId);
|
|
5720
|
-
if (!handle) throw new Error(`No active native run matches '${runId}'.`);
|
|
5721
|
-
await handle.stop(reason);
|
|
5722
|
-
}
|
|
5723
|
-
async close() {
|
|
5724
|
-
this.closed = true;
|
|
5725
|
-
this.closing ??= (async () => {
|
|
5726
|
-
const active = [...this.entries.values()];
|
|
5727
|
-
const outcomes = await Promise.allSettled(active.map((entry) => entry.handle.dispose()));
|
|
5728
|
-
for (const entry of active) {
|
|
5729
|
-
entry.unsubscribe?.();
|
|
5730
|
-
this.entries.delete(entryKey(entry.sessionId, entry.request.runId));
|
|
5731
|
-
}
|
|
5732
|
-
const failures = outcomes.filter((outcome) => outcome.status === "rejected").map((outcome) => outcome.reason);
|
|
5733
|
-
if (failures.length) throw new AggregateError(failures, "Native Team run shutdown failed.");
|
|
5734
|
-
})();
|
|
5735
|
-
return this.closing;
|
|
5736
|
-
}
|
|
5737
|
-
onEvent(entry, event) {
|
|
5738
|
-
entry.startedAt ??= event.timestamp;
|
|
5739
|
-
const status = terminalState(event);
|
|
5740
|
-
const projection = {
|
|
5741
|
-
runId: event.runId,
|
|
5742
|
-
agent: entry.request.agent,
|
|
5743
|
-
...entry.identity ? {
|
|
5744
|
-
identity: entry.identity.identity,
|
|
5745
|
-
inline: entry.identity.inline
|
|
5746
|
-
} : {},
|
|
5747
|
-
task: entry.request.task,
|
|
5748
|
-
cwd: entry.request.cwd,
|
|
5749
|
-
runtime: "pi",
|
|
5750
|
-
status: event.state === "starting" ? "queued" : event.state === "running" ? "running" : event.state,
|
|
5751
|
-
startedAt: entry.startedAt,
|
|
5752
|
-
updatedAt: event.timestamp,
|
|
5753
|
-
...event.cost === void 0 ? {} : { cost: event.cost },
|
|
5754
|
-
...event.sessionFile ? { sessionFile: event.sessionFile } : {},
|
|
5755
|
-
...event.message ? {
|
|
5756
|
-
error: status === "failed" || status === "stopped" ? event.message : void 0,
|
|
5757
|
-
summary: event.message
|
|
5758
|
-
} : {}
|
|
5759
|
-
};
|
|
5760
|
-
this.tracker.upsertNative(entry.sessionId, entry.scope, projection);
|
|
5761
|
-
this.projection?.publish(entry.sessionId, projection);
|
|
5762
|
-
if (!status || entry.terminal) return;
|
|
5763
|
-
entry.terminal = true;
|
|
5764
|
-
entry.unsubscribe?.();
|
|
5765
|
-
this.entries.delete(entryKey(entry.sessionId, entry.request.runId));
|
|
5766
|
-
const result = {
|
|
5767
|
-
runId: entry.request.runId,
|
|
5768
|
-
agent: entry.request.agent,
|
|
5769
|
-
...entry.identity ? {
|
|
5770
|
-
identity: entry.identity.identity,
|
|
5771
|
-
inline: entry.identity.inline
|
|
5772
|
-
} : {},
|
|
5773
|
-
task: entry.request.task,
|
|
5774
|
-
cwd: entry.request.cwd,
|
|
5775
|
-
runtime: "pi",
|
|
5776
|
-
state: status,
|
|
5777
|
-
success: status === "completed",
|
|
5778
|
-
summary: event.message ?? (status === "completed" ? "Native child run completed." : `Native child run ${status}.`),
|
|
5779
|
-
durationMs: Math.max(0, event.timestamp - (this.tracker.getNative(entry.sessionId, entry.request.runId)?.startedAt ?? event.timestamp)),
|
|
5780
|
-
sessionId: entry.sessionId,
|
|
5781
|
-
...event.sessionFile ? { sessionFile: event.sessionFile } : {}
|
|
5782
|
-
};
|
|
5783
|
-
if (this.notifier) this.notifier.deliver(result).then((delivered) => {
|
|
5784
|
-
if (delivered) this.tracker.acknowledgeHandoff(entry.sessionId, entry.request.runId);
|
|
5785
|
-
}).catch(() => void 0);
|
|
5786
|
-
}
|
|
5787
|
-
};
|
|
5788
|
-
//#endregion
|
|
5789
5877
|
//#region src/services/pollScheduler/index.ts
|
|
5790
5878
|
/**
|
|
5791
5879
|
* One master tick that drives every background subscriber in the runner
|
|
@@ -6099,16 +6187,16 @@ function createTeamExtensionRuntime(reportConcurrencyEvent, options) {
|
|
|
6099
6187
|
const asyncJobTracker = new AsyncJobTracker();
|
|
6100
6188
|
const admission = new AdmissionGate({ countLiveRuns: (scope) => asyncJobTracker.forSession(scope.rootSessionId, scope).list().filter((job) => job.status === void 0 || !TERMINAL_ASYNC_JOB_STATES.has(job.status)).length });
|
|
6101
6189
|
const subagentWaiter = new SubagentWaiter(asyncJobTracker);
|
|
6102
|
-
const externalProcesses = new
|
|
6190
|
+
const externalProcesses = new require_atomicJson.ExternalProcessIpc();
|
|
6103
6191
|
const asyncSubagentSpawner = new AsyncSubagentSpawner(externalProcesses);
|
|
6104
|
-
const discovery = new require_agentDiscovery.AgentDiscoveryService(options.
|
|
6192
|
+
const discovery = new require_agentDiscovery.AgentDiscoveryService(options.discoveryIo, options.agentConfig);
|
|
6105
6193
|
const skills = new SkillDiscoveryService();
|
|
6106
6194
|
const capabilityPolicies = new require_capabilityCeiling.SubagentCapabilityPolicyStore();
|
|
6107
6195
|
const mcpToolResolver = new McpDirectToolResolverBinding();
|
|
6108
6196
|
const completionNotifier = new CompletionNotifier();
|
|
6109
6197
|
const nativeRuns = new NativeRunCoordinator(options.childSessions, asyncJobTracker, completionNotifier, options.nativeRunProjection);
|
|
6110
6198
|
const teamChannel = new NativeTeamChannelService();
|
|
6111
|
-
const spawnPlanner = new SpawnPlanner(discovery, asyncSubagentSpawner, capabilityPolicies, skills, report, mcpToolResolver, admission, options.childSessions, nativeRuns, teamChannel, options.environment);
|
|
6199
|
+
const spawnPlanner = new SpawnPlanner(discovery, asyncSubagentSpawner, capabilityPolicies, skills, report, mcpToolResolver, admission, options.childSessions, nativeRuns, teamChannel, options.environment, options.agentConfig);
|
|
6112
6200
|
const management = new ManagementActions(asyncJobTracker, nativeRuns, externalProcesses);
|
|
6113
6201
|
const onExternalEvent = (event) => {
|
|
6114
6202
|
const sessionId = event.scope.rootSessionId;
|
|
@@ -6165,6 +6253,7 @@ function createTeamExtensionRuntime(reportConcurrencyEvent, options) {
|
|
|
6165
6253
|
subagentWaiter,
|
|
6166
6254
|
asyncSubagentSpawner,
|
|
6167
6255
|
discovery,
|
|
6256
|
+
agentConfig: options.agentConfig,
|
|
6168
6257
|
skills,
|
|
6169
6258
|
spawnPlanner,
|
|
6170
6259
|
completionNotifier,
|
|
@@ -6246,12 +6335,16 @@ function presentTrackedRun(run) {
|
|
|
6246
6335
|
state: runState(run.status),
|
|
6247
6336
|
rawState: run.status,
|
|
6248
6337
|
task: run.task ?? "",
|
|
6338
|
+
...run.promptWithheld ? { promptWithheld: true } : {},
|
|
6249
6339
|
cwd: run.cwd ?? "",
|
|
6250
6340
|
startedAt: run.startedAt,
|
|
6251
6341
|
...TERMINAL_RUN_STATES.has(run.status) ? { endedAt: lastUpdate } : {},
|
|
6252
6342
|
lastUpdate,
|
|
6253
6343
|
tail: [],
|
|
6254
|
-
|
|
6344
|
+
canSteer: false,
|
|
6345
|
+
...run.tokens === void 0 ? {} : { tokens: run.tokens },
|
|
6346
|
+
...run.toolCount === void 0 ? {} : { toolCount: run.toolCount },
|
|
6347
|
+
...run.cost === void 0 ? {} : { cost: run.cost },
|
|
6255
6348
|
...run.summary === void 0 ? {} : { summary: run.summary },
|
|
6256
6349
|
...run.error === void 0 ? {} : { error: run.error }
|
|
6257
6350
|
};
|
|
@@ -6262,6 +6355,8 @@ function presentNativeRun(run) {
|
|
|
6262
6355
|
agent: run.agent,
|
|
6263
6356
|
...run.identity === void 0 ? {} : { identity: run.identity },
|
|
6264
6357
|
...run.inline === void 0 ? {} : { inline: run.inline },
|
|
6358
|
+
...run.agentDescription === void 0 ? {} : { agentDescription: run.agentDescription },
|
|
6359
|
+
...run.agentFilePath === void 0 ? {} : { agentFilePath: run.agentFilePath },
|
|
6265
6360
|
state: runState(run.status),
|
|
6266
6361
|
rawState: run.status,
|
|
6267
6362
|
task: run.task,
|
|
@@ -6270,7 +6365,14 @@ function presentNativeRun(run) {
|
|
|
6270
6365
|
...TERMINAL_RUN_STATES.has(run.status) ? { endedAt: run.updatedAt } : {},
|
|
6271
6366
|
lastUpdate: run.updatedAt,
|
|
6272
6367
|
tail: [],
|
|
6273
|
-
...run.
|
|
6368
|
+
...run.model === void 0 ? {} : {
|
|
6369
|
+
model: run.model,
|
|
6370
|
+
modelSource: "runtime"
|
|
6371
|
+
},
|
|
6372
|
+
...run.thinking === void 0 ? {} : { thinking: run.thinking },
|
|
6373
|
+
...run.tokens === void 0 ? {} : { tokens: run.tokens },
|
|
6374
|
+
...run.toolCount === void 0 ? {} : { toolCount: run.toolCount },
|
|
6375
|
+
...run.cost === void 0 ? {} : { cost: run.cost },
|
|
6274
6376
|
...run.summary === void 0 ? {} : { summary: run.summary },
|
|
6275
6377
|
...run.error === void 0 ? {} : { error: run.error }
|
|
6276
6378
|
};
|
|
@@ -6280,7 +6382,7 @@ function publishRuns(directEvents, sessionId, jobs, nativeRuns) {
|
|
|
6280
6382
|
runs.push(...[...nativeRuns.values()].map(presentNativeRun));
|
|
6281
6383
|
directEvents.publish(SUBAGENT_RUNS_TYPE, sessionId, { runs });
|
|
6282
6384
|
}
|
|
6283
|
-
const TEAM_COST_STATUS = "
|
|
6385
|
+
const TEAM_COST_STATUS = "po-team-cost";
|
|
6284
6386
|
const COST_DECIMALS = 6;
|
|
6285
6387
|
function updateTeamCost(client, jobs, nativeRuns, costs, previousText, attached, force = false) {
|
|
6286
6388
|
const trackedCosts = /* @__PURE__ */ new Map();
|
|
@@ -6300,20 +6402,20 @@ function updateTeamCost(client, jobs, nativeRuns, costs, previousText, attached,
|
|
|
6300
6402
|
function recordDelegationObservation(telemetry, observation) {
|
|
6301
6403
|
if (observation.kind === "requested") {
|
|
6302
6404
|
const { event } = observation;
|
|
6303
|
-
telemetry.recordEvent("
|
|
6405
|
+
telemetry.recordEvent("po_team.delegation_requested", {
|
|
6304
6406
|
"agent.name": event.agent,
|
|
6305
6407
|
"task.id": event.taskId,
|
|
6306
6408
|
mode: event.runMode ?? "foreground"
|
|
6307
6409
|
});
|
|
6308
6410
|
} else if (observation.kind === "started") {
|
|
6309
6411
|
const { event } = observation;
|
|
6310
|
-
telemetry.recordEvent("
|
|
6412
|
+
telemetry.recordEvent("po_team.child_started", {
|
|
6311
6413
|
"run.id": event.runId,
|
|
6312
6414
|
outcome: "started"
|
|
6313
6415
|
});
|
|
6314
6416
|
} else if (observation.kind === "updated") {
|
|
6315
6417
|
const { event } = observation;
|
|
6316
|
-
telemetry.recordEvent("
|
|
6418
|
+
telemetry.recordEvent("po_team.delegation_updated", {
|
|
6317
6419
|
"run.id": event.runId,
|
|
6318
6420
|
"team.tool_count": event.toolCount ?? 0,
|
|
6319
6421
|
"team.duration_ms": event.durationMs ?? 0,
|
|
@@ -6322,43 +6424,61 @@ function recordDelegationObservation(telemetry, observation) {
|
|
|
6322
6424
|
});
|
|
6323
6425
|
} else if (observation.kind === "finished") {
|
|
6324
6426
|
const { event } = observation;
|
|
6325
|
-
telemetry.recordEvent("
|
|
6427
|
+
telemetry.recordEvent("po_team.delegation_finished", {
|
|
6326
6428
|
"run.id": event.runId,
|
|
6327
6429
|
"team.tool_count": event.toolCount ?? 0,
|
|
6328
6430
|
"team.duration_ms": event.durationMs ?? 0,
|
|
6329
6431
|
outcome: event.status
|
|
6330
6432
|
});
|
|
6331
|
-
} else telemetry.recordEvent("
|
|
6433
|
+
} else telemetry.recordEvent("po_team.delegation_cancelled", { outcome: "cancelled" });
|
|
6332
6434
|
}
|
|
6333
6435
|
const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host: serverHost, agent: host }) => {
|
|
6334
6436
|
if (!host) throw new Error("Team session requires the headless host.");
|
|
6335
|
-
if (serverHost.context.environment === void 0) throw new Error("Team
|
|
6437
|
+
if (serverHost.context.environment === void 0) throw new Error("Team server plugin requires an admitted session environment.");
|
|
6336
6438
|
const directEvents = serverHost.context.directEvents;
|
|
6337
|
-
if (directEvents === void 0) throw new Error("Team
|
|
6439
|
+
if (directEvents === void 0) throw new Error("Team server plugin requires host-owned direct events.");
|
|
6338
6440
|
const execution = {
|
|
6339
6441
|
...host.context,
|
|
6340
6442
|
get model() {
|
|
6341
6443
|
return host.context.model;
|
|
6444
|
+
},
|
|
6445
|
+
get selection() {
|
|
6446
|
+
return host.context.selection;
|
|
6342
6447
|
}
|
|
6343
6448
|
};
|
|
6344
6449
|
const sessionPeers = /* @__PURE__ */ new Set();
|
|
6345
6450
|
const stopPeerDiscovery = serverHost.context.sessionCommunication?.onPeerReady((id) => sessionPeers.add(id));
|
|
6346
|
-
const telemetry = (0, _agimon_ai_po_telemetry.
|
|
6347
|
-
serviceName: "
|
|
6451
|
+
const telemetry = (0, _agimon_ai_po_telemetry.createPoTelemetry)({
|
|
6452
|
+
serviceName: "po-team",
|
|
6348
6453
|
packageName: "@agimon-ai/po-team",
|
|
6349
6454
|
cwd: execution.cwd,
|
|
6350
6455
|
env: serverHost.context.environment,
|
|
6351
6456
|
enableLogs: true,
|
|
6352
6457
|
enableTraces: true
|
|
6353
6458
|
});
|
|
6459
|
+
const environment = serverHost.context.environment;
|
|
6460
|
+
const fs = (0, _agimon_ai_po_core_platform.requirePoFs)(context);
|
|
6461
|
+
const homeDirectory = environment.HOME ?? _agimon_ai_po_core_platform.nodeHost.homeDirectory();
|
|
6354
6462
|
const runtime = createTeamExtensionRuntime((event, attributes) => {
|
|
6355
6463
|
telemetry.recordEvent(event, attributes);
|
|
6356
6464
|
}, {
|
|
6357
|
-
environment
|
|
6358
|
-
|
|
6465
|
+
environment,
|
|
6466
|
+
discoveryIo: {
|
|
6467
|
+
fs,
|
|
6468
|
+
context: _agimon_ai_po_core_platform.BACKGROUND_CONTEXT,
|
|
6469
|
+
environment,
|
|
6470
|
+
homeDirectory,
|
|
6471
|
+
configDirName: require_agentDiscovery.getConfigDirName(environment)
|
|
6472
|
+
},
|
|
6473
|
+
agentConfig: new TeamAgentConfigService({
|
|
6474
|
+
fs,
|
|
6475
|
+
environment,
|
|
6476
|
+
homeDirectory
|
|
6477
|
+
}),
|
|
6478
|
+
childSessions: { get: () => (0, _agimon_ai_po_core_childSession.readPoChildSessionService)(context) },
|
|
6359
6479
|
nativeRunProjection
|
|
6360
6480
|
});
|
|
6361
|
-
const scope =
|
|
6481
|
+
const scope = require_atomicJson.createSessionScope(execution.sessionId);
|
|
6362
6482
|
runtime.management.bindSessionScope(scope);
|
|
6363
6483
|
const jobs = runtime.asyncJobTracker.forSession(execution.sessionId, scope);
|
|
6364
6484
|
const bridge = createDelegationBridge({
|
|
@@ -6378,9 +6498,6 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
|
|
|
6378
6498
|
telemetry.recordEvent(event, attributes);
|
|
6379
6499
|
}
|
|
6380
6500
|
});
|
|
6381
|
-
let ownedReadiness;
|
|
6382
|
-
let ready;
|
|
6383
|
-
const startupAbort = new AbortController();
|
|
6384
6501
|
const nativeRuns = /* @__PURE__ */ new Map();
|
|
6385
6502
|
const childCosts = /* @__PURE__ */ new Map();
|
|
6386
6503
|
let costText;
|
|
@@ -6418,7 +6535,8 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
|
|
|
6418
6535
|
});
|
|
6419
6536
|
if (options?.triggerTurn === false) return;
|
|
6420
6537
|
if (!execution.session.admitPrompt) throw new Error("The session cannot admit a completion prompt.");
|
|
6421
|
-
|
|
6538
|
+
const runIds = details.map((detail) => detail.runId).toSorted();
|
|
6539
|
+
await execution.session.admitPrompt(message.content, "steer", void 0, runIds.length ? `subagent-report:${runIds.join(",")}` : void 0);
|
|
6422
6540
|
});
|
|
6423
6541
|
deliveries = delivery.catch(() => void 0);
|
|
6424
6542
|
return delivery;
|
|
@@ -6431,16 +6549,26 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
|
|
|
6431
6549
|
});
|
|
6432
6550
|
if (options?.triggerTurn === false) return;
|
|
6433
6551
|
const delivery = deliveries.then(async () => {
|
|
6434
|
-
if (!execution.session.
|
|
6435
|
-
await execution.session.
|
|
6552
|
+
if (!execution.session.admitMessage) throw new Error("The session cannot admit an intercom message.");
|
|
6553
|
+
await execution.session.admitMessage({
|
|
6554
|
+
type: message.customType,
|
|
6555
|
+
text,
|
|
6556
|
+
display: message.display,
|
|
6557
|
+
details: message.details
|
|
6558
|
+
}, "steer");
|
|
6436
6559
|
});
|
|
6437
6560
|
deliveries = delivery.catch(() => void 0);
|
|
6438
6561
|
return delivery;
|
|
6439
6562
|
} });
|
|
6440
6563
|
const intercom = createHeadlessIntercomTool(channel, {
|
|
6441
6564
|
sessionId: execution.sessionId,
|
|
6442
|
-
|
|
6443
|
-
|
|
6565
|
+
name: () => serverHost.context.sessionCommunication?.sessionName,
|
|
6566
|
+
peers: () => [...sessionPeers].filter((id) => serverHost.context.sessionService?.canCommunicate?.(execution.sessionId, id) === true).flatMap((id) => {
|
|
6567
|
+
const peer = serverHost.context.sessionCommunication?.describePeer?.(id);
|
|
6568
|
+
return peer === void 0 ? [] : [peer];
|
|
6569
|
+
}),
|
|
6570
|
+
canCommunicate: (id) => serverHost.context.sessionService?.canCommunicate?.(execution.sessionId, id) === true,
|
|
6571
|
+
delivery: () => (0, _agimon_ai_po_session.readPoSessionDelivery)(context)
|
|
6444
6572
|
});
|
|
6445
6573
|
const serverService = (ctx) => {
|
|
6446
6574
|
ctx.plugin((providerContext) => {
|
|
@@ -6450,12 +6578,18 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
|
|
|
6450
6578
|
sessionScope: scope,
|
|
6451
6579
|
cwd: execution.cwd,
|
|
6452
6580
|
environment: serverHost.context.environment,
|
|
6453
|
-
|
|
6454
|
-
|
|
6581
|
+
availableModels: () => availableModelInfos(execution),
|
|
6582
|
+
repoRoot: execution.repoRoot,
|
|
6583
|
+
get parentSelection() {
|
|
6584
|
+
return execution.selection;
|
|
6455
6585
|
},
|
|
6456
6586
|
get parentModel() {
|
|
6457
6587
|
return execution.model;
|
|
6458
6588
|
},
|
|
6589
|
+
reportWarning: (body) => execution.client.notify({
|
|
6590
|
+
body,
|
|
6591
|
+
level: "warning"
|
|
6592
|
+
}),
|
|
6459
6593
|
captureForkSource: () => execution.session.forkSource?.()
|
|
6460
6594
|
},
|
|
6461
6595
|
directRunTracker: runtime.asyncJobTracker,
|
|
@@ -6464,9 +6598,16 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
|
|
|
6464
6598
|
policies: runtime.capabilityPolicies,
|
|
6465
6599
|
observeDelegation: (observation) => recordDelegationObservation(telemetry, observation)
|
|
6466
6600
|
});
|
|
6467
|
-
providerContext.inject([
|
|
6468
|
-
|
|
6469
|
-
|
|
6601
|
+
providerContext.inject([_agimon_ai_po_config.PO_CONFIG_SERVICE], (configContext) => {
|
|
6602
|
+
const config = configContext.get(_agimon_ai_po_config.PO_CONFIG_SERVICE);
|
|
6603
|
+
if (!config) throw new Error("Team requires the session Po config service.");
|
|
6604
|
+
const unbind = runtime.agentConfig.bind(() => config.getSnapshot());
|
|
6605
|
+
publishCatalog();
|
|
6606
|
+
return unbind;
|
|
6607
|
+
});
|
|
6608
|
+
providerContext.inject([_agimon_ai_po_core_mcpToolResolver.PO_MCP_TOOL_RESOLVER_SERVICE], (resolverContext) => runtime.mcpToolResolver.bind((0, _agimon_ai_po_core_mcpToolResolver.requirePoMcpToolResolver)(resolverContext)));
|
|
6609
|
+
providerContext.inject([_agimon_ai_po_core_contextContributions.PO_CONTEXT_CONTRIBUTIONS_SERVICE], (contributionContext) => {
|
|
6610
|
+
const registration = (0, _agimon_ai_po_core_contextContributions.requirePoContextContributions)(contributionContext).register({
|
|
6470
6611
|
source: "@agimon-ai/po-team",
|
|
6471
6612
|
id: "runtime",
|
|
6472
6613
|
label: "Team",
|
|
@@ -6475,30 +6616,96 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
|
|
|
6475
6616
|
});
|
|
6476
6617
|
return () => registration.dispose();
|
|
6477
6618
|
});
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
});
|
|
6491
|
-
telemetry.recordEvent("doom_team.runs_restored", {
|
|
6492
|
-
"team.suspended_count": opened.suspended.length,
|
|
6493
|
-
"team.pruned_count": opened.pruned.length,
|
|
6494
|
-
"team.reaped_count": opened.reaped,
|
|
6495
|
-
outcome: "reported"
|
|
6496
|
-
});
|
|
6497
|
-
return { value: void 0 };
|
|
6619
|
+
});
|
|
6620
|
+
};
|
|
6621
|
+
const publishCatalog = async () => {
|
|
6622
|
+
if (!activityAttached) return;
|
|
6623
|
+
try {
|
|
6624
|
+
const discovered = (await runtime.discovery.discover(execution.cwd, "both")).agents;
|
|
6625
|
+
const models = (await runtime.agentConfig.currentOrUndefined())?.models ?? [];
|
|
6626
|
+
if (!activityAttached) return;
|
|
6627
|
+
directEvents.publish(SUBAGENT_CATALOG_TYPE, execution.sessionId, {
|
|
6628
|
+
cwd: execution.cwd,
|
|
6629
|
+
agents: presentCatalog(discovered),
|
|
6630
|
+
models: catalogModels(discovered, [...models])
|
|
6498
6631
|
});
|
|
6632
|
+
} catch (error) {
|
|
6633
|
+
if (!activityAttached) return;
|
|
6634
|
+
directEvents.publish(SUBAGENT_CATALOG_TYPE, execution.sessionId, {
|
|
6635
|
+
cwd: execution.cwd,
|
|
6636
|
+
agents: [],
|
|
6637
|
+
models: [],
|
|
6638
|
+
warning: error instanceof Error ? error.message : String(error)
|
|
6639
|
+
});
|
|
6640
|
+
}
|
|
6641
|
+
};
|
|
6642
|
+
const activity = {
|
|
6643
|
+
name: "@agimon-ai/po-team",
|
|
6644
|
+
async start(activityContext) {
|
|
6645
|
+
activityAttached = true;
|
|
6646
|
+
publishCost(true);
|
|
6647
|
+
publishRunSnapshot();
|
|
6648
|
+
await publishCatalog();
|
|
6649
|
+
try {
|
|
6650
|
+
channel.bindMainSession(activityContext.sessionId);
|
|
6651
|
+
return () => {
|
|
6652
|
+
if (!activityAttached) return;
|
|
6653
|
+
activityAttached = false;
|
|
6654
|
+
channel.dispose();
|
|
6655
|
+
execution.client.setStatus(TEAM_COST_STATUS, void 0);
|
|
6656
|
+
};
|
|
6657
|
+
} catch (error) {
|
|
6658
|
+
activityAttached = false;
|
|
6659
|
+
execution.client.setStatus(TEAM_COST_STATUS, void 0);
|
|
6660
|
+
throw error;
|
|
6661
|
+
}
|
|
6662
|
+
}
|
|
6663
|
+
};
|
|
6664
|
+
/**
|
|
6665
|
+
* Re-attaches the runs this session stored before a restart. Called from `session_start`, once the session can
|
|
6666
|
+
* take a completion and before its Harness resumes: a running child gets its lane and intercom back first, and
|
|
6667
|
+
* a finished one reports its completion now.
|
|
6668
|
+
*/
|
|
6669
|
+
const restoreRuns = async () => {
|
|
6670
|
+
const report = (subject, error) => execution.client.notify({
|
|
6671
|
+
body: `${subject}: ${error instanceof Error ? error.message : String(error)}`,
|
|
6672
|
+
level: "warning"
|
|
6673
|
+
});
|
|
6674
|
+
let stored = [];
|
|
6675
|
+
try {
|
|
6676
|
+
stored = await (0, _agimon_ai_po_core_childSession.readPoChildSessionService)(context)?.stored?.() ?? [];
|
|
6677
|
+
} catch (error) {
|
|
6678
|
+
await report("Stored subagent runs could not be read", error);
|
|
6679
|
+
}
|
|
6680
|
+
let restored = 0;
|
|
6681
|
+
for (const run of stored) {
|
|
6682
|
+
const identity = storedRunIdentity(run);
|
|
6683
|
+
const intercom = run.settled ? void 0 : runtime.teamChannel.createNativeChildIntercom({
|
|
6684
|
+
rootSessionId: run.request.scope.rootSessionId,
|
|
6685
|
+
agent: run.request.agent,
|
|
6686
|
+
...identity ? {
|
|
6687
|
+
identity: identity.identity,
|
|
6688
|
+
inline: identity.inline
|
|
6689
|
+
} : {},
|
|
6690
|
+
runId: run.request.runId,
|
|
6691
|
+
task: {
|
|
6692
|
+
id: run.request.runId,
|
|
6693
|
+
subject: run.request.task
|
|
6694
|
+
}
|
|
6695
|
+
});
|
|
6696
|
+
try {
|
|
6697
|
+
await runtime.nativeRuns.restore(run.request.parentSessionId, run, intercom);
|
|
6698
|
+
restored += 1;
|
|
6699
|
+
} catch (error) {
|
|
6700
|
+
intercom?.dispose?.();
|
|
6701
|
+
await report(`Subagent run ${run.request.runId} could not resume`, error);
|
|
6702
|
+
}
|
|
6703
|
+
}
|
|
6704
|
+
telemetry.recordEvent("po_team.runs_restored", {
|
|
6705
|
+
"team.restored_count": restored,
|
|
6706
|
+
outcome: "restored"
|
|
6499
6707
|
});
|
|
6500
6708
|
};
|
|
6501
|
-
const environment = serverHost.context.environment;
|
|
6502
6709
|
return {
|
|
6503
6710
|
value: {
|
|
6504
6711
|
runtime,
|
|
@@ -6509,96 +6716,63 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ context, host:
|
|
|
6509
6716
|
channel,
|
|
6510
6717
|
intercom,
|
|
6511
6718
|
directEvents,
|
|
6512
|
-
environment: serverHost.context.environment
|
|
6719
|
+
environment: serverHost.context.environment,
|
|
6720
|
+
restoreRuns
|
|
6513
6721
|
},
|
|
6514
6722
|
services: [
|
|
6515
6723
|
(context) => {
|
|
6516
|
-
if ((0, _agimon_ai_po_core_backgroundWork.
|
|
6724
|
+
if ((0, _agimon_ai_po_core_backgroundWork.readPoBackgroundWorkService)(context) === void 0) (0, _agimon_ai_po_session.provideBackgroundWorkService)(context);
|
|
6517
6725
|
},
|
|
6518
6726
|
serverService,
|
|
6727
|
+
(context) => context.provide(PO_TEAM_AGENT_CONFIG_SERVICE, runtime.agentConfig),
|
|
6728
|
+
(context) => context.provide(_agimon_ai_po_core_childSession.PO_CHILD_SESSION_LABELS_SERVICE, { labelFor: (runId) => nativeRuns.get(runId)?.identity }),
|
|
6519
6729
|
mountMcpTools([intercom, createHeadlessSubagentTool(runtime, execution)])
|
|
6520
6730
|
],
|
|
6521
|
-
activities: [
|
|
6522
|
-
name: "@agimon-ai/po-team",
|
|
6523
|
-
async start(activityContext) {
|
|
6524
|
-
activityAttached = true;
|
|
6525
|
-
publishCost(true);
|
|
6526
|
-
publishRunSnapshot();
|
|
6527
|
-
try {
|
|
6528
|
-
const discovered = runtime.discovery.discover(execution.cwd, "both").agents;
|
|
6529
|
-
directEvents.publish(SUBAGENT_CATALOG_TYPE, execution.sessionId, {
|
|
6530
|
-
cwd: execution.cwd,
|
|
6531
|
-
agents: presentCatalog(discovered),
|
|
6532
|
-
models: catalogModels(discovered, require_agentDiscovery.resolveActiveTeamModelSpecs(environment) ?? [])
|
|
6533
|
-
});
|
|
6534
|
-
} catch (error) {
|
|
6535
|
-
directEvents.publish(SUBAGENT_CATALOG_TYPE, execution.sessionId, {
|
|
6536
|
-
cwd: execution.cwd,
|
|
6537
|
-
agents: [],
|
|
6538
|
-
models: [],
|
|
6539
|
-
warning: error instanceof Error ? error.message : String(error)
|
|
6540
|
-
});
|
|
6541
|
-
}
|
|
6542
|
-
try {
|
|
6543
|
-
channel.bindMainSession(activityContext.sessionId);
|
|
6544
|
-
return () => {
|
|
6545
|
-
if (!activityAttached) return;
|
|
6546
|
-
activityAttached = false;
|
|
6547
|
-
channel.dispose();
|
|
6548
|
-
execution.client.setStatus(TEAM_COST_STATUS, void 0);
|
|
6549
|
-
};
|
|
6550
|
-
} catch (error) {
|
|
6551
|
-
activityAttached = false;
|
|
6552
|
-
execution.client.setStatus(TEAM_COST_STATUS, void 0);
|
|
6553
|
-
throw error;
|
|
6554
|
-
}
|
|
6555
|
-
}
|
|
6556
|
-
}],
|
|
6731
|
+
activities: [activity],
|
|
6557
6732
|
async onStart() {
|
|
6558
6733
|
runtime.pollScheduler.start();
|
|
6559
|
-
telemetry.recordEvent("
|
|
6560
|
-
if (!ready) throw new Error("Team readiness was not installed.");
|
|
6561
|
-
await Promise.allSettled([ready.wait()]);
|
|
6734
|
+
telemetry.recordEvent("po_team.session_started", { "team.root_session": (0, _agimon_ai_po_core_childProcess.resolveRootSessionId)(execution.sessionId, environment) === execution.sessionId });
|
|
6562
6735
|
},
|
|
6563
6736
|
async onDispose() {
|
|
6564
6737
|
disposing = true;
|
|
6565
|
-
startupAbort.abort(/* @__PURE__ */ new Error("Team session ended."));
|
|
6566
|
-
await Promise.allSettled([...ready ? [ready.wait()] : [], ...ownedReadiness ? [ownedReadiness.dispose()] : []]);
|
|
6567
6738
|
activityAttached = false;
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6739
|
+
let stoppedRuns;
|
|
6740
|
+
await (0, _agimon_ai_po_core_extensionFile.runCleanups)([
|
|
6741
|
+
() => stopPeerDiscovery?.(),
|
|
6742
|
+
() => sessionPeers.clear(),
|
|
6743
|
+
() => execution.client.setStatus(TEAM_COST_STATUS, void 0),
|
|
6744
|
+
() => channel.dispose(),
|
|
6745
|
+
() => runtime.completionNotifier.dispose(),
|
|
6746
|
+
async () => {
|
|
6747
|
+
stoppedRuns = await stopScopeRuns({
|
|
6748
|
+
reason: "headless session ended",
|
|
6749
|
+
jobs: jobs.list(),
|
|
6750
|
+
stop: (runId, reason) => runtime.management.stop(runId, reason)
|
|
6751
|
+
});
|
|
6752
|
+
},
|
|
6753
|
+
() => (0, _agimon_ai_po_core_extensionFile.runCleanups)([() => runtime.nativeRuns.close(), () => nativeRunProjection.dispose(execution.sessionId)], "Native Team runs cleanup failed."),
|
|
6754
|
+
unsubscribeCostTracker,
|
|
6755
|
+
unsubscribeCostNative,
|
|
6756
|
+
() => nativeRuns.clear(),
|
|
6757
|
+
() => childCosts.clear(),
|
|
6758
|
+
() => {
|
|
6759
|
+
costText = void 0;
|
|
6760
|
+
},
|
|
6761
|
+
() => bridge.abandonAll(),
|
|
6762
|
+
() => fablePlan.abandonAll(),
|
|
6763
|
+
() => runtime.capabilityPolicies.clear(),
|
|
6764
|
+
() => runtime.management.releaseSessionScope(scope),
|
|
6765
|
+
() => runtime.dispose(),
|
|
6766
|
+
() => runtime.asyncJobTracker.stop(),
|
|
6767
|
+
() => runtime.pollScheduler.stop(),
|
|
6768
|
+
() => telemetry.recordEvent("po_team.session_finished", {
|
|
6769
|
+
reason: "headless session ended",
|
|
6770
|
+
"team.stopped_count": stoppedRuns?.stopped.length ?? 0,
|
|
6771
|
+
"team.unstoppable_count": stoppedRuns?.unstoppable.length ?? 0,
|
|
6772
|
+
outcome: stoppedRuns && !stoppedRuns.unstoppable.length ? "stopped" : "degraded"
|
|
6773
|
+
}),
|
|
6774
|
+
() => telemetry.shutdown()
|
|
6775
|
+
], "Team cleanup failed.");
|
|
6602
6776
|
}
|
|
6603
6777
|
};
|
|
6604
6778
|
});
|
|
@@ -6664,13 +6838,9 @@ var subagent_catalog_default = (0, _agimon_ai_po_core_extensionFile.defineChanne
|
|
|
6664
6838
|
var subagent_catalog_server_default = (0, _agimon_ai_po_core_extensionFile.defineChannel)(subagent_catalog_default);
|
|
6665
6839
|
//#endregion
|
|
6666
6840
|
//#region src/extensions/(backend)/channel/_lib/subagent-runs.ts
|
|
6667
|
-
const RUN_ID_PATTERN = /^[\w.-]+$/;
|
|
6668
6841
|
function isSubagentRunsPayload(value) {
|
|
6669
6842
|
return typeof value === "object" && value !== null && Array.isArray(value.runs);
|
|
6670
6843
|
}
|
|
6671
|
-
function publicPayload(payload) {
|
|
6672
|
-
return { runs: payload.runs.map(({ sessionFile: _sessionFile, ...run }) => run) };
|
|
6673
|
-
}
|
|
6674
6844
|
/**
|
|
6675
6845
|
* The built-in subagents data channel consumes current state from the
|
|
6676
6846
|
* host-owned direct event bus. Its bounded latest replay seeds late subscribers.
|
|
@@ -6685,16 +6855,34 @@ function createSubagentsChannel() {
|
|
|
6685
6855
|
const publish = (scope, payload) => {
|
|
6686
6856
|
if (scopes.get(scope.sessionId) !== scope) return;
|
|
6687
6857
|
latest.set(scope.sessionId, payload);
|
|
6688
|
-
host.publish(scope.sessionId,
|
|
6858
|
+
host.publish(scope.sessionId, payload);
|
|
6689
6859
|
};
|
|
6690
6860
|
return {
|
|
6691
|
-
|
|
6692
|
-
const payload =
|
|
6693
|
-
|
|
6861
|
+
homeFor(scope) {
|
|
6862
|
+
const payload = latest.get(scope.sessionId);
|
|
6863
|
+
if (!payload) return {
|
|
6864
|
+
coverage: "unavailable",
|
|
6865
|
+
entities: []
|
|
6866
|
+
};
|
|
6867
|
+
return {
|
|
6868
|
+
coverage: payload.runs.length > _agimon_ai_po_core_hubChannel.HOME_ENTITY_LIMIT ? "partial" : "ready",
|
|
6869
|
+
entities: payload.runs.slice(0, _agimon_ai_po_core_hubChannel.HOME_ENTITY_LIMIT).map((run) => ({
|
|
6870
|
+
id: (0, node_crypto.createHash)("sha256").update(JSON.stringify([
|
|
6871
|
+
scope.workspaceId ?? scope.cwd,
|
|
6872
|
+
scope.sessionId,
|
|
6873
|
+
run.runId,
|
|
6874
|
+
run.startedAt
|
|
6875
|
+
])).digest("hex"),
|
|
6876
|
+
kind: run.state === "failed" ? "failure" : run.state === "done" ? "completed" : run.state === "stopped" ? "paused" : run.state,
|
|
6877
|
+
title: (run.taskRef || run.task || run.agent).slice(0, 160),
|
|
6878
|
+
...(run.error || run.currentTool)?.trim() ? { detail: (run.error || run.currentTool).slice(0, 320) } : {},
|
|
6879
|
+
updatedAt: new Date(run.lastUpdate).toISOString(),
|
|
6880
|
+
sessionId: scope.sessionId
|
|
6881
|
+
}))
|
|
6882
|
+
};
|
|
6694
6883
|
},
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
return (latest.get(scope.sessionId)?.runs.find((run) => run.runId === runId))?.sessionFile;
|
|
6884
|
+
payloadFor(scope) {
|
|
6885
|
+
return scopes.has(scope.sessionId) ? latest.get(scope.sessionId) : void 0;
|
|
6698
6886
|
},
|
|
6699
6887
|
sessionAdded(scope) {
|
|
6700
6888
|
subscriptions.get(scope.sessionId)?.();
|
|
@@ -6750,16 +6938,11 @@ function isStopRequest(value) {
|
|
|
6750
6938
|
}
|
|
6751
6939
|
/** The typed error's text carries a recovery hint written for the model, so a missing run gets a sentence for people. */
|
|
6752
6940
|
function controlFailure(error) {
|
|
6753
|
-
if (error instanceof
|
|
6941
|
+
if (error instanceof PoTeamExpectedError && error.code === "run_not_found") return Response.json({ error: "This run is not active." }, { status: 404 });
|
|
6754
6942
|
return Response.json({ error: error instanceof Error ? error.message : String(error) }, { status: 409 });
|
|
6755
6943
|
}
|
|
6756
6944
|
/** Serves catalog discovery, run launch, and run steer and stop from the selected session process, never through a parent prompt. */
|
|
6757
6945
|
function createTeamApiHandler(options) {
|
|
6758
|
-
const discovery = new require_agentDiscovery.AgentDiscoveryService(options.environment);
|
|
6759
|
-
const read = options.read ?? ((cwd) => ({
|
|
6760
|
-
agents: discovery.discover(cwd, "both").agents,
|
|
6761
|
-
models: require_agentDiscovery.resolveActiveTeamModelSpecs(options.environment) ?? []
|
|
6762
|
-
}));
|
|
6763
6946
|
return {
|
|
6764
6947
|
async fetch(request) {
|
|
6765
6948
|
const url = new URL(request.url);
|
|
@@ -6810,8 +6993,8 @@ function createTeamApiHandler(options) {
|
|
|
6810
6993
|
}
|
|
6811
6994
|
if (request.method !== "GET" || url.pathname !== "/catalog") return Response.json({ error: "Not found." }, { status: 404 });
|
|
6812
6995
|
try {
|
|
6813
|
-
|
|
6814
|
-
const snapshot = read(options.cwd);
|
|
6996
|
+
options.invalidate?.();
|
|
6997
|
+
const snapshot = await options.read(options.cwd);
|
|
6815
6998
|
return Response.json({
|
|
6816
6999
|
cwd: options.cwd,
|
|
6817
7000
|
agents: presentCatalog(snapshot.agents),
|
|
@@ -6827,7 +7010,7 @@ function createTeamApiHandler(options) {
|
|
|
6827
7010
|
}
|
|
6828
7011
|
/** One mounted session API, backed by the Team runtime that owns the subagent tool. */
|
|
6829
7012
|
function createTeamSessionApi(runtime, execution) {
|
|
6830
|
-
const scope =
|
|
7013
|
+
const scope = require_atomicJson.createSessionScope(execution.sessionId);
|
|
6831
7014
|
const jobs = runtime.asyncJobTracker.forSession(execution.sessionId, scope);
|
|
6832
7015
|
const launch = async (request) => {
|
|
6833
7016
|
const parentForkSource = request.fork ? await execution.session.forkSource?.() : void 0;
|
|
@@ -6844,9 +7027,11 @@ function createTeamSessionApi(runtime, execution) {
|
|
|
6844
7027
|
sessionScope: scope,
|
|
6845
7028
|
environment: execution.environment,
|
|
6846
7029
|
parentSessionId: execution.sessionId,
|
|
7030
|
+
parentSelection: execution.selection,
|
|
6847
7031
|
...parentForkSource ? { parentForkSource } : {},
|
|
6848
|
-
availableModels:
|
|
6849
|
-
...execution.model ? { parentModel: execution.model } : {}
|
|
7032
|
+
availableModels: await availableModelInfos(execution),
|
|
7033
|
+
...execution.model ? { parentModel: execution.model } : {},
|
|
7034
|
+
sender: HUMAN_SENDER
|
|
6850
7035
|
}, loadConfig().config)).outcomes[0];
|
|
6851
7036
|
if (!outcome?.runId) throw new Error(outcome?.error ?? "The agent did not start.");
|
|
6852
7037
|
jobs.track(outcome.runId, outcome.identity ? {
|
|
@@ -6859,9 +7044,16 @@ function createTeamSessionApi(runtime, execution) {
|
|
|
6859
7044
|
basePath: TEAM_API_BASE_PATH,
|
|
6860
7045
|
start: () => createTeamApiHandler({
|
|
6861
7046
|
cwd: execution.cwd,
|
|
6862
|
-
|
|
7047
|
+
read: async (cwd) => ({
|
|
7048
|
+
agents: (await runtime.discovery.discover(cwd, "both")).agents,
|
|
7049
|
+
models: [...(await runtime.agentConfig.currentOrUndefined())?.models ?? []]
|
|
7050
|
+
}),
|
|
7051
|
+
invalidate: () => runtime.discovery.invalidate(),
|
|
6863
7052
|
launch,
|
|
6864
|
-
steer: (request, signal) => runtime.management.steer(request.runId,
|
|
7053
|
+
steer: (request, signal) => runtime.management.steer(request.runId, {
|
|
7054
|
+
text: request.message,
|
|
7055
|
+
sender: HUMAN_SENDER
|
|
7056
|
+
}, void 0, signal),
|
|
6865
7057
|
stop: (request) => runtime.management.stop(request.runId)
|
|
6866
7058
|
})
|
|
6867
7059
|
};
|
|
@@ -6871,6 +7063,12 @@ var route_server_default$1 = (context) => createTeamSessionApi(context.root.runt
|
|
|
6871
7063
|
//#region src/extensions/workspaces/sessions/(backend)/api/route.server.ts
|
|
6872
7064
|
var route_server_default = (0, _agimon_ai_po_core_extensionFile.defineRoute)(route_server_default$1);
|
|
6873
7065
|
//#endregion
|
|
7066
|
+
//#region src/extensions/workspaces/sessions/(backend)/hook/sessionStart.server.ts
|
|
7067
|
+
var sessionStart_server_default = (0, _agimon_ai_po_core_extensionFile.defineHook)(({ root }) => ({
|
|
7068
|
+
event: "session_start",
|
|
7069
|
+
handle: () => root.restoreRuns()
|
|
7070
|
+
}));
|
|
7071
|
+
//#endregion
|
|
6874
7072
|
//#region src/extensions/workspaces/sessions/(backend)/resource/_lib/team.server.ts
|
|
6875
7073
|
/**
|
|
6876
7074
|
* The roster the model is allowed to see.
|
|
@@ -6879,7 +7077,7 @@ var route_server_default = (0, _agimon_ai_po_core_extensionFile.defineRoute)(rou
|
|
|
6879
7077
|
* `TeamMemberContext`, whose `token` is a session capability documented as never
|
|
6880
7078
|
* leaving the direct context. A context resource is pasted into the system prompt,
|
|
6881
7079
|
* sent to the provider and persisted, so the raw struct must not be serialized here.
|
|
6882
|
-
* `formatTeamContextSnapshot` is the same projection the Pi
|
|
7080
|
+
* `formatTeamContextSnapshot` is the same projection the Pi extension renders.
|
|
6883
7081
|
*/
|
|
6884
7082
|
var team_server_default$1 = (context) => ({
|
|
6885
7083
|
name: "po/team",
|
|
@@ -6901,21 +7099,24 @@ var subagent_server_default = (0, _agimon_ai_po_core_extensionFile.defineServerT
|
|
|
6901
7099
|
//#endregion
|
|
6902
7100
|
//#region generated/server.ts
|
|
6903
7101
|
const at = (value, context) => typeof value === "function" ? value(context) : value;
|
|
7102
|
+
/* v8 ignore next -- generated normalization branch */
|
|
7103
|
+
const defined = (values) => values.filter((value) => value !== void 0);
|
|
6904
7104
|
const via = (identity, value) => value === void 0 ? void 0 : {
|
|
6905
7105
|
...identity,
|
|
6906
7106
|
...value
|
|
6907
7107
|
};
|
|
6908
|
-
const
|
|
7108
|
+
const serverPlugin = (0, _agimon_ai_po_core_serverPlugin.defineServerPlugin)({
|
|
6909
7109
|
name: "@agimon-ai/po-team",
|
|
6910
|
-
providerOverrides: (0,
|
|
7110
|
+
providerOverrides: (0, _agimon_ai_po_core_serverPlugin.composeServerProviderOverrides)(root_server_default),
|
|
7111
|
+
injects: (0, _agimon_ai_po_core_extensionFile.composeRootInjects)({ session: [root_server_default] }),
|
|
6911
7112
|
global: () => ({ get channels() {
|
|
6912
7113
|
return [() => via({ frameType: "subagent_catalog" }, subagent_catalog_server_default()), () => via({ frameType: "subagent_runs" }, subagent_runs_server_default())];
|
|
6913
7114
|
} }),
|
|
6914
|
-
workspace: () => ({ get channels() {
|
|
6915
|
-
return [() => via({ frameType: "subagent_catalog" }, subagent_catalog_server_default()), () => via({ frameType: "subagent_runs" }, subagent_runs_server_default())];
|
|
7115
|
+
workspace: (context) => ({ get channels() {
|
|
7116
|
+
return defined([context.hosted("global") ? void 0 : () => via({ frameType: "subagent_catalog" }, subagent_catalog_server_default()), context.hosted("global") ? void 0 : () => via({ frameType: "subagent_runs" }, subagent_runs_server_default())]);
|
|
6916
7117
|
} }),
|
|
6917
7118
|
session: async (context) => {
|
|
6918
|
-
const scopeSession = await root_server_default
|
|
7119
|
+
const scopeSession = await context.scopeRoot("session", root_server_default, context);
|
|
6919
7120
|
const contextSession = {
|
|
6920
7121
|
...context,
|
|
6921
7122
|
root: scopeSession.value
|
|
@@ -6926,7 +7127,10 @@ const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
|
|
|
6926
7127
|
return [at(route_server_default, contextSession)];
|
|
6927
7128
|
},
|
|
6928
7129
|
get channels() {
|
|
6929
|
-
return [() => via({ frameType: "subagent_catalog" }, subagent_catalog_server_default()), () => via({ frameType: "subagent_runs" }, subagent_runs_server_default())];
|
|
7130
|
+
return defined([context.hosted("global") ? void 0 : () => via({ frameType: "subagent_catalog" }, subagent_catalog_server_default()), context.hosted("global") ? void 0 : () => via({ frameType: "subagent_runs" }, subagent_runs_server_default())]);
|
|
7131
|
+
},
|
|
7132
|
+
get hooks() {
|
|
7133
|
+
return [via({ event: "session_start" }, at(sessionStart_server_default, contextSession))];
|
|
6930
7134
|
},
|
|
6931
7135
|
get resources() {
|
|
6932
7136
|
return [at(team_server_default, contextSession)];
|
|
@@ -6942,7 +7146,7 @@ const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
|
|
|
6942
7146
|
}
|
|
6943
7147
|
});
|
|
6944
7148
|
//#endregion
|
|
6945
|
-
exports.default =
|
|
6946
|
-
exports.
|
|
7149
|
+
exports.default = serverPlugin;
|
|
7150
|
+
exports.serverPlugin = serverPlugin;
|
|
6947
7151
|
|
|
6948
7152
|
//# sourceMappingURL=server.cjs.map
|