pi-herdsman 0.22.2 → 0.23.0

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/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
15
15
  // package.json
16
16
  var package_default = {
17
17
  name: "pi-herdsman",
18
- version: "0.22.2",
18
+ version: "0.23.0",
19
19
  type: "module",
20
20
  description: "Asynchronous Pi subagents and agent fleet orchestration for parallel coding agents with nested delegation, background work, and supervision in herdr.",
21
21
  license: "Apache-2.0",
@@ -90,12 +90,14 @@ var package_default = {
90
90
  "@earendil-works/pi-ai": "*",
91
91
  "@earendil-works/pi-coding-agent": "*",
92
92
  "@earendil-works/pi-tui": "*",
93
+ "@howaboua/pi-codex-conversion": "^3.0.45",
93
94
  typebox: "*"
94
95
  },
95
96
  devDependencies: {
96
97
  "@earendil-works/pi-ai": "1.1.0",
97
98
  "@earendil-works/pi-coding-agent": "1.1.0",
98
99
  "@earendil-works/pi-tui": "1.1.0",
100
+ "@howaboua/pi-codex-conversion": "3.0.45",
99
101
  esbuild: "^0.28.2",
100
102
  typebox: "^1.3.7"
101
103
  },
@@ -112,6 +114,11 @@ var package_default = {
112
114
  ],
113
115
  publishConfig: {
114
116
  registry: "https://registry.npmjs.org/"
117
+ },
118
+ peerDependenciesMeta: {
119
+ "@howaboua/pi-codex-conversion": {
120
+ optional: true
121
+ }
115
122
  }
116
123
  };
117
124
 
@@ -553,6 +560,8 @@ function releaseProcessLock(claimDir, ownerPath, claim, name) {
553
560
  }
554
561
 
555
562
  // extension/mailbox.ts
563
+ var MANAGED_AGENT_BOOTSTRAP_LIMIT_BYTES = 64 * 1024;
564
+ var BOOTSTRAP_ID = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/;
556
565
  var UUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
557
566
  var PREFIX = "__PI_HERDSMAN_AGENT_V5__:";
558
567
  var MAILBOX_PROTOCOL_LIMIT_BYTES = 1024 * 1024;
@@ -563,6 +572,7 @@ var MailboxClaimOccupiedError = class extends Error {
563
572
  code = "MAILBOX_CLAIM_OCCUPIED";
564
573
  };
