pi-herdsman 0.21.0 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.21.0",
18
+ version: "0.21.1",
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",
@@ -64,7 +64,7 @@ var package_default = {
64
64
  },
65
65
  piHerdsman: {
66
66
  runtime: {
67
- pi: "1.0.1",
67
+ pi: "1.0.4",
68
68
  herdr: {
69
69
  version: "0.9.3",
70
70
  sha256: {
@@ -93,9 +93,9 @@ var package_default = {
93
93
  typebox: "*"
94
94
  },
95
95
  devDependencies: {
96
- "@earendil-works/pi-ai": "1.0.1",
97
- "@earendil-works/pi-coding-agent": "1.0.1",
98
- "@earendil-works/pi-tui": "1.0.1",
96
+ "@earendil-works/pi-ai": "1.0.4",
97
+ "@earendil-works/pi-coding-agent": "1.0.4",
98
+ "@earendil-works/pi-tui": "1.0.4",
99
99
  esbuild: "^0.28.2",
100
100
  typebox: "^1.3.7"
101
101
  },
@@ -1579,6 +1579,11 @@ function overrideBodyMode(definition) {
1579
1579
  function normalizedToolNames(tools) {
1580
1580
  return (tools ?? []).flatMap((tool) => tool.split(",")).map((tool) => tool.trim()).filter(Boolean);
1581
1581
  }
1582
+ function matchesToolPattern(pattern, name) {
1583
+ if (!pattern.includes("*")) return pattern === name;
1584
+ const source = pattern.split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/gu, "\\$&")).join(".*");
1585
+ return new RegExp(`^${source}$`, "u").test(name);
1586
+ }
1582
1587
  function readOptionalAgentDefinitions(root2) {
1583
1588
  const stats = statSync3(root2, { throwIfNoEntry: false });
1584
1589
  if (!stats) return [];
@@ -1954,33 +1959,41 @@ function agentLaunchArgs(agent, options) {
1954
1959
  }
1955
1960
  }
1956
1961
  if (sharedPromptPath) args.push("--append-system-prompt", sharedPromptPath);
1957
- if (managedAgent)
1958
- args.push("--append-system-prompt", `<active_agent name="${agent.name}"/>`);
1959
1962
  const explicitTools = frontmatter.tools !== void 0;
1960
- const noTools = frontmatter.noTools || explicitTools && frontmatter.tools.length === 0;
1963
+ const configuredTools = normalizedToolNames(frontmatter.tools);
1964
+ const noTools = frontmatter.noTools === true || explicitTools && configuredTools.length === 0;
1961
1965
  if (noTools) args.push("--no-tools");
1962
1966
  if (frontmatter.noBuiltinTools) args.push("--no-builtin-tools");
1963
1967
  const requiredTools = [
1964
1968
  ...managedAgent ? agentDefinitionDelegationEnabled(agent) ? [...AGENT_COORDINATION_TOOLS, "ask_owner"] : ["ask_owner"] : [],
1965
1969
  ...options.requiredTools ?? []
1966
1970
  ].filter((tool, index, all) => all.indexOf(tool) === index);
1967
- if (managedAgent || requiredTools.length) {
1968
- if (noTools || explicitTools) {
1969
- const configuredTools = normalizedToolNames(frontmatter.tools).filter(
1970
- (tool) => (!managedAgent || tool !== "agent") && !requiredTools.includes(tool)
1971
+ const requiredToolSet = new Set(requiredTools);
1972
+ const excluded = normalizedToolNames(frontmatter.excludeTools).filter((pattern) => !requiredToolSet.has(pattern)).filter((pattern, index, all) => all.indexOf(pattern) === index);
1973
+ for (const pattern of excluded) {
1974
+ if (!pattern.includes("*")) continue;
1975
+ const required = requiredTools.find(
1976
+ (tool) => matchesToolPattern(pattern, tool)
1977
+ );
1978
+ if (required)
1979
+ throw new Error(
1980
+ `agent ${agent.name} excludeTools pattern ${JSON.stringify(pattern)} matches required tool ${JSON.stringify(required)}; required tools cannot be excluded by patterns`
1971
1981
  );
1972
- const tools = [.../* @__PURE__ */ new Set([...configuredTools, ...requiredTools])];
1973
- if (tools.length) args.push("--tools", tools.join(","));
1982
+ }
1983
+ if (noTools || explicitTools) {
1984
+ const configured = configuredTools.filter(
1985
+ (tool) => (!managedAgent || tool !== "agent") && !requiredToolSet.has(tool)
1986
+ );
1987
+ const selected = [.../* @__PURE__ */ new Set([...configured, ...requiredTools])];
1988
+ if (selected.length) {
1989
+ if (!selected.some((tool) => tool.startsWith("mcp__"))) {
1990
+ selected.push("mcp__");
1991
+ if (!excluded.includes("mcp__")) excluded.push("mcp__");
1992
+ }
1993
+ args.push("--tools", selected.join(","));
1974
1994
  }
1975
- const requiredToolSet = new Set(requiredTools);
1976
- const excluded = normalizedToolNames(frontmatter.excludeTools).filter((tool) => !requiredToolSet.has(tool)).filter((tool, index, all) => all.indexOf(tool) === index);
1977
- if (excluded.length) args.push("--exclude-tools", excluded.join(","));
1978
- } else {
1979
- if (frontmatter.tools?.length)
1980
- args.push("--tools", frontmatter.tools.join(","));
1981
- if (frontmatter.excludeTools?.length)
1982
- args.push("--exclude-tools", frontmatter.excludeTools.join(","));
1983
1995
  }
1996
+ if (excluded.length) args.push("--exclude-tools", excluded.join(","));
1984
1997
  const noSkills = frontmatter.noSkills ?? frontmatter.inheritSkills !== true;
1985
1998
  if (noSkills) args.push("--no-skills");
1986
1999
  for (const skill of frontmatter.skills ?? []) args.push("--skill", skill);
@@ -1989,6 +2002,8 @@ function agentLaunchArgs(agent, options) {
1989
2002
  args.push("--no-extensions");
1990
2003
  for (const extension of frontmatter.extensions ?? [])
1991
2004
  args.push("--extension", extension);
2005
+ if (managedAgent)
2006
+ args.push("--append-system-prompt", `<active_agent name="${agent.name}"/>`);
1992
2007
  return args;
1993
2008
  }
1994
2009
 
@@ -11889,10 +11904,21 @@ function createAgentController(pi, options) {
11889
11904
  } finally {
11890
11905
  resetRelease();
11891
11906
  }
11907
+ let ownerDisplay = "lead";
11908
+ if (scope.kind === "managed-agent") {
11909
+ const definition2 = process.env.PI_HERDSMAN_AGENT_DEFINITION;
11910
+ const parentLabel = process.env.PI_HERDSMAN_LABEL;
11911
+ if (!definition2 || !parentLabel)
11912
+ throw new Error(
11913
+ "Managed-Agent launch is missing its definition or label"
11914
+ );
11915
+ ownerDisplay = displayIdentity(definition2, parentLabel);
11916
+ }
11892
11917
  const env = [
11893
11918
  `PI_HERDSMAN_MAILBOX=${mailbox}`,
11894
11919
  `PI_HERDSMAN_RUN_ID=${runId}`,
11895
11920
  `PI_HERDSMAN_OWNER_SESSION_ID=${owner}`,
11921
+ `PI_HERDSMAN_OWNER_DISPLAY=${ownerDisplay}`,
11896
11922
  `PI_SUBAGENT_PARENT_SESSION=${forwardingSession}`,
11897
11923
  `PI_HERDSMAN_LABEL=${label}`,
11898
11924
  `PI_HERDSMAN_WORKSPACE_ID=${workspaceId}`,
@@ -13527,6 +13553,9 @@ function collectSessionUsage(ctx, ownedChildren, openOwnedSession, leadRoots = [
13527
13553
  import { randomUUID as randomUUID9 } from "node:crypto";
13528
13554
  import { Type as Type2 } from "typebox";
13529
13555
  import { isDeepStrictEqual } from "node:util";
13556
+ var DELEGATING_AGENT_ROLE_CHARTER = `## Delegating agent role
13557
+ ${DELEGATING_AGENT_SCOPE_DESCRIPTION}
13558
+ ${FILE_HANDOFF_GUIDANCE}`;
13530
13559
  function currentTurnIsSoleToolCall(message, name) {
13531
13560
  const turn = message;
13532
13561
  if (turn?.role !== "assistant" || !Array.isArray(turn.content)) return false;
@@ -14699,7 +14728,9 @@ function registerManagedAgentRuntime(pi, options) {
14699
14728
  const view = await controller.agentSnapshotView(
14700
14729
  ctx,
14701
14730
  scope,
14702
- controller.sessionSignal()
14731
+ controller.sessionSignal(),
14732
+ true,
14733
+ false
14703
14734
  );
14704
14735
  return buildAgentStatusSnapshot(view, ctx, {
14705
14736
  scope,
@@ -14717,29 +14748,23 @@ function registerManagedAgentRuntime(pi, options) {
14717
14748
  });
14718
14749
  }
14719
14750
  controller?.registerTools(/* @__PURE__ */ new Map());
14720
- if (delegationEnabled)
14721
- pi.on("before_agent_start", async (event, ctx) => {
14722
- const projection = await options.prepareDelegatingStart(ctx);
14723
- if (projection.supervisorStateMessage)
14724
- pi.sendMessage(projection.supervisorStateMessage, {
14725
- triggerTurn: false
14726
- });
14751
+ pi.on("before_agent_start", (event, ctx) => {
14752
+ const definition = process.env.PI_HERDSMAN_AGENT_DEFINITION;
14753
+ const label = process.env.PI_HERDSMAN_LABEL;
14754
+ event.systemPromptOptions.sections.pi_herdsman_agent = [
14755
+ `identity: ${displayIdentity(definition, label)}`,
14756
+ `direct_owner: ${process.env.PI_HERDSMAN_OWNER_DISPLAY}`
14757
+ ].join("\n");
14758
+ if (delegationEnabled) {
14727
14759
  const roster = startupDefinitionRoster;
14728
14760
  const availableRoster = roster?.sessionId === ctx.sessionManager.getSessionId() ? roster : void 0;
14729
- return {
14730
- systemPrompt: `${event.systemPrompt}
14731
-
14732
- ${projection.roleCharter}
14733
-
14734
- ` + (availableRoster ? `## Available agent definitions
14735
-
14736
- <agent_definitions>
14737
- ${JSON.stringify(availableRoster.definitions, null, 2)}
14738
- </agent_definitions>
14761
+ event.systemPromptOptions.sections.delegating_agent_role = DELEGATING_AGENT_ROLE_CHARTER;
14762
+ if (availableRoster)
14763
+ event.systemPromptOptions.sections.agent_definitions = `${JSON.stringify(availableRoster.definitions, null, 2)}
14739
14764
 
14740
- This is the session-start definition snapshot. Use agent_list for live Agent state or to refresh Agent definitions after configuration changes.` : "")
14741
- };
14742
- });
14765
+ This is the session-start definition snapshot. Use agent_list for live Agent state or to refresh Agent definitions after configuration changes.`;
14766
+ }
14767
+ });
14743
14768
  const execution = createManagedAgentExecutionState();
14744
14769
  const metadataPublisher = createManagedAgentMetadataPublisher(pi);
14745
14770
  const leafStatus = createManagedAgentLeafStatus({
@@ -15149,6 +15174,8 @@ function managedAgentEnvironmentError() {
15149
15174
  if (!validId(e.PI_HERDSMAN_RUN_ID)) return "PI_HERDSMAN_RUN_ID invalid";
15150
15175
  if (!validId(e.PI_HERDSMAN_OWNER_SESSION_ID))
15151
15176
  return "PI_HERDSMAN_OWNER_SESSION_ID invalid";
15177
+ if (!e.PI_HERDSMAN_OWNER_DISPLAY?.trim())
15178
+ return "PI_HERDSMAN_OWNER_DISPLAY missing";
15152
15179
  if (!e.PI_HERDSMAN_LABEL || !AGENT_LABEL_PATTERN2.test(e.PI_HERDSMAN_LABEL))
15153
15180
  return "PI_HERDSMAN_LABEL invalid";
15154
15181
  if (!e.PI_HERDSMAN_WORKSPACE_ID?.trim())
@@ -21017,9 +21044,6 @@ var LEAD_ROLE_CHARTER = `## Lead role
21017
21044
  ${LEAD_SCOPE_DESCRIPTION}
21018
21045
  ${LEAD_SUPERVISOR_PEER_GUIDANCE}
21019
21046
  ${FILE_HANDOFF_GUIDANCE}`;
21020
- var DELEGATING_AGENT_ROLE_CHARTER = `## Delegating agent role
21021
- ${DELEGATING_AGENT_SCOPE_DESCRIPTION}
21022
- ${FILE_HANDOFF_GUIDANCE}`;
21023
21047
  var MANAGER_ROLE_CHARTER = `## Manager role
21024
21048
  Manage project work by branch. Use staff_delegate with a task and optional branch
21025
21049
  to start new project work. Use staff_resume with its branch to resume existing
@@ -21614,125 +21638,6 @@ ${globalInstructions}
21614
21638
  const currentChief = (failOnVerificationError = false) => roleTransitions.currentChief(failOnVerificationError);
21615
21639
  const managerForScope = (scope) => roleTransitions.managerForScope(scope);
21616
21640
  const currentWorktreeScope = (ctx) => roleTransitions.currentWorktreeScope(ctx);
21617
- const managedSupervisorWorktreeScope = async (ctx) => {
21618
- const workspaceId = process.env.HERDR_WORKSPACE_ID;
21619
- if (!workspaceId) return void 0;
21620
- try {
21621
- return await worktreeGroupScope(pi, ctx, workspaceId, ctx.signal);
21622
- } catch (error2) {
21623
- if (error2 instanceof OperationError && error2.detail.details?.herdrCode === "not_git_worktree")
21624
- return void 0;
21625
- throw error2;
21626
- }
21627
- };
21628
- const managedSupervisorAgent = (ctx, descriptor) => verifiedHerdrAgent(descriptor, {
21629
- listAgents: async () => (await listAllHerdrAgents(pi, ctx, ctx.signal)).agents,
21630
- getAgent: async (paneId) => (await runHerdr(pi, ctx, ["agent", "get", paneId], {
21631
- signal: ctx.signal
21632
- }))?.agent,
21633
- expectedSession: expectedSession2,
21634
- isPiAgent,
21635
- matchesExpectedSession
21636
- });
21637
- const managedCurrentManager = async (ctx, scope) => {
21638
- const currentScope = scope === null || scope === void 0 ? await managedSupervisorWorktreeScope(ctx) : scope;
21639
- if (!currentScope) return void 0;
21640
- const status = readManagerDescriptorStatus(
21641
- supervisionRuntime(),
21642
- currentScope.primaryWorkspaceId
21643
- );
21644
- if (!status || !status.live) return void 0;
21645
- if (status.descriptor.repoKey !== currentScope.repoKey)
21646
- throw new Error("Manager authority does not match project");
21647
- verifyManagerCoordinationAuthority(
21648
- status.descriptor,
21649
- readLeadCoordinationState(
21650
- supervisionRuntime(),
21651
- status.descriptor.piSessionId
21652
- ),
21653
- HERDSMAN_BUILD,
21654
- requireCompatibleBuild
21655
- );
21656
- if (!await managedSupervisorAgent(ctx, status.descriptor))
21657
- throw new Error(
21658
- "Manager authority exists but live discovery is inconclusive"
21659
- );
21660
- return status.descriptor;
21661
- };
21662
- const managedCurrentChief = async (ctx, failOnVerificationError = false) => {
21663
- const runtime = supervisionRuntime();
21664
- const leaseMayExist = () => {
21665
- try {
21666
- statSync7(runtime.lock);
21667
- return true;
21668
- } catch (error2) {
21669
- if (error2.code === "ENOENT") return false;
21670
- throw error2;
21671
- }
21672
- };
21673
- let descriptor;
21674
- try {
21675
- descriptor = readChiefDescriptor(runtime.descriptor);
21676
- } catch (error2) {
21677
- if (failOnVerificationError && leaseMayExist()) throw error2;
21678
- return void 0;
21679
- }
21680
- requireCompatibleBuild(
21681
- HERDSMAN_BUILD,
21682
- descriptor.build,
21683
- "supervision",
21684
- `Chief ${descriptor.piSessionId}`
21685
- );
21686
- if (!chiefLeaseIsHeld(runtime)) {
21687
- if (failOnVerificationError && leaseMayExist())
21688
- throw new Error("Unable to verify Chief supervision lease");
21689
- return void 0;
21690
- }
21691
- try {
21692
- const verified = await verifyRemoteChiefAuthority(descriptor, {
21693
- remoteIdentity: () => managedSupervisorAgent(ctx, descriptor),
21694
- requireCompatibleBuild,
21695
- build: HERDSMAN_BUILD
21696
- });
21697
- if (!verified) return void 0;
21698
- return descriptor;
21699
- } catch (error2) {
21700
- if (error2 instanceof OperationError && error2.detail.category === "incompatible_build")
21701
- throw error2;
21702
- if (failOnVerificationError) throw error2;
21703
- return void 0;
21704
- }
21705
- };
21706
- const prepareManagedSupervisorState = async (ctx) => {
21707
- const content = await leadSupervisorState(ctx, {
21708
- currentWorktreeScope: managedSupervisorWorktreeScope,
21709
- projectAssignmentForScope: (scope, sessionId) => {
21710
- const assignments = findProjectAssignmentBySession(
21711
- supervisionRuntime(),
21712
- scope.repoKey,
21713
- sessionId
21714
- );
21715
- if (assignments.length > 1)
21716
- throw new Error(
21717
- "Multiple project assignments match the Lead session"
21718
- );
21719
- return assignments[0];
21720
- },
21721
- currentManager: managedCurrentManager,
21722
- currentChiefAuthority: managedCurrentChief
21723
- });
21724
- const latest = [
21725
- ...buildSessionProjection2(ctx.sessionManager.getBranch()).entries
21726
- ].reverse().find(
21727
- (candidate) => candidate.sourceEntry.type === "custom_message" && candidate.sourceEntry.customType === SUPERVISOR_STATE_TYPE && candidate.messages.length > 0
21728
- );
21729
- const latestMessage = latest?.messages[0];
21730
- return supervisorStateMessage(
21731
- SUPERVISOR_STATE_TYPE,
21732
- content,
21733
- latestMessage ? contentText5(latestMessage.content, "") : void 0
21734
- );
21735
- };
21736
21641
  const currentManager = (ctx, scope = null) => roleTransitions.currentManager(ctx, scope);
21737
21642
  const currentSupervisor = (ctx) => roleTransitions.currentSupervisor(ctx);
21738
21643
  const liveAgent = (...args) => leadRuntimes.liveAgent(...args);
@@ -22546,10 +22451,6 @@ ${summary}`,
22546
22451
  resolveMessageFiles,
22547
22452
  currentTurnMessage,
22548
22453
  getAgentDefinitions: async (ctx) => (await contextAgentDefinitions(ctx)).definitions,
22549
- prepareDelegatingStart: async (ctx) => ({
22550
- roleCharter: DELEGATING_AGENT_ROLE_CHARTER,
22551
- supervisorStateMessage: await prepareManagedSupervisorState(ctx)
22552
- }),
22553
22454
  appendError: (ctx, kind, error2) => appendDurableError(pi, ctx, kind, error2)
22554
22455
  });
22555
22456
  }