@narumitw/pi-subagents 0.43.0 → 0.46.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/README.md +53 -13
- package/package.json +1 -1
- package/src/agents.ts +16 -0
- package/src/config-ui.ts +151 -20
- package/src/consult-render.ts +194 -0
- package/src/consult.ts +164 -37
- package/src/cwd-policy.ts +183 -0
- package/src/execution.ts +127 -64
- package/src/in-process-transport.ts +3 -3
- package/src/inspect-render.ts +234 -0
- package/src/inspect.ts +51 -3
- package/src/persistence.ts +29 -0
- package/src/pi-invocation.ts +168 -0
- package/src/registry.ts +12 -0
- package/src/render-common.ts +252 -0
- package/src/render.ts +134 -99
- package/src/runner.ts +19 -22
- package/src/settings.ts +111 -11
- package/src/stateful-guidance.ts +35 -0
- package/src/stateful-lifecycle.ts +31 -0
- package/src/stateful-render.ts +249 -0
- package/src/stateful-safety.ts +91 -0
- package/src/stateful.ts +235 -218
- package/src/subagents.ts +60 -18
- package/src/subprocess-transport.ts +19 -2
package/src/subagents.ts
CHANGED
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
import type { ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
16
16
|
import {
|
|
17
|
+
type ConsultationCwdPolicy,
|
|
17
18
|
type ConsultResourcePolicy,
|
|
19
|
+
type DelegationCwdPolicy,
|
|
18
20
|
discoverAgentCatalog,
|
|
19
21
|
formatAgentCatalog,
|
|
20
22
|
type SubagentSettings,
|
|
@@ -29,6 +31,9 @@ import type { SubagentDetails } from "./runner.js";
|
|
|
29
31
|
import {
|
|
30
32
|
consumeSubagentSettingsNotice,
|
|
31
33
|
DEFAULT_CONSULT_RESOURCE_POLICY,
|
|
34
|
+
DEFAULT_CONSULTATION_CWD_POLICY,
|
|
35
|
+
DEFAULT_DELEGATION_CWD_POLICY,
|
|
36
|
+
inspectSubagentSettings,
|
|
32
37
|
readSubagentSettings,
|
|
33
38
|
} from "./settings.js";
|
|
34
39
|
import { registerStatefulSubagents } from "./stateful.js";
|
|
@@ -36,8 +41,11 @@ import { registerStatefulSubagents } from "./stateful.js";
|
|
|
36
41
|
export default function (pi: ExtensionAPI) {
|
|
37
42
|
const settings = readSubagentSettings();
|
|
38
43
|
let currentSettings: SubagentSettings | undefined = settings;
|
|
44
|
+
let currentCatalog = "";
|
|
39
45
|
const blockingEnabled = settings?.blocking?.enabled !== false;
|
|
40
|
-
const refreshBlockingCatalog = blockingEnabled
|
|
46
|
+
const refreshBlockingCatalog = blockingEnabled
|
|
47
|
+
? registerBlockingSubagent(pi, () => currentSettings)
|
|
48
|
+
: () => undefined;
|
|
41
49
|
let refreshStatefulCatalog: (catalog: string) => void = () => undefined;
|
|
42
50
|
let refreshConsultCatalog: (catalog: string) => void = () => undefined;
|
|
43
51
|
|
|
@@ -46,33 +54,40 @@ export default function (pi: ExtensionAPI) {
|
|
|
46
54
|
// validation against settings that may have changed before this session.
|
|
47
55
|
const loadNotice = consumeSubagentSettingsNotice();
|
|
48
56
|
const refreshedSettings = readSubagentSettings();
|
|
49
|
-
currentSettings = refreshedSettings;
|
|
50
57
|
const refreshedNotice = consumeSubagentSettingsNotice();
|
|
58
|
+
if (!inspectSubagentSettings().error) currentSettings = refreshedSettings;
|
|
51
59
|
const notice = [
|
|
52
60
|
...new Set([loadNotice, refreshedNotice].filter((value) => value !== undefined)),
|
|
53
61
|
].join("\n");
|
|
54
62
|
if (notice) ctx.ui.notify(notice, "warning");
|
|
55
63
|
|
|
56
|
-
|
|
64
|
+
currentCatalog = formatAgentCatalog(
|
|
57
65
|
discoverAgentCatalog(ctx.cwd, ctx.isProjectTrusted(), refreshedSettings),
|
|
58
66
|
).text;
|
|
59
|
-
refreshBlockingCatalog(
|
|
60
|
-
refreshStatefulCatalog(
|
|
61
|
-
refreshConsultCatalog(
|
|
67
|
+
refreshBlockingCatalog(currentCatalog);
|
|
68
|
+
refreshStatefulCatalog(currentCatalog);
|
|
69
|
+
refreshConsultCatalog(currentCatalog);
|
|
62
70
|
});
|
|
63
71
|
|
|
64
72
|
const statefulRuntime = registerStatefulSubagents(pi, {
|
|
65
73
|
blockingEnabled,
|
|
66
74
|
settings: settings?.stateful,
|
|
75
|
+
getSettings: () => currentSettings,
|
|
67
76
|
});
|
|
68
77
|
refreshStatefulCatalog = statefulRuntime.setAgentCatalog;
|
|
69
78
|
const getBlockingEnabled = () => blockingEnabled;
|
|
70
79
|
const getConsultResourcePolicy = () =>
|
|
71
80
|
currentSettings?.consult?.resources ?? DEFAULT_CONSULT_RESOURCE_POLICY;
|
|
81
|
+
const getConsultationCwdPolicy = () =>
|
|
82
|
+
currentSettings?.cwdPolicy?.consultation ?? DEFAULT_CONSULTATION_CWD_POLICY;
|
|
83
|
+
const getDelegationCwdPolicy = () =>
|
|
84
|
+
currentSettings?.cwdPolicy?.delegation ?? DEFAULT_DELEGATION_CWD_POLICY;
|
|
72
85
|
registerSubagentInspect(pi, {
|
|
73
86
|
...statefulRuntime,
|
|
74
87
|
getBlockingEnabled,
|
|
75
88
|
getConsultResourcePolicy,
|
|
89
|
+
getConsultationCwdPolicy,
|
|
90
|
+
getDelegationCwdPolicy,
|
|
76
91
|
});
|
|
77
92
|
if (blockingEnabled) {
|
|
78
93
|
refreshConsultCatalog = registerSubagentConsult(pi, {
|
|
@@ -83,29 +98,52 @@ export default function (pi: ExtensionAPI) {
|
|
|
83
98
|
...statefulRuntime,
|
|
84
99
|
getBlockingEnabled,
|
|
85
100
|
getConsultResourcePolicy,
|
|
101
|
+
getConsultationCwdPolicy,
|
|
102
|
+
getDelegationCwdPolicy,
|
|
86
103
|
setConsultResourcePolicy(value: ConsultResourcePolicy) {
|
|
87
104
|
currentSettings = {
|
|
88
105
|
...(currentSettings ?? {}),
|
|
89
106
|
consult: { ...(currentSettings?.consult ?? {}), resources: value },
|
|
90
107
|
};
|
|
108
|
+
refreshConsultCatalog(currentCatalog);
|
|
109
|
+
},
|
|
110
|
+
setConsultationCwdPolicy(value: ConsultationCwdPolicy) {
|
|
111
|
+
currentSettings = {
|
|
112
|
+
...(currentSettings ?? {}),
|
|
113
|
+
cwdPolicy: { ...(currentSettings?.cwdPolicy ?? {}), consultation: value },
|
|
114
|
+
};
|
|
115
|
+
refreshConsultCatalog(currentCatalog);
|
|
116
|
+
},
|
|
117
|
+
setDelegationCwdPolicy(value: DelegationCwdPolicy) {
|
|
118
|
+
currentSettings = {
|
|
119
|
+
...(currentSettings ?? {}),
|
|
120
|
+
cwdPolicy: { ...(currentSettings?.cwdPolicy ?? {}), delegation: value },
|
|
121
|
+
};
|
|
122
|
+
refreshBlockingCatalog(currentCatalog);
|
|
123
|
+
statefulRuntime.refreshSettingsGuidance();
|
|
91
124
|
},
|
|
92
125
|
});
|
|
93
126
|
}
|
|
94
127
|
|
|
95
|
-
function registerBlockingSubagent(
|
|
128
|
+
function registerBlockingSubagent(
|
|
129
|
+
pi: ExtensionAPI,
|
|
130
|
+
getSettings: () => SubagentSettings | undefined,
|
|
131
|
+
): (catalog: string) => void {
|
|
96
132
|
let catalog = "";
|
|
97
|
-
const baseDescription =
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
133
|
+
const baseDescription = () =>
|
|
134
|
+
[
|
|
135
|
+
"Run specialized subagents as a blocking operation with isolated contexts.",
|
|
136
|
+
"The call blocks the main agent until every worker and optional aggregator finishes, so queued steering waits.",
|
|
137
|
+
"Modes: single (agent + task), parallel (tasks array), chain (sequential with {previous} placeholder).",
|
|
138
|
+
"Parallel mode may include an aggregator fan-in step that receives all task outputs. Use subagent_consult instead for one synchronous child that must be executor-constrained to read-only tools.",
|
|
139
|
+
'Default agent scope is "user" (from ~/.pi/agent/agents).',
|
|
140
|
+
'To enable project-local agents in .pi/agents, pass agentScope: "both" (or "project") as a top-level argument for that call.',
|
|
141
|
+
`Working-directory target policy: ${getSettings()?.cwdPolicy?.delegation ?? DEFAULT_DELEGATION_CWD_POLICY}. This controls launch targets and protected project resources, not filesystem access or sandboxing.`,
|
|
142
|
+
].join(" ");
|
|
105
143
|
const definition: ToolDefinition<typeof SubagentParams, SubagentDetails> = {
|
|
106
144
|
name: "subagent",
|
|
107
145
|
label: "Blocking Subagent",
|
|
108
|
-
description: appendAgentCatalog(baseDescription, catalog),
|
|
146
|
+
description: appendAgentCatalog(baseDescription(), catalog),
|
|
109
147
|
promptSnippet:
|
|
110
148
|
"Run blocking isolated subagents only when their outputs are required before the main agent can continue.",
|
|
111
149
|
promptGuidelines: [
|
|
@@ -121,7 +159,7 @@ function registerBlockingSubagent(pi: ExtensionAPI): (catalog: string) => void {
|
|
|
121
159
|
parameters: SubagentParams,
|
|
122
160
|
|
|
123
161
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
124
|
-
return executeSubagent(toolCallId, params, signal, onUpdate, ctx);
|
|
162
|
+
return executeSubagent(toolCallId, params, signal, onUpdate, ctx, getSettings());
|
|
125
163
|
},
|
|
126
164
|
|
|
127
165
|
renderCall(args, theme) {
|
|
@@ -140,7 +178,7 @@ function registerBlockingSubagent(pi: ExtensionAPI): (catalog: string) => void {
|
|
|
140
178
|
});
|
|
141
179
|
return (nextCatalog: string) => {
|
|
142
180
|
catalog = nextCatalog;
|
|
143
|
-
definition.description = appendAgentCatalog(baseDescription, catalog);
|
|
181
|
+
definition.description = appendAgentCatalog(baseDescription(), catalog);
|
|
144
182
|
pi.registerTool<typeof SubagentParams, SubagentDetails>(definition);
|
|
145
183
|
};
|
|
146
184
|
}
|
|
@@ -154,8 +192,11 @@ export { formatTokens, formatUsageStats } from "./render.js";
|
|
|
154
192
|
export { buildPiArgs } from "./runner.js";
|
|
155
193
|
export {
|
|
156
194
|
DEFAULT_CONSULT_RESOURCE_POLICY,
|
|
195
|
+
DEFAULT_CONSULTATION_CWD_POLICY,
|
|
196
|
+
DEFAULT_DELEGATION_CWD_POLICY,
|
|
157
197
|
inspectCompletionDeliverySettings,
|
|
158
198
|
inspectConsultResourceSettings,
|
|
199
|
+
inspectCwdPolicySettings,
|
|
159
200
|
inspectDelegationWorkflowSettings,
|
|
160
201
|
inspectSubagentSettings,
|
|
161
202
|
normalizeAgentSettings,
|
|
@@ -169,5 +210,6 @@ export {
|
|
|
169
210
|
updateAgentToolsSetting,
|
|
170
211
|
updateCompletionDeliverySetting,
|
|
171
212
|
updateConsultResourceSetting,
|
|
213
|
+
updateCwdPolicySetting,
|
|
172
214
|
updateDelegationWorkflowSetting,
|
|
173
215
|
} from "./settings.js";
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type AgentConfig,
|
|
3
|
+
discoverAgents,
|
|
4
|
+
type SubagentSettings,
|
|
5
|
+
type SubagentThinkingLevel,
|
|
6
|
+
} from "./agents.js";
|
|
2
7
|
import type { ManagedAgent, TurnOutcome } from "./registry.js";
|
|
3
8
|
import { getResultFinalOutput, runSingleAgent, type SubagentDetails } from "./runner.js";
|
|
4
9
|
import { readSubagentSettings, resolveSubagentThinkingLevel } from "./settings.js";
|
|
@@ -12,11 +17,17 @@ export function resolveStatefulSubprocessThinkingLevel(
|
|
|
12
17
|
return resolveSubagentThinkingLevel(agents, record.agent, record.thinkingLevel);
|
|
13
18
|
}
|
|
14
19
|
|
|
20
|
+
export interface SubprocessTransportOptions {
|
|
21
|
+
getSettings?: () => SubagentSettings | undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
15
24
|
export class SubprocessTransport implements SubagentTransport {
|
|
16
25
|
readonly kind = "subprocess" as const;
|
|
17
26
|
|
|
27
|
+
constructor(private readonly options: SubprocessTransportOptions = {}) {}
|
|
28
|
+
|
|
18
29
|
async runTurn(record: ManagedAgent, task: string, signal: AbortSignal): Promise<TurnOutcome> {
|
|
19
|
-
const settings = readSubagentSettings();
|
|
30
|
+
const settings = this.options.getSettings ? this.options.getSettings() : readSubagentSettings();
|
|
20
31
|
const discovery = discoverAgents(record.cwd, record.agentScope ?? "user", settings);
|
|
21
32
|
const agent = discovery.agents.find((candidate) => candidate.name === record.agent);
|
|
22
33
|
const boundedTask = buildStatefulTurnPrompt(record, task);
|
|
@@ -38,6 +49,12 @@ export class SubprocessTransport implements SubagentTransport {
|
|
|
38
49
|
resolveStatefulTurnTimeout(agent),
|
|
39
50
|
undefined,
|
|
40
51
|
makeDetails,
|
|
52
|
+
undefined,
|
|
53
|
+
{
|
|
54
|
+
projectTrust:
|
|
55
|
+
record.target?.trust.projectTrusted ??
|
|
56
|
+
(record.agentScope === "project" || record.agentScope === "both"),
|
|
57
|
+
},
|
|
41
58
|
);
|
|
42
59
|
return {
|
|
43
60
|
output: getResultFinalOutput(single),
|