565
574
  var LIMITS = {
575
+ bootstrap: MANAGED_AGENT_BOOTSTRAP_LIMIT_BYTES,
566
576
  state: 64 * 1024,
567
577
  request: MAILBOX_PROTOCOL_LIMIT_BYTES,
568
578
  ask: MAILBOX_PROTOCOL_LIMIT_BYTES,
@@ -699,6 +709,41 @@ function validate(value2, kind) {
699
709
  if (Buffer.byteLength(text, "utf8") > LIMITS[kind])
700
710
  throw new Error("Mailbox record is too large");
701
711
  const v = value2;
712
+ if (kind === "bootstrap") {
713
+ const allowed2 = [
714
+ "version",
715
+ "build",
716
+ "runId",
717
+ "ownerSessionId",
718
+ "workspaceId",
719
+ "agentLabel",
720
+ "participants"
721
+ ];
722
+ if (Object.keys(v).some((key) => !allowed2.includes(key)))
723
+ throw new Error("Unknown mailbox field");
724
+ if (!isRuntimeBuild(v.build))
725
+ throw new Error("Invalid runtime build identity");
726
+ for (const field of [
727
+ "runId",
728
+ "ownerSessionId",
729
+ "workspaceId",
730
+ "agentLabel"
731
+ ])
732
+ if (typeof v[field] !== "string" || !v[field].trim())
733
+ throw new Error(`Invalid mailbox field: ${field}`);
734
+ if (!UUID2.test(v.runId)) throw new Error("Invalid mailbox UUID");
735
+ if (!Array.isArray(v.participants) || !v.participants.length)
736
+ throw new Error("Invalid bootstrap participants");
737
+ const ids = /* @__PURE__ */ new Set();
738
+ for (const participant of v.participants) {
739
+ if (!participant || typeof participant !== "object" || Object.keys(participant).some(
740
+ (key) => !["id", "payload"].includes(key)
741
+ ) || typeof participant.id !== "string" || !BOOTSTRAP_ID.test(participant.id) || ids.has(participant.id) || typeof participant.payload !== "string")
742
+ throw new Error("Invalid or duplicate bootstrap participant");
743
+ ids.add(participant.id);
744
+ }
745
+ return;
746
+ }
702
747
  const allowed = kind === "state" ? [
703
748
  "version",
704
749
  "build",
@@ -975,6 +1020,7 @@ function resetAgentMailbox(path) {
975
1020
  for (const name of [
976
1021
  "state.json",
977
1022
  "ask.json",
1023
+ "bootstrap.json",
978
1024
  ...readdirSync3(path).filter(
979
1025
  (x) => /^(request|result)-.*\.json$/.test(x)
980
1026
  )
@@ -986,6 +1032,24 @@ function resetAgentMailbox(path) {
986
1032
  }
987
1033
  }
988
1034
  }
1035
+ function writeAgentBootstrap(path, record) {
1036
+ atomic(file(path, "bootstrap.json"), record, "bootstrap");
1037
+ }
1038
+ function readAgentBootstrap(path) {
1039
+ const value2 = read(
1040
+ file(path, "bootstrap.json"),
1041
+ "bootstrap"
1042
+ );
1043
+ if (value2) validate(value2, "bootstrap");
1044
+ return value2;
1045
+ }
1046
+ function removeAgentBootstrap(path) {
1047
+ try {
1048
+ unlinkSync2(file(path, "bootstrap.json"));
1049
+ } catch (error2) {
1050
+ if (error2.code !== "ENOENT") throw error2;
1051
+ }
1052
+ }
989
1053
  function removeAgentMailbox(path) {
990
1054
  let names2;
991
1055
  try {
@@ -1189,6 +1253,7 @@ function currentTurnIsSoleToolCall(ctx, name) {
1189
1253
  const calls = turn.content.filter((part) => part?.type === "toolCall");
1190
1254
  return calls.length === 1 && calls[0]?.name === name;
1191
1255
  }
1256
+ var MANAGED_AGENT_BOOTSTRAP_EVENT = "pi-herdsman:managed-agent-bootstrap";
1192
1257
  var FILE_HANDOFF_GUIDANCE = "Pass every user-supplied or already-available artifact relevant to the recipient's assignment, decisions, integration, validation, or onward handoff through `files`; do not assume the recipient inherits the sender's conversation or attachments. Preserve exact supplied result refs when forwarding them and omit unrelated evidence. `files` carries evidence, not runtime capability.";
1193
1258
  function failUnknownResultRef(input, operation) {
1194
1259
  fail(
@@ -12144,6 +12209,7 @@ function createAgentController(pi, options) {
12144
12209
  let promptWriteFailed = false;
12145
12210
  let started;
12146
12211
  let accepted = false;
12212
+ const preparedBootstrap = [];
12147
12213
  try {
12148
12214
  try {
12149
12215
  promptPaths = writePrivatePromptSnapshots([
@@ -12171,6 +12237,69 @@ function createAgentController(pi, options) {
12171
12237
  );
12172
12238
  ownerDisplay = displayIdentity(definition2, parentLabel);
12173
12239
  }
12240
+ if (p.action === "delegate") {
12241
+ const registrations = /* @__PURE__ */ new Map();
12242
+ let open = true;
12243
+ let registrationError;
12244
+ pi.events.emit(MANAGED_AGENT_BOOTSTRAP_EVENT, {
12245
+ protocol: 1,
12246
+ phase: "prepare",
12247
+ context: ctx,
12248
+ agent: label,
12249
+ register(id, prepare) {
12250
+ if (!open)
12251
+ throw new Error(
12252
+ "Managed-agent bootstrap registration is closed"
12253
+ );
12254
+ if (!/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/.test(id)) {
12255
+ registrationError ??= new Error(
12256
+ "Invalid managed-agent bootstrap participant ID"
12257
+ );
12258
+ return;
12259
+ }
12260
+ if (registrations.has(id)) {
12261
+ registrationError ??= new Error(
12262
+ `Duplicate managed-agent bootstrap participant ID: ${id}`
12263
+ );
12264
+ return;
12265
+ }
12266
+ if (typeof prepare !== "function") {
12267
+ registrationError ??= new Error(
12268
+ "Invalid managed-agent bootstrap prepare callback"
12269
+ );
12270
+ return;
12271
+ }
12272
+ registrations.set(id, prepare);
12273
+ }
12274
+ });
12275
+ open = false;
12276
+ if (registrationError) throw registrationError;
12277
+ const participants = [];
12278
+ for (const [id, prepare] of registrations) {
12279
+ const result = await prepare();
12280
+ if (result !== void 0) {
12281
+ if (!result || typeof result.payload !== "string" || result.commit !== void 0 && typeof result.commit !== "function")
12282
+ throw new Error(
12283
+ `Invalid preparation from managed-agent bootstrap participant "${id}"`
12284
+ );
12285
+ participants.push({ id, payload: result.payload });
12286
+ preparedBootstrap.push({
12287
+ id,
12288
+ ...result.commit ? { commit: result.commit } : {}
12289
+ });
12290
+ }
12291
+ }
12292
+ if (participants.length)
12293
+ writeAgentBootstrap(mailbox, {
12294
+ version: 5,
12295
+ build: options.build,
12296
+ runId,
12297
+ ownerSessionId: owner,
12298
+ workspaceId,
12299
+ agentLabel: label,
12300
+ participants
12301
+ });
12302
+ }
12174
12303
  const env = [
12175
12304
  `PI_HERDSMAN_MAILBOX=${mailbox}`,
12176
12305
  `PI_HERDSMAN_RUN_ID=${runId}`,
@@ -12360,6 +12489,8 @@ ${result.stderr ?? ""}`.trim(),
12360
12489
  signal,
12361
12490
  waitForSession: true
12362
12491
  });
12492
+ for (const participant of preparedBootstrap)
12493
+ await participant.commit?.();
12363
12494
  runtimes.set(label, runtime);
12364
12495
  options.onChanged();
12365
12496
  const requestId = await submit(
@@ -15644,8 +15775,53 @@ function registerManagedAgentSessionStartHandler(pi, execution, options) {
15644
15775
  }
15645
15776
  }
15646
15777
  }
15647
- if (!existing)
15778
+ if (!existing) {
15648
15779
  validateManagedAgentDefinition(await options.getAgentDefinitions(ctx));
15780
+ const bootstrap = readAgentBootstrap(mailbox);
15781
+ if (bootstrap) {
15782
+ if (bootstrap.runId !== candidate.runId || bootstrap.ownerSessionId !== candidate.ownerSessionId || bootstrap.workspaceId !== candidate.workspaceId || bootstrap.agentLabel !== candidate.agentLabel)
15783
+ throw new Error("Managed-agent bootstrap identity mismatch");
15784
+ if (!sameRuntimeBuild(options.build, bootstrap.build))
15785
+ throw new Error("Managed-agent bootstrap Herdsman build mismatch");
15786
+ for (const participant of bootstrap.participants) {
15787
+ let initializer;
15788
+ let acceptCount = 0;
15789
+ let invalidInitializer = false;
15790
+ pi.events.emit(MANAGED_AGENT_BOOTSTRAP_EVENT, {
15791
+ protocol: 1,
15792
+ phase: "initialize",
15793
+ context: ctx,
15794
+ agent: candidate.agentLabel,
15795
+ participant: { id: participant.id, payload: participant.payload },
15796
+ accept(callback) {
15797
+ acceptCount++;
15798
+ if (typeof callback !== "function") {
15799
+ invalidInitializer = true;
15800
+ return;
15801
+ }
15802
+ if (acceptCount === 1) initializer = callback;
15803
+ }
15804
+ });
15805
+ if (acceptCount === 0 || invalidInitializer)
15806
+ throw new Error(
15807
+ `Managed-agent bootstrap participant "${participant.id}" is unavailable or invalid`
15808
+ );
15809
+ if (acceptCount > 1)
15810
+ throw new Error(
15811
+ `Managed-agent bootstrap participant "${participant.id}" has multiple initializers`
15812
+ );
15813
+ try {
15814
+ await initializer();
15815
+ } catch (error2) {
15816
+ throw new Error(
15817
+ `Managed-agent bootstrap participant "${participant.id}" failed: ${String(error2)}`,
15818
+ { cause: error2 }
15819
+ );
15820
+ }
15821
+ }
15822
+ removeAgentBootstrap(mailbox);
15823
+ }
15824
+ }
15649
15825
  const release = options.claimAssignmentLock(mailbox, "session_start", {
15650
15826
  label: execution.assignment.agentLabel,
15651
15827
  paneId: execution.assignment.paneId
@@ -22570,7 +22746,7 @@ async function workspacePresentationProvenance(pi, ctx, workspaceIds, workspaceC
22570
22746
  );
22571
22747
  return new Map(entries);
22572
22748
  }
22573
- function index_default(pi) {
22749
+ function extension_default(pi) {
22574
22750
  let leadRuntimes;
22575
22751
  let leadStatusRuntime;
22576
22752
  let leadHerdRunRuntime;
@@ -23799,6 +23975,6 @@ ${summary}`,
23799
23975
  });
23800
23976
  }
23801
23977
  export {
23802
- index_default as default
23978
+ extension_default as default
23803
23979
  };
23804
23980
  //# sourceMappingURL=index.js.map