pi-subagents 0.60.0 → 0.61.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 +32 -0
- package/docs/agents.md +2 -2
- package/docs/configuration.md +9 -5
- package/docs/extension-api.md +14 -7
- package/docs/models.md +1 -1
- package/docs/observability.md +1 -1
- package/docs/tool-reference.md +12 -3
- package/docs/workflows.md +14 -13
- package/install.mjs +2 -1
- package/package.json +1 -1
- package/skills/pi-subagents/SKILL.md +6 -4
- package/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
- package/skills/pi-subagents/references/execution-controls.md +42 -11
- package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +4 -4
- package/skills/pi-subagents/references/review-and-validation.md +1 -1
- package/src/agents/agent-management.ts +102 -63
- package/src/agents/agents.ts +527 -221
- package/src/api/background-work.ts +7 -2
- package/src/api/external-runs.ts +67 -4
- package/src/api/preflight.ts +13 -8
- package/src/api/shared-types.ts +1 -0
- package/src/extension/index.ts +7 -4
- package/src/extension/public-execution.ts +47 -4
- package/src/extension/rpc.ts +62 -4
- package/src/extension/schemas.ts +11 -7
- package/src/extension/tool-description.ts +14 -18
- package/src/runs/background/async-execution.ts +51 -35
- package/src/runs/background/async-job-tracker.ts +62 -3
- package/src/runs/background/async-resume.ts +3 -1
- package/src/runs/background/async-status.ts +59 -9
- package/src/runs/background/auto-drain.ts +1 -1
- package/src/runs/background/fleet-view.ts +1 -1
- package/src/runs/background/result-watcher.ts +1 -1
- package/src/runs/background/resume-guidance.ts +1 -1
- package/src/runs/background/run-status.ts +2 -2
- package/src/runs/background/subagent-runner.ts +1 -2
- package/src/runs/background/subagent-wait.ts +20 -21
- package/src/runs/background/wait-completions.ts +1 -1
- package/src/runs/background/wait-tool.ts +24 -18
- package/src/runs/foreground/execution.ts +61 -2
- package/src/runs/foreground/subagent-executor.ts +178 -58
- package/src/runs/shared/acceptance.ts +43 -18
- package/src/runs/shared/host-step-status.ts +1 -0
- package/src/runs/shared/model-fallback.ts +61 -17
- package/src/runs/shared/permissions.ts +1 -1
- package/src/runs/shared/tool-timeout.ts +1 -1
- package/src/runs/shared/workflow-graph.ts +3 -2
- package/src/shared/types.ts +40 -3
- package/src/shared/workflow-child-permit.ts +91 -0
- package/src/slash/prompt-template-bridge.ts +37 -1
- package/src/slash/slash-commands.ts +18 -26
- package/src/tui/render.ts +95 -52
- package/src/workflows/scripted-workflow.ts +153 -4
- package/src/workflows/workflow-child-summary.ts +1 -1
- package/src/workflows/workflow-receipt.ts +41 -4
- package/src/workflows/workflow-resources.ts +150 -0
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
type AgentDiscoveryDiagnostic,
|
|
8
8
|
type AgentScope,
|
|
9
9
|
type AgentSource,
|
|
10
|
-
BUILTIN_AGENT_NAMES,
|
|
11
10
|
defaultInheritProjectContext,
|
|
12
11
|
defaultInheritSkills,
|
|
13
12
|
defaultSystemPromptMode,
|
|
@@ -28,7 +27,7 @@ import {
|
|
|
28
27
|
buildProactiveSkillSubagentRecommendationLines,
|
|
29
28
|
} from "./proactive-skills.ts";
|
|
30
29
|
import { parseFrontmatter, parseFrontmatterList } from "./frontmatter.ts";
|
|
31
|
-
import { toModelInfo } from "../shared/model-info.ts";
|
|
30
|
+
import { resolveEffectiveThinking, toModelInfo } from "../shared/model-info.ts";
|
|
32
31
|
import { resolveSubagentModelOverride, type ParentModel } from "../runs/shared/model-fallback.ts";
|
|
33
32
|
import { validateToolBudgetConfig } from "../runs/shared/tool-budget.ts";
|
|
34
33
|
import { validateAcceptanceInput } from "../runs/shared/acceptance.ts";
|
|
@@ -37,7 +36,7 @@ import type { AcceptanceInput, AgentCapabilitiesSnapshot, AgentCapabilityRow, De
|
|
|
37
36
|
import { getProjectConfigDir } from "../shared/utils.ts";
|
|
38
37
|
import { previewDisplayText } from "../shared/display-text.ts";
|
|
39
38
|
import { capabilityCeilingAgentRestrictionSources, isAgentAllowedByCapabilityCeiling, resolveCurrentSubagentCapabilityCeiling } from "../runs/shared/capability-ceiling.ts";
|
|
40
|
-
import {
|
|
39
|
+
import { mergeRuntimeAgents, type RuntimeAgentOwner } from "./runtime-agent-registry.ts";
|
|
41
40
|
import { listExternalJobProviders } from "../api/external-job-provider.ts";
|
|
42
41
|
|
|
43
42
|
type ManagementAction = "list" | "get" | "models" | "create" | "update" | "delete" | "eject" | "disable" | "enable" | "reset";
|
|
@@ -129,18 +128,39 @@ function allAgents(d: { builtin: AgentConfig[]; package: AgentConfig[]; user: Ag
|
|
|
129
128
|
return [...d.builtin, ...d.package, ...d.user, ...d.project];
|
|
130
129
|
}
|
|
131
130
|
|
|
132
|
-
function
|
|
133
|
-
|
|
131
|
+
function effectiveAgentsForScope(
|
|
132
|
+
scope: AgentScope,
|
|
133
|
+
d: { builtin: AgentConfig[]; package: AgentConfig[]; user: AgentConfig[]; project: AgentConfig[] },
|
|
134
|
+
runtimeAgentOwner?: RuntimeAgentOwner,
|
|
135
|
+
): AgentConfig[] {
|
|
136
|
+
let agents = mergeAgentsForScope(scope, d.user, d.project, d.builtin, d.package);
|
|
137
|
+
if (runtimeAgentOwner) {
|
|
138
|
+
agents = mergeRuntimeAgents(runtimeAgentOwner, { agents }, allAgents(d)).agents;
|
|
139
|
+
}
|
|
140
|
+
return agents;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function availableAgentNamesFromDiscovery(
|
|
144
|
+
d: { builtin: AgentConfig[]; package: AgentConfig[]; user: AgentConfig[]; project: AgentConfig[] },
|
|
145
|
+
runtimeAgentOwner?: RuntimeAgentOwner,
|
|
146
|
+
): string[] {
|
|
147
|
+
const agents = runtimeAgentOwner ? effectiveAgentsForScope("both", d, runtimeAgentOwner) : allAgents(d);
|
|
148
|
+
return [...new Set(agents.map((agent) => agent.name))].sort((a, b) => a.localeCompare(b));
|
|
134
149
|
}
|
|
135
150
|
|
|
136
151
|
function availableAgentNames(cwd: string): string[] {
|
|
137
152
|
return availableAgentNamesFromDiscovery(discoverAgentsAll(cwd));
|
|
138
153
|
}
|
|
139
154
|
|
|
140
|
-
function findAgentsInDiscovery(
|
|
155
|
+
function findAgentsInDiscovery(
|
|
156
|
+
name: string,
|
|
157
|
+
d: { builtin: AgentConfig[]; package: AgentConfig[]; user: AgentConfig[]; project: AgentConfig[] },
|
|
158
|
+
scope: AgentScope = "both",
|
|
159
|
+
runtimeAgentOwner?: RuntimeAgentOwner,
|
|
160
|
+
): AgentConfig[] {
|
|
141
161
|
const raw = name.trim();
|
|
142
162
|
const sanitized = sanitizeName(raw);
|
|
143
|
-
const scoped =
|
|
163
|
+
const scoped = effectiveAgentsForScope(scope, d, runtimeAgentOwner);
|
|
144
164
|
let resolved = resolveAgentName(raw, scoped);
|
|
145
165
|
if (!resolved.agent && !resolved.error && sanitized !== raw) resolved = resolveAgentName(sanitized, scoped);
|
|
146
166
|
if (resolved.agent) return scoped.filter((agent) => agent.name === resolved.agent!.name).sort((a, b) => a.source.localeCompare(b.source));
|
|
@@ -863,16 +883,7 @@ function formatAgentDetail(agent: AgentConfig): string {
|
|
|
863
883
|
export function handleList(params: ManagementParams, ctx: ManagementContext): AgentToolResult<Details> {
|
|
864
884
|
const scope = normalizeListScope(params.agentScope) ?? "both";
|
|
865
885
|
const d = discoverAgentsAll(ctx.cwd, ctx.model?.provider);
|
|
866
|
-
let scopedAgents =
|
|
867
|
-
if (ctx.runtimeAgentOwner && listRuntimeAgentConfigs(ctx.runtimeAgentOwner).length > 0) {
|
|
868
|
-
const configuredAgents: AgentConfig[] = [
|
|
869
|
-
...d.builtin,
|
|
870
|
-
...d.package,
|
|
871
|
-
...d.user,
|
|
872
|
-
...d.project,
|
|
873
|
-
];
|
|
874
|
-
scopedAgents = mergeRuntimeAgents(ctx.runtimeAgentOwner, { agents: scopedAgents }, configuredAgents).agents;
|
|
875
|
-
}
|
|
886
|
+
let scopedAgents = effectiveAgentsForScope(scope, d, ctx.runtimeAgentOwner);
|
|
876
887
|
scopedAgents = scopedAgents
|
|
877
888
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
878
889
|
const capabilityCeiling = resolveCurrentSubagentCapabilityCeiling(ctx.currentSessionId);
|
|
@@ -913,80 +924,108 @@ function formatModelSource(agent: AgentConfig, currentModel: ParentModel | undef
|
|
|
913
924
|
if (agent.modelSource?.type === "subagents.defaultModel" && agent.model === agent.modelSource.model) {
|
|
914
925
|
return `${agent.modelSource.scope} defaultModel`;
|
|
915
926
|
}
|
|
916
|
-
if (agent.model) return
|
|
927
|
+
if (agent.model) return `${agent.source} agent config`;
|
|
917
928
|
if (currentModel) return "inherits current session model";
|
|
918
929
|
return "inherit requested, but no current session model is available";
|
|
919
930
|
}
|
|
920
931
|
|
|
921
932
|
function handleModels(params: ManagementParams, ctx: ManagementContext): AgentToolResult<Details> {
|
|
922
933
|
const requestedAgent = params.agent?.trim();
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
}
|
|
934
|
+
const scope = normalizeListScope(params.agentScope);
|
|
935
|
+
if (!scope) return result("agentScope must be 'user', 'project', or 'both' for models.", true);
|
|
926
936
|
|
|
927
937
|
const discovered = discoverAgentsAll(ctx.cwd, ctx.model?.provider);
|
|
928
|
-
const
|
|
929
|
-
|
|
938
|
+
const effectiveAgents = effectiveAgentsForScope(scope, discovered, ctx.runtimeAgentOwner)
|
|
939
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
930
940
|
const availableModels = ctx.modelRegistry.getAvailable().map(toModelInfo);
|
|
931
941
|
const currentModel = ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined;
|
|
932
942
|
const preferredProvider = ctx.model?.provider;
|
|
933
|
-
const
|
|
943
|
+
const capabilityCeiling = resolveCurrentSubagentCapabilityCeiling(ctx.currentSessionId);
|
|
934
944
|
|
|
945
|
+
let selectedAgents = effectiveAgents;
|
|
935
946
|
if (requestedAgent) {
|
|
936
|
-
const
|
|
937
|
-
|
|
938
|
-
const
|
|
939
|
-
const
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
`
|
|
946
|
-
];
|
|
947
|
-
if (agent.override) {
|
|
948
|
-
lines.push("Override file:");
|
|
949
|
-
lines.push(` ${agent.override.path}`);
|
|
950
|
-
}
|
|
951
|
-
if (agent.model && resolvedModel && agent.model !== resolvedModel) {
|
|
952
|
-
lines.push("Requested model setting:");
|
|
953
|
-
lines.push(` ${agent.model}`);
|
|
947
|
+
const matches = findAgentsInDiscovery(requestedAgent, discovered, scope, ctx.runtimeAgentOwner);
|
|
948
|
+
const diagnostics = diagnosticsForScope(discovered.agentDiagnostics, scope);
|
|
949
|
+
const normalizedName = sanitizeName(requestedAgent);
|
|
950
|
+
const diagnostic = findBlockingAgentDiagnostic(requestedAgent, matches, diagnostics)
|
|
951
|
+
?? (normalizedName !== requestedAgent ? findBlockingAgentDiagnostic(normalizedName, matches, diagnostics) : undefined);
|
|
952
|
+
if (diagnostic) return result(`Agent '${params.agent}' has invalid configuration: ${diagnostic.error}`, true);
|
|
953
|
+
const distinctNames = [...new Set(matches.map((agent) => agent.name))];
|
|
954
|
+
if (distinctNames.length > 1) return result(`Ambiguous agent alias or name '${params.agent}': ${distinctNames.sort((a, b) => a.localeCompare(b)).join(", ")}`, true);
|
|
955
|
+
if (!matches.length) {
|
|
956
|
+
return result(`Agent '${params.agent}' not found. Available: ${availableAgentNamesFromDiscovery(discovered, ctx.runtimeAgentOwner).join(", ") || "none"}.`, true);
|
|
954
957
|
}
|
|
955
|
-
|
|
956
|
-
lines.push("Current session model:");
|
|
957
|
-
lines.push(` ${currentModel ? `${currentModel.provider}/${currentModel.id}` : "(unavailable)"}`);
|
|
958
|
-
return result(lines.join("\n"));
|
|
958
|
+
selectedAgents = [matches[0]!];
|
|
959
959
|
}
|
|
960
960
|
|
|
961
961
|
const lines = [
|
|
962
|
-
"
|
|
963
|
-
"",
|
|
964
|
-
"Current session model:",
|
|
965
|
-
` ${currentModel ? `${currentModel.provider}/${currentModel.id}` : "(unavailable)"}`,
|
|
962
|
+
requestedAgent ? "Subagent model" : "Subagent models",
|
|
966
963
|
"",
|
|
964
|
+
...(requestedAgent ? [] : [
|
|
965
|
+
"Current session model:",
|
|
966
|
+
` ${currentModel ? `${currentModel.provider}/${currentModel.id}` : "(unavailable)"}`,
|
|
967
|
+
"",
|
|
968
|
+
]),
|
|
967
969
|
];
|
|
968
970
|
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
971
|
+
const modelEntries = selectedAgents.flatMap((agent) => requestedAgent
|
|
972
|
+
? [{ agent, name: requestedAgent }]
|
|
973
|
+
: [{ agent, name: agent.name }, ...(agent.aliases ?? []).map((name) => ({ agent, name }))]);
|
|
974
|
+
for (const { agent, name } of modelEntries) {
|
|
975
|
+
const resolvedModel = resolveSubagentModelOverride(agent.model, currentModel, availableModels, agent.modelProvider ?? preferredProvider);
|
|
976
|
+
const effectiveThinking = resolveEffectiveThinking(resolvedModel, agent.thinking)
|
|
977
|
+
?? (agent.thinking === false ? "off" : undefined);
|
|
978
|
+
const source = `${formatModelSource(agent, currentModel)}${agent.disabled ? "; disabled" : ""}${isAgentAllowedByCapabilityCeiling(agent.name, capabilityCeiling) ? "" : "; restricted"}`;
|
|
979
|
+
if (requestedAgent) {
|
|
980
|
+
lines.push(`Agent: ${requestedAgent}`);
|
|
981
|
+
lines.push("Effective model:");
|
|
982
|
+
lines.push(` ${resolvedModel ?? "(unresolved)"}`);
|
|
983
|
+
lines.push(`Source: ${source}`);
|
|
984
|
+
lines.push(`Thinking: ${effectiveThinking ?? "default"}`);
|
|
985
|
+
if (agent.fallbackModels?.length) {
|
|
986
|
+
lines.push("Fallback models:");
|
|
987
|
+
for (const fallback of agent.fallbackModels) {
|
|
988
|
+
lines.push(` ${resolveSubagentModelOverride(fallback, currentModel, availableModels, agent.modelProvider ?? preferredProvider) ?? fallback}`);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
if (agent.override) {
|
|
992
|
+
lines.push("Override file:");
|
|
993
|
+
lines.push(` ${agent.override.path}`);
|
|
994
|
+
}
|
|
995
|
+
if (agent.model && resolvedModel && agent.model !== resolvedModel) {
|
|
996
|
+
lines.push("Requested model setting:");
|
|
997
|
+
lines.push(` ${agent.model}`);
|
|
998
|
+
}
|
|
999
|
+
if (agent.disabled) lines.push("Disabled: true");
|
|
1000
|
+
if (!isAgentAllowedByCapabilityCeiling(agent.name, capabilityCeiling)) lines.push("Restricted: true");
|
|
1001
|
+
lines.push("Current session model:");
|
|
1002
|
+
lines.push(` ${currentModel ? `${currentModel.provider}/${currentModel.id}` : "(unavailable)"}`);
|
|
1003
|
+
break;
|
|
978
1004
|
}
|
|
979
|
-
const resolvedModel = resolveSubagentModelOverride(agent.model, currentModel, availableModels, preferredProvider);
|
|
980
|
-
const source = `${formatModelSource(agent, currentModel)}${agent.disabled ? "; disabled" : ""}`;
|
|
981
1005
|
lines.push(name);
|
|
982
1006
|
lines.push(" model:");
|
|
983
1007
|
lines.push(` ${resolvedModel ?? "(unresolved)"}`);
|
|
984
1008
|
lines.push(` source: ${source}`);
|
|
1009
|
+
lines.push(` thinking: ${effectiveThinking ?? "default"}`);
|
|
1010
|
+
if (agent.fallbackModels?.length) {
|
|
1011
|
+
lines.push(" fallback models:");
|
|
1012
|
+
for (const fallback of agent.fallbackModels) {
|
|
1013
|
+
lines.push(` ${resolveSubagentModelOverride(fallback, currentModel, availableModels, agent.modelProvider ?? preferredProvider) ?? fallback}`);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
if (agent.override) {
|
|
1017
|
+
lines.push(" override file:");
|
|
1018
|
+
lines.push(` ${agent.override.path}`);
|
|
1019
|
+
}
|
|
1020
|
+
if (agent.model && resolvedModel && agent.model !== resolvedModel) {
|
|
1021
|
+
lines.push(" requested model setting:");
|
|
1022
|
+
lines.push(` ${agent.model}`);
|
|
1023
|
+
}
|
|
985
1024
|
lines.push("");
|
|
986
1025
|
}
|
|
987
1026
|
|
|
988
1027
|
const availableFullIds = availableModels.map((m) => m.fullId).sort();
|
|
989
|
-
if (availableFullIds.length > 0) {
|
|
1028
|
+
if (!requestedAgent && availableFullIds.length > 0) {
|
|
990
1029
|
lines.push("Available models in this session's registry (copy an exact provider/id when passing model):");
|
|
991
1030
|
lines.push("");
|
|
992
1031
|
const shown = availableFullIds.slice(0, 80);
|
|
@@ -995,7 +1034,7 @@ function handleModels(params: ManagementParams, ctx: ManagementContext): AgentTo
|
|
|
995
1034
|
lines.push("");
|
|
996
1035
|
lines.push("Use an exact provider/id from this list when you pass model; bare ids resolve only when unique in the registry.");
|
|
997
1036
|
}
|
|
998
|
-
|
|
1037
|
+
if (!requestedAgent) appendAgentDiagnosticLines(lines, diagnosticsForScope(discovered.agentDiagnostics, scope));
|
|
999
1038
|
return result(lines.join("\n"));
|
|
1000
1039
|
}
|
|
1001
1040
|
|