@gotgenes/pi-subagents 7.8.0 → 8.0.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 +35 -0
- package/README.md +10 -13
- package/docs/architecture/architecture.md +179 -133
- package/docs/architecture/history/phase-13-remaining-smells.md +88 -0
- package/docs/plans/0219-reduce-test-duplication-top-3-clone-families.md +162 -0
- package/docs/plans/0237-remove-disallowed-tools.md +180 -0
- package/docs/retro/0218-push-sdk-boundary-in-settings.md +37 -0
- package/docs/retro/0219-reduce-test-duplication-top-3-clone-families.md +64 -0
- package/docs/retro/0237-remove-disallowed-tools.md +41 -0
- package/package.json +1 -1
- package/src/config/custom-agents.ts +0 -9
- package/src/lifecycle/agent-runner.ts +7 -11
- package/src/session/session-config.ts +3 -10
- package/src/types.ts +0 -2
- package/src/ui/agent-config-editor.ts +0 -2
- package/src/ui/agent-creation-wizard.ts +0 -1
|
@@ -22,7 +22,7 @@ import type { ShellExec, SubagentType, ThinkingLevel } from "#src/types";
|
|
|
22
22
|
const EXCLUDED_TOOL_NAMES = ["Agent", "get_subagent_result", "steer_subagent"];
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Filter the session's active tool names according to extension
|
|
25
|
+
* Filter the session's active tool names according to extension rules.
|
|
26
26
|
*
|
|
27
27
|
* Run twice - once before `bindExtensions` (filters built-in tools) and once after
|
|
28
28
|
* (filters extension-registered tools, which only join the active set during
|
|
@@ -36,16 +36,13 @@ function filterActiveTools(
|
|
|
36
36
|
activeTools: string[],
|
|
37
37
|
config: ToolFilterConfig,
|
|
38
38
|
): string[] {
|
|
39
|
-
const { toolNames, extensions
|
|
39
|
+
const { toolNames, extensions } = config;
|
|
40
40
|
if (extensions === false) {
|
|
41
|
-
|
|
42
|
-
if (!disallowedSet) return activeTools;
|
|
43
|
-
return activeTools.filter((t) => !disallowedSet.has(t));
|
|
41
|
+
return activeTools;
|
|
44
42
|
}
|
|
45
43
|
const builtinToolNameSet = new Set(toolNames);
|
|
46
44
|
return activeTools.filter((t) => {
|
|
47
45
|
if (EXCLUDED_TOOL_NAMES.includes(t)) return false;
|
|
48
|
-
if (disallowedSet?.has(t)) return false;
|
|
49
46
|
if (builtinToolNameSet.has(t)) return true;
|
|
50
47
|
if (Array.isArray(extensions)) {
|
|
51
48
|
return extensions.some((ext) => t.startsWith(ext) || t.includes(ext));
|
|
@@ -341,9 +338,9 @@ export async function runAgent(
|
|
|
341
338
|
});
|
|
342
339
|
|
|
343
340
|
// Filter active tools: remove our own tools to prevent nesting,
|
|
344
|
-
// apply extension allowlist if specified
|
|
341
|
+
// apply extension allowlist if specified.
|
|
345
342
|
// First pass - over built-in tools, before bindExtensions registers extension tools.
|
|
346
|
-
if (cfg.toolFilter.extensions !== false
|
|
343
|
+
if (cfg.toolFilter.extensions !== false) {
|
|
347
344
|
const filtered = filterActiveTools(session.getActiveToolNames(), cfg.toolFilter);
|
|
348
345
|
session.setActiveToolsByName(filtered);
|
|
349
346
|
}
|
|
@@ -367,9 +364,8 @@ export async function runAgent(
|
|
|
367
364
|
// Extension-registered tools (added during bindExtensions) are not in the
|
|
368
365
|
// session's active set when the first filter pass runs above. Without this
|
|
369
366
|
// re-filter, the `extensions: string[]` allowlist branch never matches any
|
|
370
|
-
// extension tools
|
|
371
|
-
|
|
372
|
-
if (cfg.toolFilter.extensions !== false || cfg.toolFilter.disallowedSet) {
|
|
367
|
+
// extension tools. Run the same filter against the post-bind active set.
|
|
368
|
+
if (cfg.toolFilter.extensions !== false) {
|
|
373
369
|
const refiltered = filterActiveTools(session.getActiveToolNames(), cfg.toolFilter);
|
|
374
370
|
session.setActiveToolsByName(refiltered);
|
|
375
371
|
}
|
|
@@ -21,14 +21,12 @@ import type { AgentPromptConfig, SubagentType, ThinkingLevel } from "#src/types"
|
|
|
21
21
|
/**
|
|
22
22
|
* Tool filtering configuration — consumed by `filterActiveTools` in `agent-runner.ts`.
|
|
23
23
|
*
|
|
24
|
-
* Groups the
|
|
25
|
-
* the built-in tool allowlist
|
|
24
|
+
* Groups the two fields that travel together through the assembly→runner boundary:
|
|
25
|
+
* the built-in tool allowlist and the extensions setting.
|
|
26
26
|
*/
|
|
27
27
|
export interface ToolFilterConfig {
|
|
28
28
|
/** Built-in tool name allowlist for this agent type. */
|
|
29
29
|
toolNames: string[];
|
|
30
|
-
/** Disallowed tool set from agentConfig. undefined when empty. */
|
|
31
|
-
disallowedSet: Set<string> | undefined;
|
|
32
30
|
/** Resolved extensions setting: false | true | string[] allowlist. */
|
|
33
31
|
extensions: boolean | string[];
|
|
34
32
|
}
|
|
@@ -210,11 +208,6 @@ export function assembleSessionConfig(
|
|
|
210
208
|
// tell the resource loader not to load them again.
|
|
211
209
|
const noSkills = skills === false || Array.isArray(skills);
|
|
212
210
|
|
|
213
|
-
// Disallowed tools set (for filterActiveTools in runAgent)
|
|
214
|
-
const disallowedSet = agentConfig.disallowedTools
|
|
215
|
-
? new Set(agentConfig.disallowedTools)
|
|
216
|
-
: undefined;
|
|
217
|
-
|
|
218
211
|
// Model resolution: explicit option > config model string > parent model
|
|
219
212
|
const model =
|
|
220
213
|
options.model ??
|
|
@@ -229,7 +222,7 @@ export function assembleSessionConfig(
|
|
|
229
222
|
return {
|
|
230
223
|
effectiveCwd,
|
|
231
224
|
systemPrompt,
|
|
232
|
-
toolFilter: { toolNames,
|
|
225
|
+
toolFilter: { toolNames, extensions },
|
|
233
226
|
model,
|
|
234
227
|
thinkingLevel,
|
|
235
228
|
noSkills,
|
package/src/types.ts
CHANGED
|
@@ -42,8 +42,6 @@ export interface AgentPromptConfig {
|
|
|
42
42
|
/** Unified agent configuration — used for both default and user-defined agents. */
|
|
43
43
|
export interface AgentConfig extends AgentIdentity, AgentPromptConfig {
|
|
44
44
|
builtinToolNames?: string[];
|
|
45
|
-
/** Tool denylist — these tools are removed even if `builtinToolNames` or extensions include them. */
|
|
46
|
-
disallowedTools?: string[];
|
|
47
45
|
/** true = inherit all, string[] = only listed, false = none */
|
|
48
46
|
extensions: true | string[] | false;
|
|
49
47
|
/** true = inherit all, string[] = only listed, false = none */
|
|
@@ -53,8 +53,6 @@ export function buildEjectContent(cfg: AgentConfig): string {
|
|
|
53
53
|
if (cfg.skills === false) fmFields.push("skills: false");
|
|
54
54
|
else if (Array.isArray(cfg.skills))
|
|
55
55
|
fmFields.push(`skills: ${cfg.skills.join(", ")}`);
|
|
56
|
-
if (cfg.disallowedTools?.length)
|
|
57
|
-
fmFields.push(`disallowed_tools: ${cfg.disallowedTools.join(", ")}`);
|
|
58
56
|
if (cfg.inheritContext) fmFields.push("inherit_context: true");
|
|
59
57
|
if (cfg.runInBackground) fmFields.push("run_in_background: true");
|
|
60
58
|
if (cfg.isolated) fmFields.push("isolated: true");
|
|
@@ -106,7 +106,6 @@ max_turns: <optional max agentic turns. 0 or omit for unlimited (default)>
|
|
|
106
106
|
prompt_mode: <"replace" (body IS the full system prompt) or "append" (body is appended to default prompt). Default: replace>
|
|
107
107
|
extensions: <true (inherit all MCP/extension tools), false (none), or comma-separated names. Default: true>
|
|
108
108
|
skills: <true (inherit all), false (none), or comma-separated skill names to preload into prompt. Default: true>
|
|
109
|
-
disallowed_tools: <comma-separated tool names to block, even if otherwise available. Omit for none>
|
|
110
109
|
inherit_context: <true to fork parent conversation into agent so it sees chat history. Default: false>
|
|
111
110
|
run_in_background: <true to run in background by default. Default: false>
|
|
112
111
|
isolated: <true for no extension/MCP tools, only built-in tools. Default: false>
|