pi-subagents 0.57.0 → 0.59.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/CHANGELOG.md +104 -0
- package/docs/agents.md +18 -9
- package/docs/configuration.md +4 -4
- package/docs/extension-api.md +40 -1
- package/docs/models.md +27 -4
- package/docs/observability.md +1 -1
- package/docs/tool-reference.md +92 -6
- package/docs/workflows.md +115 -0
- package/package.json +3 -1
- package/prompts/review-loop.md +2 -2
- package/skills/council-mode/SKILL.md +1 -1
- package/skills/pi-subagents/SKILL.md +3 -1
- package/skills/pi-subagents/references/execution-controls.md +6 -2
- package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/skills/pi-subagents/references/prompting-and-roles.md +26 -5
- package/src/agents/agent-management.ts +28 -17
- package/src/agents/agent-serializer.ts +9 -2
- package/src/agents/agents.ts +103 -27
- package/src/agents/runtime-agent-events.ts +70 -0
- package/src/agents/runtime-agent-registry.ts +19 -18
- package/src/api/agents.ts +10 -5
- package/src/api/background-work.ts +5 -1
- package/src/api/delegation.ts +0 -7
- package/src/api/preflight.ts +32 -10
- package/src/extension/fanout-child.ts +5 -3
- package/src/extension/index.ts +66 -27
- package/src/extension/public-execution.ts +15 -2
- package/src/extension/rpc.ts +35 -14
- package/src/extension/schemas.ts +37 -12
- package/src/extension/tool-description.ts +25 -6
- package/src/integrations/herdr-status.ts +5 -0
- package/src/intercom/result-intercom.ts +2 -0
- package/src/profiles/profiles.ts +5 -6
- package/src/runs/background/active-async-capacity.ts +2 -2
- package/src/runs/background/async-execution.ts +78 -46
- package/src/runs/background/async-job-tracker.ts +14 -12
- package/src/runs/background/async-resume.ts +29 -27
- package/src/runs/background/async-status-snapshot.ts +23 -261
- package/src/runs/background/async-status.ts +68 -7
- package/src/runs/background/chain-append.ts +8 -3
- package/src/runs/background/chain-root-attachment.ts +60 -8
- package/src/runs/background/fleet-view.ts +21 -11
- package/src/runs/background/notify.ts +184 -9
- package/src/runs/background/result-delivery-ownership.ts +45 -0
- package/src/runs/background/result-files.ts +2 -1
- package/src/runs/background/result-watcher.ts +29 -10
- package/src/runs/background/resume-guidance.ts +1 -1
- package/src/runs/background/retained-children.ts +1 -1
- package/src/runs/background/run-status.ts +18 -8
- package/src/runs/background/scheduled-runs.ts +86 -7
- package/src/runs/background/stale-run-reconciler.ts +10 -4
- package/src/runs/background/steering.ts +4 -14
- package/src/runs/background/subagent-runner.ts +389 -350
- package/src/runs/background/subagent-wait.ts +58 -10
- package/src/runs/background/terminal-run-index.ts +1 -1
- package/src/runs/background/wait-completions.ts +22 -1
- package/src/runs/background/wait-config.ts +23 -9
- package/src/runs/background/wait-tool.ts +9 -2
- package/src/runs/foreground/async-steering-action.ts +2 -2
- package/src/runs/foreground/execution.ts +134 -121
- package/src/runs/foreground/foreground-control.ts +3 -0
- package/src/runs/foreground/foreground-history.ts +1 -0
- package/src/runs/foreground/subagent-executor.ts +527 -257
- package/src/runs/foreground/workflow-detach-reconcile.ts +130 -120
- package/src/runs/shared/abort-recovery.ts +119 -0
- package/src/runs/shared/async-status-projection.ts +463 -0
- package/src/runs/shared/child-identity.ts +19 -4
- package/src/runs/shared/child-launch-plan.ts +151 -0
- package/src/runs/shared/completion-evidence.ts +89 -0
- package/src/runs/shared/completion-guard.ts +5 -4
- package/src/runs/shared/dynamic-fanout.ts +3 -3
- package/src/runs/shared/fast-mode-extension.ts +5 -5
- package/src/runs/shared/host-step-status.ts +230 -0
- package/src/runs/shared/lane-metadata.ts +105 -0
- package/src/runs/shared/launch-cwd.ts +16 -0
- package/src/runs/shared/long-running-guard.ts +2 -1
- package/src/runs/shared/mcp-config-sources.ts +422 -0
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
- package/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
- package/src/runs/shared/model-exclusions.ts +12 -0
- package/src/runs/shared/model-fallback.ts +25 -6
- package/src/runs/shared/nested-events.ts +6 -2
- package/src/runs/shared/nested-render.ts +7 -3
- package/src/runs/shared/parallel-handoff.ts +419 -7
- package/src/runs/shared/parallel-utils.ts +15 -1
- package/src/runs/shared/pi-args.ts +81 -8
- package/src/runs/shared/single-output.ts +44 -4
- package/src/runs/shared/subagent-prompt-runtime.ts +98 -13
- package/src/runs/shared/worktree-cleanup-plan.ts +847 -0
- package/src/runs/shared/worktree.ts +18 -0
- package/src/shared/child-session-name.ts +46 -0
- package/src/shared/extension-context.ts +24 -0
- package/src/shared/formatters.ts +11 -2
- package/src/shared/launch-contract.ts +5 -1
- package/src/shared/settings.ts +9 -103
- package/src/shared/types.ts +240 -30
- package/src/shared/utils.ts +41 -84
- package/src/slash/delegation-adapters.ts +1 -8
- package/src/slash/delegation-request.ts +0 -4
- package/src/slash/slash-bridge.ts +1 -2
- package/src/slash/slash-commands.ts +369 -90
- package/src/slash/slash-live-state.ts +22 -11
- package/src/slash/subagents-admin.ts +3 -0
- package/src/tui/fleet-status.ts +125 -74
- package/src/tui/fleet.ts +11 -5
- package/src/tui/render.ts +330 -33
- package/src/watchdog/turn-delta.ts +1 -1
- package/src/workflows/chat-progress.ts +6 -3
- package/src/workflows/host-command.ts +230 -0
- package/src/workflows/scripted-workflow.ts +496 -35
- package/src/workflows/workflow-child-summary.ts +9 -5
- package/src/workflows/workflow-preflight.ts +270 -0
- package/src/workflows/workflow-receipt.ts +79 -5
- package/src/workflows/workflow-settlement.ts +246 -0
- package/src/runs/shared/turn-budget.ts +0 -98
package/src/agents/agents.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { parse as parseYaml } from "yaml";
|
|
|
8
8
|
import * as os from "node:os";
|
|
9
9
|
import * as path from "node:path";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
|
-
import type { AcceptanceInput, AcceptanceRole, AgentRunnerConfig, OutputMode, ToolBudgetConfig
|
|
11
|
+
import type { AcceptanceInput, AcceptanceRole, AgentRunnerConfig, OutputMode, ToolBudgetConfig } from "../shared/types.ts";
|
|
12
12
|
import { CODE_OWNED_EXTERNAL_CLI_ADAPTER_LABEL, isCodeOwnedExternalCliAdapterId, parseExternalCliCapabilityNarrowing, validateCodeOwnedProfileRunner } from "../runs/shared/external-cli-contract.ts";
|
|
13
13
|
import { getAgentDir, getProjectConfigDir } from "../shared/utils.ts";
|
|
14
14
|
import { KNOWN_FIELDS } from "./agent-serializer.ts";
|
|
@@ -20,7 +20,6 @@ import { parseModelScopeConfig, type ModelScopeConfig } from "../runs/shared/mod
|
|
|
20
20
|
export { BUILTIN_AGENT_NAMES } from "./builtin-names.ts";
|
|
21
21
|
export { buildRuntimeName, frontmatterNameForConfig, parsePackageName } from "./identity.ts";
|
|
22
22
|
import { parseMemoryFrontmatter } from "./agent-memory.ts";
|
|
23
|
-
import { resolveTurnBudgetConfig } from "../runs/shared/turn-budget.ts";
|
|
24
23
|
import { validateAcceptanceInput } from "../runs/shared/acceptance.ts";
|
|
25
24
|
import { validatePermissionRules, type PermissionRules } from "../runs/shared/permissions.ts";
|
|
26
25
|
import { parseThinkingLevel, type ThinkingLevel } from "../shared/thinking-ceiling.ts";
|
|
@@ -62,6 +61,7 @@ export interface BuiltinAgentOverrideBase {
|
|
|
62
61
|
thinking?: string | false;
|
|
63
62
|
systemPromptMode: SystemPromptMode;
|
|
64
63
|
inheritProjectContext: boolean;
|
|
64
|
+
inheritGlobalContext: boolean;
|
|
65
65
|
inheritSkills: boolean;
|
|
66
66
|
defaultContext?: AgentDefaultContext;
|
|
67
67
|
acceptanceRole?: AcceptanceRole;
|
|
@@ -70,9 +70,11 @@ export interface BuiltinAgentOverrideBase {
|
|
|
70
70
|
skills?: string[];
|
|
71
71
|
skillPath?: string[];
|
|
72
72
|
tools?: string[];
|
|
73
|
+
allowNestedSubagents?: boolean;
|
|
73
74
|
mcpDirectTools?: string[];
|
|
74
75
|
extensions?: string[];
|
|
75
76
|
subagentOnlyExtensions?: string[];
|
|
77
|
+
mutationTools?: string[];
|
|
76
78
|
completionGuard?: boolean;
|
|
77
79
|
toolBudget?: ToolBudgetConfig;
|
|
78
80
|
}
|
|
@@ -89,6 +91,7 @@ interface BuiltinAgentOverrideConfig {
|
|
|
89
91
|
thinking?: string | false;
|
|
90
92
|
systemPromptMode?: SystemPromptMode;
|
|
91
93
|
inheritProjectContext?: boolean;
|
|
94
|
+
inheritGlobalContext?: boolean;
|
|
92
95
|
inheritSkills?: boolean;
|
|
93
96
|
defaultContext?: AgentDefaultContext | false;
|
|
94
97
|
acceptanceRole?: AcceptanceRole | false;
|
|
@@ -96,8 +99,10 @@ interface BuiltinAgentOverrideConfig {
|
|
|
96
99
|
systemPrompt?: string;
|
|
97
100
|
skills?: string[] | false;
|
|
98
101
|
tools?: string[] | false | "inherit";
|
|
102
|
+
allowNestedSubagents?: boolean;
|
|
99
103
|
extensions?: string[] | false;
|
|
100
104
|
subagentOnlyExtensions?: string[] | false;
|
|
105
|
+
mutationTools?: string[] | false;
|
|
101
106
|
completionGuard?: boolean;
|
|
102
107
|
toolBudget?: ToolBudgetConfig | false;
|
|
103
108
|
}
|
|
@@ -127,6 +132,7 @@ export interface AgentConfig {
|
|
|
127
132
|
description: string;
|
|
128
133
|
aliases?: string[];
|
|
129
134
|
tools?: string[];
|
|
135
|
+
allowNestedSubagents?: boolean;
|
|
130
136
|
mcpDirectTools?: string[];
|
|
131
137
|
model?: string;
|
|
132
138
|
modelProvider?: string;
|
|
@@ -135,12 +141,12 @@ export interface AgentConfig {
|
|
|
135
141
|
thinking?: string | false;
|
|
136
142
|
systemPromptMode: SystemPromptMode;
|
|
137
143
|
inheritProjectContext: boolean;
|
|
144
|
+
inheritGlobalContext: boolean;
|
|
138
145
|
inheritSkills: boolean;
|
|
139
146
|
defaultContext?: AgentDefaultContext;
|
|
140
147
|
defaultAsync?: boolean;
|
|
141
148
|
defaultTimeoutMs?: number;
|
|
142
149
|
defaultToolTimeoutMs?: number;
|
|
143
|
-
defaultTurnBudget?: TurnBudgetConfig;
|
|
144
150
|
defaultAcceptance?: AcceptanceInput;
|
|
145
151
|
acceptanceRole?: AcceptanceRole;
|
|
146
152
|
systemPrompt: string;
|
|
@@ -152,6 +158,7 @@ export interface AgentConfig {
|
|
|
152
158
|
extensions?: string[];
|
|
153
159
|
extensionsFromDefault?: boolean;
|
|
154
160
|
subagentOnlyExtensions?: string[];
|
|
161
|
+
mutationTools?: string[];
|
|
155
162
|
output?: string;
|
|
156
163
|
outputMode?: OutputMode;
|
|
157
164
|
defaultReads?: string[];
|
|
@@ -173,6 +180,7 @@ type ProjectRootResolution = "nearest" | "git-root";
|
|
|
173
180
|
|
|
174
181
|
interface SubagentSettings {
|
|
175
182
|
overrides: Record<string, BuiltinAgentOverrideConfig>;
|
|
183
|
+
providerOverrides: Record<string, Record<string, BuiltinAgentOverrideConfig>>;
|
|
176
184
|
defaultModel?: string;
|
|
177
185
|
defaultProvider?: string;
|
|
178
186
|
defaultThinking?: string;
|
|
@@ -183,7 +191,7 @@ interface SubagentSettings {
|
|
|
183
191
|
modelScope?: ModelScopeConfig;
|
|
184
192
|
}
|
|
185
193
|
|
|
186
|
-
const EMPTY_SUBAGENT_SETTINGS: SubagentSettings = { overrides: {} };
|
|
194
|
+
const EMPTY_SUBAGENT_SETTINGS: SubagentSettings = { overrides: {}, providerOverrides: {} };
|
|
187
195
|
const agentFrontmatterFields = new WeakMap<AgentConfig, Set<string>>();
|
|
188
196
|
|
|
189
197
|
export interface ChainStepConfig {
|
|
@@ -710,6 +718,7 @@ function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
|
|
|
710
718
|
...(agent.thinking !== undefined ? { thinking: agent.thinking } : {}),
|
|
711
719
|
systemPromptMode: agent.systemPromptMode,
|
|
712
720
|
inheritProjectContext: agent.inheritProjectContext,
|
|
721
|
+
inheritGlobalContext: agent.inheritGlobalContext,
|
|
713
722
|
inheritSkills: agent.inheritSkills,
|
|
714
723
|
...(agent.defaultContext !== undefined ? { defaultContext: agent.defaultContext } : {}),
|
|
715
724
|
...(agent.acceptanceRole !== undefined ? { acceptanceRole: agent.acceptanceRole } : {}),
|
|
@@ -718,9 +727,11 @@ function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
|
|
|
718
727
|
...(agent.skills ? { skills: [...agent.skills] } : {}),
|
|
719
728
|
...(agent.skillPath ? { skillPath: [...agent.skillPath] } : {}),
|
|
720
729
|
...(agent.tools ? { tools: [...agent.tools] } : {}),
|
|
730
|
+
...(agent.allowNestedSubagents !== undefined ? { allowNestedSubagents: agent.allowNestedSubagents } : {}),
|
|
721
731
|
...(agent.mcpDirectTools ? { mcpDirectTools: [...agent.mcpDirectTools] } : {}),
|
|
722
732
|
...(!agent.extensionsFromDefault && agent.extensions ? { extensions: [...agent.extensions] } : {}),
|
|
723
733
|
...(agent.subagentOnlyExtensions ? { subagentOnlyExtensions: [...agent.subagentOnlyExtensions] } : {}),
|
|
734
|
+
...(agent.mutationTools ? { mutationTools: [...agent.mutationTools] } : {}),
|
|
724
735
|
...(agent.completionGuard !== undefined ? { completionGuard: agent.completionGuard } : {}),
|
|
725
736
|
...(agent.toolBudget !== undefined ? { toolBudget: agent.toolBudget } : {}),
|
|
726
737
|
};
|
|
@@ -741,6 +752,7 @@ function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentO
|
|
|
741
752
|
...(override.thinking !== undefined ? { thinking: override.thinking } : {}),
|
|
742
753
|
...(override.systemPromptMode !== undefined ? { systemPromptMode: override.systemPromptMode } : {}),
|
|
743
754
|
...(override.inheritProjectContext !== undefined ? { inheritProjectContext: override.inheritProjectContext } : {}),
|
|
755
|
+
...(override.inheritGlobalContext !== undefined ? { inheritGlobalContext: override.inheritGlobalContext } : {}),
|
|
744
756
|
...(override.inheritSkills !== undefined ? { inheritSkills: override.inheritSkills } : {}),
|
|
745
757
|
...(override.defaultContext !== undefined ? { defaultContext: override.defaultContext } : {}),
|
|
746
758
|
...(override.acceptanceRole !== undefined ? { acceptanceRole: override.acceptanceRole } : {}),
|
|
@@ -748,8 +760,10 @@ function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentO
|
|
|
748
760
|
...(override.systemPrompt !== undefined ? { systemPrompt: override.systemPrompt } : {}),
|
|
749
761
|
...(override.skills !== undefined ? { skills: override.skills === false ? false : [...override.skills] } : {}),
|
|
750
762
|
...(override.tools !== undefined ? { tools: Array.isArray(override.tools) ? [...override.tools] : override.tools } : {}),
|
|
763
|
+
...(override.allowNestedSubagents !== undefined ? { allowNestedSubagents: override.allowNestedSubagents } : {}),
|
|
751
764
|
...(override.extensions !== undefined ? { extensions: override.extensions === false ? false : [...override.extensions] } : {}),
|
|
752
765
|
...(override.subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions: override.subagentOnlyExtensions === false ? false : [...override.subagentOnlyExtensions] } : {}),
|
|
766
|
+
...(override.mutationTools !== undefined ? { mutationTools: override.mutationTools === false ? false : [...override.mutationTools] } : {}),
|
|
753
767
|
...(override.completionGuard !== undefined ? { completionGuard: override.completionGuard } : {}),
|
|
754
768
|
...(override.toolBudget !== undefined ? { toolBudget: override.toolBudget === false ? false : { ...override.toolBudget, ...(Array.isArray(override.toolBudget.block) ? { block: [...override.toolBudget.block] } : {}) } } : {}),
|
|
755
769
|
};
|
|
@@ -799,7 +813,7 @@ export function findNearestProjectRoot(cwd: string): string | null {
|
|
|
799
813
|
return findProjectRootCandidates(cwd)[0] ?? null;
|
|
800
814
|
}
|
|
801
815
|
|
|
802
|
-
function findConfiguredProjectRoot(cwd: string): string | null {
|
|
816
|
+
export function findConfiguredProjectRoot(cwd: string): string | null {
|
|
803
817
|
const candidates = findProjectRootCandidates(cwd);
|
|
804
818
|
const nearestRoot = candidates[0];
|
|
805
819
|
if (!nearestRoot) return null;
|
|
@@ -958,6 +972,14 @@ function parseBuiltinOverrideEntry(
|
|
|
958
972
|
}
|
|
959
973
|
}
|
|
960
974
|
|
|
975
|
+
if ("inheritGlobalContext" in input) {
|
|
976
|
+
if (typeof input.inheritGlobalContext === "boolean") {
|
|
977
|
+
override.inheritGlobalContext = input.inheritGlobalContext;
|
|
978
|
+
} else {
|
|
979
|
+
throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'inheritGlobalContext'; expected a boolean.`);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
961
983
|
if ("inheritSkills" in input) {
|
|
962
984
|
if (typeof input.inheritSkills === "boolean") {
|
|
963
985
|
override.inheritSkills = input.inheritSkills;
|
|
@@ -1030,6 +1052,10 @@ function parseBuiltinOverrideEntry(
|
|
|
1030
1052
|
|
|
1031
1053
|
const tools = parseToolsOverride(input.tools, { filePath, name });
|
|
1032
1054
|
if (tools !== undefined) override.tools = tools;
|
|
1055
|
+
if ("allowNestedSubagents" in input) {
|
|
1056
|
+
if (typeof input.allowNestedSubagents === "boolean") override.allowNestedSubagents = input.allowNestedSubagents;
|
|
1057
|
+
else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'allowNestedSubagents'; expected a boolean.`);
|
|
1058
|
+
}
|
|
1033
1059
|
|
|
1034
1060
|
const extensions = parseOverrideStringArrayOrFalse(input.extensions, { filePath, name, field: "extensions" });
|
|
1035
1061
|
if (extensions !== undefined) override.extensions = extensions;
|
|
@@ -1037,6 +1063,9 @@ function parseBuiltinOverrideEntry(
|
|
|
1037
1063
|
const subagentOnlyExtensions = parseOverrideStringArrayOrFalse(input.subagentOnlyExtensions, { filePath, name, field: "subagentOnlyExtensions" });
|
|
1038
1064
|
if (subagentOnlyExtensions !== undefined) override.subagentOnlyExtensions = subagentOnlyExtensions;
|
|
1039
1065
|
|
|
1066
|
+
const mutationTools = parseOverrideStringArrayOrFalse(input.mutationTools, { filePath, name, field: "mutationTools" });
|
|
1067
|
+
if (mutationTools !== undefined) override.mutationTools = mutationTools;
|
|
1068
|
+
|
|
1040
1069
|
return Object.keys(override).length > 0 ? override : undefined;
|
|
1041
1070
|
}
|
|
1042
1071
|
|
|
@@ -1106,9 +1135,12 @@ function readSubagentSettings(filePath: string | null): SubagentSettings {
|
|
|
1106
1135
|
const modelScope = parseModelScopeConfig(subagentsObject.modelScope, { filePath });
|
|
1107
1136
|
|
|
1108
1137
|
const parsed: Record<string, BuiltinAgentOverrideConfig> = {};
|
|
1138
|
+
const providerOverrides: Record<string, Record<string, BuiltinAgentOverrideConfig>> = {};
|
|
1109
1139
|
const agentOverrides = subagentsObject.agentOverrides;
|
|
1140
|
+
const agentOverridesByProvider = subagentsObject.agentOverridesByProvider;
|
|
1110
1141
|
const parsedSettings: SubagentSettings = {
|
|
1111
1142
|
overrides: parsed,
|
|
1143
|
+
providerOverrides,
|
|
1112
1144
|
...(defaultModel !== undefined ? { defaultModel } : {}),
|
|
1113
1145
|
...(defaultProvider !== undefined ? { defaultProvider } : {}),
|
|
1114
1146
|
...(defaultThinking !== undefined ? { defaultThinking } : {}),
|
|
@@ -1118,16 +1150,42 @@ function readSubagentSettings(filePath: string | null): SubagentSettings {
|
|
|
1118
1150
|
...(disableThinking !== undefined ? { disableThinking } : {}),
|
|
1119
1151
|
...(modelScope !== undefined ? { modelScope } : {}),
|
|
1120
1152
|
};
|
|
1121
|
-
if (
|
|
1122
|
-
|
|
1153
|
+
if (agentOverrides && typeof agentOverrides === "object" && !Array.isArray(agentOverrides)) {
|
|
1154
|
+
for (const [name, value] of Object.entries(agentOverrides)) {
|
|
1155
|
+
const override = parseBuiltinOverrideEntry(name, value, filePath);
|
|
1156
|
+
if (override) parsed[name] = override;
|
|
1157
|
+
}
|
|
1123
1158
|
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1159
|
+
if (agentOverridesByProvider !== undefined) {
|
|
1160
|
+
if (!agentOverridesByProvider || typeof agentOverridesByProvider !== "object" || Array.isArray(agentOverridesByProvider)) {
|
|
1161
|
+
throw new Error(`Subagent settings in '${filePath}' have invalid 'agentOverridesByProvider'; expected an object keyed by provider.`);
|
|
1162
|
+
}
|
|
1163
|
+
for (const [provider, value] of Object.entries(agentOverridesByProvider)) {
|
|
1164
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1165
|
+
throw new Error(`Subagent settings in '${filePath}' have invalid 'agentOverridesByProvider.${provider}'; expected an object keyed by agent.`);
|
|
1166
|
+
}
|
|
1167
|
+
const entries: Record<string, BuiltinAgentOverrideConfig> = {};
|
|
1168
|
+
for (const [agentName, agentValue] of Object.entries(value)) {
|
|
1169
|
+
const override = parseBuiltinOverrideEntry(`agentOverridesByProvider.${provider}.${agentName}`, agentValue, filePath);
|
|
1170
|
+
if (override) entries[agentName] = override;
|
|
1171
|
+
}
|
|
1172
|
+
providerOverrides[provider] = entries;
|
|
1173
|
+
}
|
|
1127
1174
|
}
|
|
1128
1175
|
return parsedSettings;
|
|
1129
1176
|
}
|
|
1130
1177
|
|
|
1178
|
+
function selectProviderOverrides(settings: SubagentSettings, provider: string | undefined): SubagentSettings {
|
|
1179
|
+
if (!provider) return settings;
|
|
1180
|
+
const selected = settings.providerOverrides[provider];
|
|
1181
|
+
if (!selected) return settings;
|
|
1182
|
+
const overrides = { ...settings.overrides };
|
|
1183
|
+
for (const [name, override] of Object.entries(selected)) {
|
|
1184
|
+
overrides[name] = { ...overrides[name], ...override };
|
|
1185
|
+
}
|
|
1186
|
+
return { ...settings, overrides };
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1131
1189
|
function resolveSubagentDefaultProvider(
|
|
1132
1190
|
userSettings: SubagentSettings,
|
|
1133
1191
|
projectSettings: SubagentSettings,
|
|
@@ -1272,6 +1330,7 @@ function applyBuiltinOverride(
|
|
|
1272
1330
|
if (override.thinking !== undefined) { if (override.thinking === false) delete next.thinking; else next.thinking = override.thinking; }
|
|
1273
1331
|
if (override.systemPromptMode !== undefined) next.systemPromptMode = override.systemPromptMode;
|
|
1274
1332
|
if (override.inheritProjectContext !== undefined) next.inheritProjectContext = override.inheritProjectContext;
|
|
1333
|
+
if (override.inheritGlobalContext !== undefined) next.inheritGlobalContext = override.inheritGlobalContext;
|
|
1275
1334
|
if (override.inheritSkills !== undefined) next.inheritSkills = override.inheritSkills;
|
|
1276
1335
|
if (override.defaultContext !== undefined) { if (override.defaultContext === false) delete next.defaultContext; else next.defaultContext = override.defaultContext; }
|
|
1277
1336
|
if (override.acceptanceRole !== undefined) { if (override.acceptanceRole === false) delete next.acceptanceRole; else next.acceptanceRole = override.acceptanceRole; }
|
|
@@ -1279,8 +1338,10 @@ function applyBuiltinOverride(
|
|
|
1279
1338
|
if (override.systemPrompt !== undefined) next.systemPrompt = override.systemPrompt;
|
|
1280
1339
|
if (override.skills !== undefined) { if (override.skills === false) delete next.skills; else next.skills = [...override.skills]; }
|
|
1281
1340
|
if (override.tools !== undefined) applyToolsOverride(next, override.tools);
|
|
1341
|
+
if (override.allowNestedSubagents !== undefined) next.allowNestedSubagents = override.allowNestedSubagents;
|
|
1282
1342
|
if (override.extensions !== undefined) { if (override.extensions === false) delete next.extensions; else next.extensions = [...override.extensions]; }
|
|
1283
1343
|
if (override.subagentOnlyExtensions !== undefined) { if (override.subagentOnlyExtensions === false) delete next.subagentOnlyExtensions; else next.subagentOnlyExtensions = [...override.subagentOnlyExtensions]; }
|
|
1344
|
+
if (override.mutationTools !== undefined) { if (override.mutationTools === false) delete next.mutationTools; else next.mutationTools = [...override.mutationTools]; }
|
|
1284
1345
|
if (override.completionGuard !== undefined) next.completionGuard = override.completionGuard;
|
|
1285
1346
|
if (override.toolBudget !== undefined) { if (override.toolBudget === false) delete next.toolBudget; else next.toolBudget = override.toolBudget; }
|
|
1286
1347
|
|
|
@@ -1418,6 +1479,9 @@ function applyCustomAgentOverride(
|
|
|
1418
1479
|
if (override.inheritProjectContext !== undefined) {
|
|
1419
1480
|
fill("inheritProjectContext", ["inheritProjectContext"], override.inheritProjectContext);
|
|
1420
1481
|
}
|
|
1482
|
+
if (override.inheritGlobalContext !== undefined) {
|
|
1483
|
+
fill("inheritGlobalContext", ["inheritGlobalContext"], override.inheritGlobalContext);
|
|
1484
|
+
}
|
|
1421
1485
|
if (override.inheritSkills !== undefined) {
|
|
1422
1486
|
fill("inheritSkills", ["inheritSkills"], override.inheritSkills);
|
|
1423
1487
|
}
|
|
@@ -1439,6 +1503,9 @@ function applyCustomAgentOverride(
|
|
|
1439
1503
|
applyToolsOverride(mutable(), override.tools);
|
|
1440
1504
|
anyFilled = true;
|
|
1441
1505
|
}
|
|
1506
|
+
if (override.allowNestedSubagents !== undefined) {
|
|
1507
|
+
fill("allowNestedSubagents", ["allowNestedSubagents"], override.allowNestedSubagents);
|
|
1508
|
+
}
|
|
1442
1509
|
if (override.extensions !== undefined) {
|
|
1443
1510
|
fill("extensions", ["extensions"], override.extensions === false ? undefined : [...override.extensions]);
|
|
1444
1511
|
}
|
|
@@ -1449,6 +1516,9 @@ function applyCustomAgentOverride(
|
|
|
1449
1516
|
override.subagentOnlyExtensions === false ? undefined : [...override.subagentOnlyExtensions],
|
|
1450
1517
|
);
|
|
1451
1518
|
}
|
|
1519
|
+
if (override.mutationTools !== undefined) {
|
|
1520
|
+
fill("mutationTools", ["mutationTools"], override.mutationTools === false ? undefined : [...override.mutationTools]);
|
|
1521
|
+
}
|
|
1452
1522
|
if (override.completionGuard !== undefined) {
|
|
1453
1523
|
fill("completionGuard", ["completionGuard"], override.completionGuard);
|
|
1454
1524
|
}
|
|
@@ -1488,7 +1558,7 @@ function applyCustomAgentOverrides(
|
|
|
1488
1558
|
|
|
1489
1559
|
export function buildBuiltinOverrideConfig(
|
|
1490
1560
|
base: BuiltinAgentOverrideBase,
|
|
1491
|
-
draft: Pick<AgentConfig, "model" | "modelProvider" | "fallbackModels" | "fast" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "extensions" | "subagentOnlyExtensions" | "completionGuard" | "toolBudget"> & Partial<Pick<AgentConfig, "description" | "output" | "outputMode" | "defaultReads">>,
|
|
1561
|
+
draft: Pick<AgentConfig, "model" | "modelProvider" | "fallbackModels" | "fast" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritGlobalContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "allowNestedSubagents" | "mcpDirectTools" | "extensions" | "subagentOnlyExtensions" | "mutationTools" | "completionGuard" | "toolBudget"> & Partial<Pick<AgentConfig, "description" | "output" | "outputMode" | "defaultReads">>,
|
|
1492
1562
|
): BuiltinAgentOverrideConfig | undefined {
|
|
1493
1563
|
const override: BuiltinAgentOverrideConfig = {};
|
|
1494
1564
|
|
|
@@ -1506,6 +1576,7 @@ export function buildBuiltinOverrideConfig(
|
|
|
1506
1576
|
if (draft.thinking !== base.thinking) override.thinking = draft.thinking ?? false;
|
|
1507
1577
|
if (draft.systemPromptMode !== base.systemPromptMode) override.systemPromptMode = draft.systemPromptMode;
|
|
1508
1578
|
if (draft.inheritProjectContext !== base.inheritProjectContext) override.inheritProjectContext = draft.inheritProjectContext;
|
|
1579
|
+
if (draft.inheritGlobalContext !== base.inheritGlobalContext) override.inheritGlobalContext = draft.inheritGlobalContext;
|
|
1509
1580
|
if (draft.inheritSkills !== base.inheritSkills) override.inheritSkills = draft.inheritSkills;
|
|
1510
1581
|
if (draft.defaultContext !== base.defaultContext) override.defaultContext = draft.defaultContext ?? false;
|
|
1511
1582
|
if (draft.acceptanceRole !== base.acceptanceRole) override.acceptanceRole = draft.acceptanceRole ?? false;
|
|
@@ -1516,10 +1587,12 @@ export function buildBuiltinOverrideConfig(
|
|
|
1516
1587
|
const baseTools = joinToolList(base);
|
|
1517
1588
|
const draftTools = joinToolList(draft);
|
|
1518
1589
|
if (!arraysEqual(draftTools, baseTools)) override.tools = draftTools ? [...draftTools] : false;
|
|
1590
|
+
if (draft.allowNestedSubagents !== base.allowNestedSubagents) override.allowNestedSubagents = draft.allowNestedSubagents === true;
|
|
1519
1591
|
if (!arraysEqual(draft.extensions, base.extensions)) override.extensions = draft.extensions ? [...draft.extensions] : false;
|
|
1520
1592
|
if (!arraysEqual(draft.subagentOnlyExtensions, base.subagentOnlyExtensions)) {
|
|
1521
1593
|
override.subagentOnlyExtensions = draft.subagentOnlyExtensions ? [...draft.subagentOnlyExtensions] : false;
|
|
1522
1594
|
}
|
|
1595
|
+
if (!arraysEqual(draft.mutationTools, base.mutationTools)) override.mutationTools = draft.mutationTools ? [...draft.mutationTools] : false;
|
|
1523
1596
|
if ((draft.completionGuard !== false) !== (base.completionGuard !== false)) {
|
|
1524
1597
|
override.completionGuard = draft.completionGuard !== false;
|
|
1525
1598
|
}
|
|
@@ -1649,7 +1722,7 @@ export function removeBuiltinAgentOverrideFields(
|
|
|
1649
1722
|
return { path: filePath, removed: true };
|
|
1650
1723
|
}
|
|
1651
1724
|
|
|
1652
|
-
const DISCOVERY_PRUNED_DIR_NAMES = new Set([".git", "node_modules"]);
|
|
1725
|
+
const DISCOVERY_PRUNED_DIR_NAMES = new Set([".git", "node_modules", ".pi", "sync-backups"]);
|
|
1653
1726
|
|
|
1654
1727
|
function isDiscoveryNestedProjectRoot(dir: string): boolean {
|
|
1655
1728
|
return isDirectory(getProjectConfigDir(dir)) || isDirectory(path.join(dir, ".agents"));
|
|
@@ -1863,7 +1936,7 @@ function parseAgentRunnerFrontmatter(raw: string | undefined, agentName: string)
|
|
|
1863
1936
|
|
|
1864
1937
|
function validateExternalRunnerProfile(frontmatter: Record<string, string>, agentName: string, runner: AgentRunnerConfig | undefined): void {
|
|
1865
1938
|
if (runner?.type !== "external-cli" && runner?.type !== "external-job") return;
|
|
1866
|
-
const unsupported = ["tools", "model", "fallbackModels", "thinking", "extensions", "subagentOnlyExtensions", "maxSubagentDepth", "completionGuard", "skills", "skill", "skillPath", "toolBudget", "permission", "permissions"]
|
|
1939
|
+
const unsupported = ["tools", "allowNestedSubagents", "model", "fallbackModels", "thinking", "extensions", "subagentOnlyExtensions", "mutationTools", "maxSubagentDepth", "completionGuard", "skills", "skill", "skillPath", "toolBudget", "permission", "permissions"]
|
|
1867
1940
|
.filter((field) => frontmatter[field] !== undefined);
|
|
1868
1941
|
if (unsupported.length > 0) {
|
|
1869
1942
|
throw new Error(`Agent '${agentName}' uses runner.type='${runner.type}' and declares unsupported Pi-only fields: ${unsupported.join(", ")}.`);
|
|
@@ -1963,6 +2036,7 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
|
|
|
1963
2036
|
: frontmatter.inheritProjectContext === "false"
|
|
1964
2037
|
? false
|
|
1965
2038
|
: defaultInheritProjectContext(localName);
|
|
2039
|
+
const inheritGlobalContext = frontmatter.inheritGlobalContext === "true";
|
|
1966
2040
|
const inheritSkills = frontmatter.inheritSkills === "true"
|
|
1967
2041
|
? true
|
|
1968
2042
|
: frontmatter.inheritSkills === "false"
|
|
@@ -1995,13 +2069,6 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
|
|
|
1995
2069
|
}
|
|
1996
2070
|
defaultToolTimeoutMs = parsed;
|
|
1997
2071
|
}
|
|
1998
|
-
let defaultTurnBudget: TurnBudgetConfig | undefined;
|
|
1999
|
-
if (frontmatter.turnBudget !== undefined && frontmatter.turnBudget.trim()) {
|
|
2000
|
-
const parsed = JSON.parse(frontmatter.turnBudget) as unknown;
|
|
2001
|
-
const resolved = resolveTurnBudgetConfig(parsed, `Agent '${localName}' turnBudget frontmatter`);
|
|
2002
|
-
if (resolved.error) throw new Error(resolved.error);
|
|
2003
|
-
defaultTurnBudget = resolved.turnBudget;
|
|
2004
|
-
}
|
|
2005
2072
|
const defaultAcceptance = parseAgentAcceptanceFrontmatter(frontmatter.acceptance, localName);
|
|
2006
2073
|
let outputMode: OutputMode | undefined;
|
|
2007
2074
|
if (frontmatter.outputMode !== undefined) {
|
|
@@ -2016,12 +2083,19 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
|
|
|
2016
2083
|
|
|
2017
2084
|
const extensions = resolveAgentRelativeExtensionPaths(parseFrontmatterList(frontmatter.extensions), filePath);
|
|
2018
2085
|
const subagentOnlyExtensions = resolveAgentRelativeExtensionPaths(parseFrontmatterList(frontmatter.subagentOnlyExtensions), filePath);
|
|
2086
|
+
const mutationTools = parseFrontmatterList(frontmatter.mutationTools);
|
|
2019
2087
|
let fast: boolean | undefined;
|
|
2020
2088
|
if (frontmatter.fast !== undefined) {
|
|
2021
2089
|
if (frontmatter.fast === "true") fast = true;
|
|
2022
2090
|
else if (frontmatter.fast === "false") fast = false;
|
|
2023
2091
|
else throw new Error(`Agent '${localName}' has invalid fast frontmatter; expected true or false.`);
|
|
2024
2092
|
}
|
|
2093
|
+
let allowNestedSubagents: boolean | undefined;
|
|
2094
|
+
if (frontmatter.allowNestedSubagents !== undefined) {
|
|
2095
|
+
if (frontmatter.allowNestedSubagents === "true") allowNestedSubagents = true;
|
|
2096
|
+
else if (frontmatter.allowNestedSubagents === "false") allowNestedSubagents = false;
|
|
2097
|
+
else throw new Error(`Agent '${localName}' has invalid allowNestedSubagents frontmatter; expected true or false.`);
|
|
2098
|
+
}
|
|
2025
2099
|
|
|
2026
2100
|
const extraFields: Record<string, string> = {};
|
|
2027
2101
|
for (const [key, value] of Object.entries(frontmatter)) {
|
|
@@ -2065,6 +2139,7 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
|
|
|
2065
2139
|
description: frontmatter.description,
|
|
2066
2140
|
...(aliases !== undefined ? { aliases } : {}),
|
|
2067
2141
|
...(rawTools !== undefined ? { tools } : {}),
|
|
2142
|
+
...(allowNestedSubagents !== undefined ? { allowNestedSubagents } : {}),
|
|
2068
2143
|
...(mcpDirectTools.length > 0 ? { mcpDirectTools } : {}),
|
|
2069
2144
|
...(frontmatter.model !== undefined ? { model: frontmatter.model } : {}),
|
|
2070
2145
|
...(fallbackModels?.length ? { fallbackModels } : {}),
|
|
@@ -2072,12 +2147,12 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
|
|
|
2072
2147
|
...(frontmatter.thinking !== undefined ? { thinking: frontmatter.thinking === "false" ? false : frontmatter.thinking } : {}),
|
|
2073
2148
|
systemPromptMode,
|
|
2074
2149
|
inheritProjectContext,
|
|
2150
|
+
inheritGlobalContext,
|
|
2075
2151
|
inheritSkills,
|
|
2076
2152
|
...(defaultContext !== undefined ? { defaultContext } : {}),
|
|
2077
2153
|
...(defaultAsync !== undefined ? { defaultAsync } : {}),
|
|
2078
2154
|
...(defaultTimeoutMs !== undefined ? { defaultTimeoutMs } : {}),
|
|
2079
2155
|
...(defaultToolTimeoutMs !== undefined ? { defaultToolTimeoutMs } : {}),
|
|
2080
|
-
...(defaultTurnBudget !== undefined ? { defaultTurnBudget } : {}),
|
|
2081
2156
|
...(defaultAcceptance !== undefined ? { defaultAcceptance } : {}),
|
|
2082
2157
|
...(acceptanceRole !== undefined ? { acceptanceRole } : {}),
|
|
2083
2158
|
systemPrompt: body,
|
|
@@ -2088,6 +2163,7 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
|
|
|
2088
2163
|
...(skillPath?.length ? { skillPath } : {}),
|
|
2089
2164
|
...(extensions !== undefined ? { extensions } : {}),
|
|
2090
2165
|
...(subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions } : {}),
|
|
2166
|
+
...(mutationTools?.length ? { mutationTools } : {}),
|
|
2091
2167
|
...(frontmatter.output !== undefined ? { output: frontmatter.output } : {}),
|
|
2092
2168
|
...(outputMode !== undefined ? { outputMode } : {}),
|
|
2093
2169
|
...(defaultReads?.length ? { defaultReads } : {}),
|
|
@@ -2202,15 +2278,15 @@ function extraUserAgentDirs(): string[] {
|
|
|
2202
2278
|
.filter((dir) => dir.length > 0);
|
|
2203
2279
|
}
|
|
2204
2280
|
|
|
2205
|
-
export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryResult {
|
|
2281
|
+
export function discoverAgents(cwd: string, scope: AgentScope, preferredModelProvider?: string): AgentDiscoveryResult {
|
|
2206
2282
|
const effectiveCwd = path.resolve(cwd);
|
|
2207
2283
|
const userDirOld = path.join(getAgentDir(), "agents");
|
|
2208
2284
|
const userDirNew = path.join(os.homedir(), ".agents");
|
|
2209
2285
|
const { readDirs: projectAgentDirs, candidateDirs: projectCandidateDirs, preferredDir: projectAgentsDir } = resolveNearestProjectAgentDirs(effectiveCwd);
|
|
2210
2286
|
const userSettingsPath = getUserAgentSettingsPath();
|
|
2211
2287
|
const projectSettingsPath = getProjectAgentSettingsPath(effectiveCwd);
|
|
2212
|
-
const userSettings = scope === "project" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(userSettingsPath);
|
|
2213
|
-
const projectSettings = scope === "user" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(projectSettingsPath);
|
|
2288
|
+
const userSettings = selectProviderOverrides(scope === "project" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(userSettingsPath), preferredModelProvider);
|
|
2289
|
+
const projectSettings = selectProviderOverrides(scope === "user" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(projectSettingsPath), preferredModelProvider);
|
|
2214
2290
|
const defaultProvider = resolveSubagentDefaultProvider(userSettings, projectSettings, projectSettingsPath);
|
|
2215
2291
|
const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath, defaultProvider);
|
|
2216
2292
|
const defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath);
|
|
@@ -2273,7 +2349,7 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
|
|
|
2273
2349
|
return { agents, agentDiagnostics, projectAgentsDir, cwd: effectiveCwd, scope, directories, ...(modelScope !== undefined ? { modelScope } : {}), ...(maxThinking !== undefined ? { maxThinking } : {}) };
|
|
2274
2350
|
}
|
|
2275
2351
|
|
|
2276
|
-
export function discoverAgentsAll(cwd: string): {
|
|
2352
|
+
export function discoverAgentsAll(cwd: string, preferredModelProvider?: string): {
|
|
2277
2353
|
builtin: AgentConfig[];
|
|
2278
2354
|
package: AgentConfig[];
|
|
2279
2355
|
user: AgentConfig[];
|
|
@@ -2296,8 +2372,8 @@ export function discoverAgentsAll(cwd: string): {
|
|
|
2296
2372
|
const { readDirs: projectChainDirs, preferredDir: projectChainDir } = resolveNearestProjectChainDirs(cwd);
|
|
2297
2373
|
const userSettingsPath = getUserAgentSettingsPath();
|
|
2298
2374
|
const projectSettingsPath = getProjectAgentSettingsPath(cwd);
|
|
2299
|
-
const userSettings = readSubagentSettings(userSettingsPath);
|
|
2300
|
-
const projectSettings = readSubagentSettings(projectSettingsPath);
|
|
2375
|
+
const userSettings = selectProviderOverrides(readSubagentSettings(userSettingsPath), preferredModelProvider);
|
|
2376
|
+
const projectSettings = selectProviderOverrides(readSubagentSettings(projectSettingsPath), preferredModelProvider);
|
|
2301
2377
|
const defaultProvider = resolveSubagentDefaultProvider(userSettings, projectSettings, projectSettingsPath);
|
|
2302
2378
|
const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath, defaultProvider);
|
|
2303
2379
|
const defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { registerRuntimeAgent, type RuntimeAgentDefinition, type RuntimeAgentRegistration } from "./runtime-agent-registry.ts";
|
|
3
|
+
|
|
4
|
+
export const RUNTIME_AGENT_REGISTER_EVENT = "pi-subagents:runtime-agent-register:v1";
|
|
5
|
+
export const RUNTIME_AGENT_REGISTER_VERSION = 1;
|
|
6
|
+
|
|
7
|
+
export type RuntimeAgentRegistrationResult =
|
|
8
|
+
| { ok: true; registration: RuntimeAgentRegistration }
|
|
9
|
+
| { ok: false; error: Error };
|
|
10
|
+
|
|
11
|
+
export interface RuntimeAgentRegistrationRequest {
|
|
12
|
+
version: 1;
|
|
13
|
+
name: string;
|
|
14
|
+
definition: RuntimeAgentDefinition;
|
|
15
|
+
result?: RuntimeAgentRegistrationResult;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface RegisterRuntimeAgentViaEventsInput {
|
|
19
|
+
pi: Pick<ExtensionAPI, "events">;
|
|
20
|
+
name: string;
|
|
21
|
+
definition: RuntimeAgentDefinition;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function errorFrom(value: unknown): Error {
|
|
25
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Register through the installed pi-subagents owner in this Pi process. */
|
|
29
|
+
export function registerAgentViaEvents(input: RegisterRuntimeAgentViaEventsInput): RuntimeAgentRegistration {
|
|
30
|
+
const request: RuntimeAgentRegistrationRequest = {
|
|
31
|
+
version: RUNTIME_AGENT_REGISTER_VERSION,
|
|
32
|
+
name: input.name,
|
|
33
|
+
definition: input.definition,
|
|
34
|
+
};
|
|
35
|
+
input.pi.events.emit(RUNTIME_AGENT_REGISTER_EVENT, request);
|
|
36
|
+
const result = request.result as unknown;
|
|
37
|
+
if (result === undefined) {
|
|
38
|
+
throw new Error("pi-subagents is not installed, not ready, or does not support runtime agent event registration.");
|
|
39
|
+
}
|
|
40
|
+
if (result && typeof result === "object" && !Array.isArray(result)) {
|
|
41
|
+
const candidate = result as Record<string, unknown>;
|
|
42
|
+
if (candidate.ok === true && candidate.registration && typeof candidate.registration === "object" && typeof (candidate.registration as { dispose?: unknown }).dispose === "function") {
|
|
43
|
+
return candidate.registration as RuntimeAgentRegistration;
|
|
44
|
+
}
|
|
45
|
+
if (candidate.ok === false && candidate.error instanceof Error) throw candidate.error;
|
|
46
|
+
}
|
|
47
|
+
throw new Error("pi-subagents returned a malformed runtime agent registration result.");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Install the process-local registration listener for the owning pi-subagents runtime. */
|
|
51
|
+
export function registerRuntimeAgentEventListener(pi: ExtensionAPI): () => void {
|
|
52
|
+
return pi.events.on(RUNTIME_AGENT_REGISTER_EVENT, (rawRequest) => {
|
|
53
|
+
if (!rawRequest || typeof rawRequest !== "object" || Array.isArray(rawRequest)) return;
|
|
54
|
+
const request = rawRequest as Record<string, unknown>;
|
|
55
|
+
if (request.result !== undefined) return;
|
|
56
|
+
try {
|
|
57
|
+
if (request.version !== RUNTIME_AGENT_REGISTER_VERSION) {
|
|
58
|
+
throw new Error(`Unsupported runtime agent registration event version '${String(request.version)}'.`);
|
|
59
|
+
}
|
|
60
|
+
const registration = registerRuntimeAgent({
|
|
61
|
+
pi,
|
|
62
|
+
name: request.name as string,
|
|
63
|
+
definition: request.definition as RuntimeAgentDefinition,
|
|
64
|
+
});
|
|
65
|
+
request.result = { ok: true, registration } satisfies RuntimeAgentRegistrationResult;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
request.result = { ok: false, error: errorFrom(error) } satisfies RuntimeAgentRegistrationResult;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|