@narumitw/pi-subagents 0.38.0 → 0.40.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 +6 -3
- package/package.json +6 -6
- package/src/config-ui.ts +2 -0
- package/src/stateful-tool-params.ts +36 -24
package/README.md
CHANGED
|
@@ -390,13 +390,16 @@ Built-in agents inherit the active/default Pi model instead of forcing a provide
|
|
|
390
390
|
|
|
391
391
|
Open `/subagents`, choose **Advanced settings**, then **Agent tool permissions** in an interactive
|
|
392
392
|
Pi session to edit the tools each subagent may use. The standard bounded multi-select keeps a
|
|
393
|
-
one-save draft: toggles do not write until **Save changes**, Escape
|
|
394
|
-
configured tool names remain visible and preserved.
|
|
393
|
+
one-save draft: toggles do not write until **Save changes**, Escape leaves the draft without writing,
|
|
394
|
+
and unavailable configured tool names remain visible and preserved. In TUI mode, type to fuzzy-search
|
|
395
|
+
tool names and availability metadata; Save and Discard remain pinned below the matches. These are user
|
|
396
|
+
settings stored in `~/.pi/agent/pi-subagents.json` and affect future sessions.
|
|
395
397
|
|
|
396
398
|
Compatibility: a valid legacy `pi-subagents-config.json` remains readable with a warning and is never modified automatically; rename it to `pi-subagents.json`. The first subsequent settings save writes the canonical file. If both files exist, the new filename takes precedence.
|
|
397
399
|
|
|
398
400
|
- Select an agent, then press Enter or Space to toggle tools.
|
|
399
|
-
-
|
|
401
|
+
- Choose **Save changes** to write the draft, choose **Discard draft** to abandon it, or press Esc to
|
|
402
|
+
return to agent selection without writing.
|
|
400
403
|
- Save the default selection to remove a custom override and use the agent defaults again.
|
|
401
404
|
- Deselect every tool and save to run that agent with no tools.
|
|
402
405
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@narumitw/pi-subagents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"description": "Pi extension for delegating work to specialized isolated subagents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
"@earendil-works/pi-tui": "*"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@biomejs/biome": "2.5.
|
|
44
|
-
"@earendil-works/pi-agent-core": "0.
|
|
45
|
-
"@earendil-works/pi-ai": "0.
|
|
46
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
47
|
-
"@earendil-works/pi-tui": "0.
|
|
43
|
+
"@biomejs/biome": "2.5.6",
|
|
44
|
+
"@earendil-works/pi-agent-core": "0.83.0",
|
|
45
|
+
"@earendil-works/pi-ai": "0.83.0",
|
|
46
|
+
"@earendil-works/pi-coding-agent": "0.83.0",
|
|
47
|
+
"@earendil-works/pi-tui": "0.83.0",
|
|
48
48
|
"typescript": "7.0.2"
|
|
49
49
|
},
|
|
50
50
|
"repository": {
|
package/src/config-ui.ts
CHANGED
|
@@ -297,6 +297,7 @@ async function showSubagentManager(
|
|
|
297
297
|
"tool-draft": () => ({
|
|
298
298
|
kind: "multiSelect",
|
|
299
299
|
title: toolDraft ? `${safeTerminalText(toolDraft.agentName)} tools` : "Agent tools",
|
|
300
|
+
enableSearch: true,
|
|
300
301
|
lines: toolDraft
|
|
301
302
|
? [
|
|
302
303
|
`Source: ${safeTerminalText(toolDraft.agentSource)}`,
|
|
@@ -311,6 +312,7 @@ async function showSubagentManager(
|
|
|
311
312
|
id: name,
|
|
312
313
|
label: safeTerminalText(name),
|
|
313
314
|
description: available ? "Available tool" : "Configured tool is not currently loaded",
|
|
315
|
+
searchText: available ? "available tool" : "configured unavailable preserved",
|
|
314
316
|
selected: toolDraft?.selected.has(name) ?? false,
|
|
315
317
|
disabled: !available,
|
|
316
318
|
disabledReason: available
|
|
@@ -73,6 +73,7 @@ export type ValidatedMailboxParams =
|
|
|
73
73
|
|
|
74
74
|
export function validateManageParams(params: unknown): ValidatedManageParams {
|
|
75
75
|
const values = parameterRecord(params, "subagent_manage");
|
|
76
|
+
assertKnownKeys("subagent_manage", values, ["action", "agentId", "includeClosed", "subtree"]);
|
|
76
77
|
const action = values.action;
|
|
77
78
|
if (
|
|
78
79
|
typeof action !== "string" ||
|
|
@@ -81,18 +82,32 @@ export function validateManageParams(params: unknown): ValidatedManageParams {
|
|
|
81
82
|
throw new Error(`subagent_manage action must be one of: ${MANAGE_ACTIONS.join(", ")}`);
|
|
82
83
|
}
|
|
83
84
|
if (action === "list") {
|
|
84
|
-
assertOnlyActionKeys("subagent_manage", action, values, ["action", "includeClosed"]);
|
|
85
85
|
assertOptionalBoolean("subagent_manage", action, values, "includeClosed");
|
|
86
|
-
return
|
|
86
|
+
return {
|
|
87
|
+
action,
|
|
88
|
+
...(values.includeClosed === undefined ? {} : { includeClosed: values.includeClosed }),
|
|
89
|
+
} as ValidatedManageParams;
|
|
87
90
|
}
|
|
88
|
-
assertOnlyActionKeys("subagent_manage", action, values, ["action", "agentId", "subtree"]);
|
|
89
91
|
assertRequiredString("subagent_manage", action, values, "agentId");
|
|
90
92
|
assertOptionalBoolean("subagent_manage", action, values, "subtree");
|
|
91
|
-
return
|
|
93
|
+
return {
|
|
94
|
+
action,
|
|
95
|
+
agentId: values.agentId,
|
|
96
|
+
...(values.subtree === undefined ? {} : { subtree: values.subtree }),
|
|
97
|
+
} as ValidatedManageParams;
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
export function validateMailboxParams(params: unknown): ValidatedMailboxParams {
|
|
95
101
|
const values = parameterRecord(params, "subagent_mailbox");
|
|
102
|
+
assertKnownKeys("subagent_mailbox", values, [
|
|
103
|
+
"action",
|
|
104
|
+
"agentId",
|
|
105
|
+
"message",
|
|
106
|
+
"senderId",
|
|
107
|
+
"deduplicationKey",
|
|
108
|
+
"acknowledge",
|
|
109
|
+
"limit",
|
|
110
|
+
]);
|
|
96
111
|
const action = values.action;
|
|
97
112
|
if (
|
|
98
113
|
typeof action !== "string" ||
|
|
@@ -101,13 +116,6 @@ export function validateMailboxParams(params: unknown): ValidatedMailboxParams {
|
|
|
101
116
|
throw new Error(`subagent_mailbox action must be one of: ${MAILBOX_ACTIONS.join(", ")}`);
|
|
102
117
|
}
|
|
103
118
|
if (action === "send") {
|
|
104
|
-
assertOnlyActionKeys("subagent_mailbox", action, values, [
|
|
105
|
-
"action",
|
|
106
|
-
"agentId",
|
|
107
|
-
"message",
|
|
108
|
-
"senderId",
|
|
109
|
-
"deduplicationKey",
|
|
110
|
-
]);
|
|
111
119
|
assertRequiredString("subagent_mailbox", action, values, "agentId");
|
|
112
120
|
assertRequiredString("subagent_mailbox", action, values, "message");
|
|
113
121
|
const message = values.message as string;
|
|
@@ -123,14 +131,16 @@ export function validateMailboxParams(params: unknown): ValidatedMailboxParams {
|
|
|
123
131
|
'subagent_mailbox action "send" requires deduplicationKey at most 256 characters',
|
|
124
132
|
);
|
|
125
133
|
}
|
|
126
|
-
return
|
|
134
|
+
return {
|
|
135
|
+
action,
|
|
136
|
+
agentId: values.agentId,
|
|
137
|
+
message,
|
|
138
|
+
...(values.senderId === undefined ? {} : { senderId: values.senderId }),
|
|
139
|
+
...(values.deduplicationKey === undefined
|
|
140
|
+
? {}
|
|
141
|
+
: { deduplicationKey: values.deduplicationKey }),
|
|
142
|
+
} as ValidatedMailboxParams;
|
|
127
143
|
}
|
|
128
|
-
assertOnlyActionKeys("subagent_mailbox", action, values, [
|
|
129
|
-
"action",
|
|
130
|
-
"agentId",
|
|
131
|
-
"acknowledge",
|
|
132
|
-
"limit",
|
|
133
|
-
]);
|
|
134
144
|
assertRequiredString("subagent_mailbox", action, values, "agentId");
|
|
135
145
|
assertOptionalBoolean("subagent_mailbox", action, values, "acknowledge");
|
|
136
146
|
if (
|
|
@@ -142,7 +152,12 @@ export function validateMailboxParams(params: unknown): ValidatedMailboxParams {
|
|
|
142
152
|
) {
|
|
143
153
|
throw new Error('subagent_mailbox action "read" requires limit between 1 and 20');
|
|
144
154
|
}
|
|
145
|
-
return
|
|
155
|
+
return {
|
|
156
|
+
action,
|
|
157
|
+
agentId: values.agentId,
|
|
158
|
+
...(values.acknowledge === undefined ? {} : { acknowledge: values.acknowledge }),
|
|
159
|
+
...(values.limit === undefined ? {} : { limit: values.limit }),
|
|
160
|
+
} as ValidatedMailboxParams;
|
|
146
161
|
}
|
|
147
162
|
|
|
148
163
|
function parameterRecord(params: unknown, toolName: string): Record<string, unknown> {
|
|
@@ -152,18 +167,15 @@ function parameterRecord(params: unknown, toolName: string): Record<string, unkn
|
|
|
152
167
|
return params as Record<string, unknown>;
|
|
153
168
|
}
|
|
154
169
|
|
|
155
|
-
function
|
|
170
|
+
function assertKnownKeys(
|
|
156
171
|
toolName: string,
|
|
157
|
-
action: string,
|
|
158
172
|
values: Record<string, unknown>,
|
|
159
173
|
allowed: readonly string[],
|
|
160
174
|
): void {
|
|
161
175
|
const unexpected = Object.keys(values).find(
|
|
162
176
|
(key) => values[key] !== undefined && !allowed.includes(key),
|
|
163
177
|
);
|
|
164
|
-
if (unexpected) {
|
|
165
|
-
throw new Error(`${toolName} action "${action}" does not accept ${unexpected}`);
|
|
166
|
-
}
|
|
178
|
+
if (unexpected) throw new Error(`${toolName} does not accept ${unexpected}`);
|
|
167
179
|
}
|
|
168
180
|
|
|
169
181
|
function assertRequiredString(
|