@youngjurry/pi-agents 0.7.3 → 0.7.5
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 +12 -0
- package/README.md +2 -2
- package/control.ts +11 -9
- package/package.json +1 -1
- package/roles.ts +8 -9
- package/tools.ts +2 -2
- package/types.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.5 - 2026-09-05
|
|
4
|
+
|
|
5
|
+
- Exclude the active `wait_agent` caller from its folded child-status summary.
|
|
6
|
+
- Prevent the root Agent's necessarily `running` tool turn from appearing as a phantom running sub-agent.
|
|
7
|
+
- Scope nested waits to the caller's own subtree while preserving `Ctrl+O` expansion.
|
|
8
|
+
|
|
9
|
+
## 0.7.4 - 2026-09-05
|
|
10
|
+
|
|
11
|
+
- Match Pi's progressive Skill disclosure for sub-agent Roles instead of eagerly injecting complete `SKILL.md` files.
|
|
12
|
+
- Let an omitted `skills` field inherit all discoverable Skills, an explicit list expose only those Skills, and `skills: []` expose none.
|
|
13
|
+
- Preserve explicit unknown-Skill validation and report inherited Role skills as `*` through on-demand Role discovery.
|
|
14
|
+
|
|
3
15
|
## 0.7.3 - 2026-09-05
|
|
4
16
|
|
|
5
17
|
- Fold the full `wait_agent` status tree by default and reuse Pi's `Ctrl+O` expansion state to reveal it on demand.
|
package/README.md
CHANGED
|
@@ -134,7 +134,7 @@ nickname_candidates: [Ada, Grace]
|
|
|
134
134
|
Review carefully and return findings with exact paths.
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
-
`skills`
|
|
137
|
+
`skills` optionally filters Pi's normal progressive Skill disclosure. Omit the field to inherit all discoverable Skills, specify names such as `skills: [document]` to expose only those Skill names/descriptions/paths, or use `skills: []` to expose none. The child still reads a matching `SKILL.md` on demand rather than placing complete Skill instructions in every prompt. As in Pi's main Agent, the catalog is shown only when `read` or `bash` is active. Unknown explicitly selected Skill names fail clearly instead of being silently ignored.
|
|
138
138
|
|
|
139
139
|
## Model configuration
|
|
140
140
|
|
|
@@ -180,7 +180,7 @@ The settings file is optional, but spawning requires a model from either the tas
|
|
|
180
180
|
- Referenced legacy flat child files are migrated when their main session is resumed
|
|
181
181
|
- Parents receive a compact completion notice instead of the full answer; use `list_agents(view="results")` or read the result file on demand
|
|
182
182
|
- Notices to a busy agent are queued safely: `wait_agent` returns them in its own result, and any leftovers are delivered right after a successful recipient turn
|
|
183
|
-
- `wait_agent` sends only newly queued mailbox notices to the model; its
|
|
183
|
+
- `wait_agent` sends only newly queued mailbox notices to the model; its child status tree excludes the active caller, is folded in the TUI by default, and can be toggled with `Ctrl+O`
|
|
184
184
|
- Failed notice delivery is re-queued instead of silently discarded
|
|
185
185
|
- Notices pending when a turn is aborted or errors are deferred to the next explicit turn without restarting the interrupted agent
|
|
186
186
|
- The extension never inserts messages between an assistant tool call and its tool result, keeping session history protocol-valid for strict gateways
|
package/control.ts
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
rootAgentInstructions,
|
|
24
24
|
sanitizeForkMessages,
|
|
25
25
|
} from "./context.ts";
|
|
26
|
-
import { discoverRoles,
|
|
26
|
+
import { discoverRoles, resolveRole, selectRoleSkills } from "./roles.ts";
|
|
27
27
|
import {
|
|
28
28
|
DEFAULT_CHILD_THINKING_LEVEL,
|
|
29
29
|
DEFAULT_MAX_CONCURRENT_SUBAGENTS,
|
|
@@ -594,8 +594,7 @@ export class AgentControl {
|
|
|
594
594
|
assignedSkillNames?: readonly string[],
|
|
595
595
|
): Promise<DefaultResourceLoader> {
|
|
596
596
|
const selfPath = path.resolve(this.selfExtensionPath);
|
|
597
|
-
|
|
598
|
-
loader = new DefaultResourceLoader({
|
|
597
|
+
const loader = new DefaultResourceLoader({
|
|
599
598
|
cwd,
|
|
600
599
|
agentDir: getAgentDir(),
|
|
601
600
|
settingsManager,
|
|
@@ -603,11 +602,14 @@ export class AgentControl {
|
|
|
603
602
|
...base,
|
|
604
603
|
extensions: base.extensions.filter((extension) => path.resolve(extension.resolvedPath) !== selfPath),
|
|
605
604
|
}),
|
|
606
|
-
|
|
607
|
-
base
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
605
|
+
...(assignedSkillNames === undefined ? {} : {
|
|
606
|
+
skillsOverride: (base: ReturnType<DefaultResourceLoader["getSkills"]>) => ({
|
|
607
|
+
...base,
|
|
608
|
+
skills: selectRoleSkills(assignedSkillNames, base.skills),
|
|
609
|
+
}),
|
|
610
|
+
}),
|
|
611
|
+
systemPromptOverride: (base) => [base || "You are a coding agent.", instructions]
|
|
612
|
+
.filter((part) => part.trim()).join("\n\n"),
|
|
611
613
|
});
|
|
612
614
|
await loader.reload();
|
|
613
615
|
this.captureTranscriptToolDefinitions(loader);
|
|
@@ -1151,7 +1153,7 @@ export class AgentControl {
|
|
|
1151
1153
|
model: role.model || settings.defaultModel,
|
|
1152
1154
|
thinkingLevel: role.thinkingLevel ?? settings.defaultThinkingLevel ?? DEFAULT_CHILD_THINKING_LEVEL,
|
|
1153
1155
|
tools: role.tools,
|
|
1154
|
-
skills: role.skills,
|
|
1156
|
+
skills: role.skills ?? ["*"],
|
|
1155
1157
|
source: role.source,
|
|
1156
1158
|
}));
|
|
1157
1159
|
}
|
package/package.json
CHANGED
package/roles.ts
CHANGED
|
@@ -45,6 +45,11 @@ function stringList(value: unknown): string[] | undefined {
|
|
|
45
45
|
return result.length > 0 ? result : undefined;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
function optionalStringList(value: unknown): string[] | undefined {
|
|
49
|
+
if (value === undefined) return undefined;
|
|
50
|
+
return stringList(value) ?? [];
|
|
51
|
+
}
|
|
52
|
+
|
|
48
53
|
function loadDirectory(directory: string, source: "user" | "project"): AgentRole[] {
|
|
49
54
|
if (!fs.existsSync(directory)) return [];
|
|
50
55
|
let entries: fs.Dirent[];
|
|
@@ -68,7 +73,7 @@ function loadDirectory(directory: string, source: "user" | "project"): AgentRole
|
|
|
68
73
|
description: frontmatter.description.trim(),
|
|
69
74
|
systemPrompt: body.trim(),
|
|
70
75
|
tools: stringList(frontmatter.tools),
|
|
71
|
-
skills:
|
|
76
|
+
skills: optionalStringList(frontmatter.skills),
|
|
72
77
|
model: typeof frontmatter.model === "string" ? frontmatter.model.trim() : undefined,
|
|
73
78
|
thinkingLevel: thinking,
|
|
74
79
|
nicknameCandidates: stringList(frontmatter.nickname_candidates),
|
|
@@ -117,18 +122,12 @@ export function resolveRole(cwd: string, projectTrusted: boolean, name?: string)
|
|
|
117
122
|
return role;
|
|
118
123
|
}
|
|
119
124
|
|
|
120
|
-
export function
|
|
121
|
-
if (!requestedNames?.length) return "";
|
|
125
|
+
export function selectRoleSkills(requestedNames: readonly string[], discoveredSkills: readonly Skill[]): Skill[] {
|
|
122
126
|
const skillsByName = new Map(discoveredSkills.map((skill) => [skill.name, skill]));
|
|
123
127
|
const missing = requestedNames.filter((name) => !skillsByName.has(name));
|
|
124
128
|
if (missing.length > 0) {
|
|
125
129
|
const available = [...skillsByName.keys()].sort().join(", ") || "none";
|
|
126
130
|
throw new Error(`Role references unknown skill(s): ${missing.join(", ")}. Available skills: ${available}`);
|
|
127
131
|
}
|
|
128
|
-
|
|
129
|
-
const skill = skillsByName.get(name)!;
|
|
130
|
-
const instructions = fs.readFileSync(skill.filePath, "utf8").trim();
|
|
131
|
-
return `<skill>\nName: ${skill.name}\nLocation: ${skill.filePath}\nBase directory: ${skill.baseDir}\n\n${instructions}\n</skill>`;
|
|
132
|
-
});
|
|
133
|
-
return `<agent_skills>\nThe following Role-selected skills are fully loaded. Follow them when completing the task. Resolve relative paths against each skill's base directory.\n\n${sections.join("\n\n")}\n</agent_skills>`;
|
|
132
|
+
return [...new Set(requestedNames)].map((name) => skillsByName.get(name)!);
|
|
134
133
|
}
|
package/tools.ts
CHANGED
|
@@ -88,7 +88,7 @@ function renderCollaborationResult(
|
|
|
88
88
|
role.model ? `model: ${role.model}` : undefined,
|
|
89
89
|
role.thinkingLevel ? `thinking: ${role.thinkingLevel}` : undefined,
|
|
90
90
|
`tools: ${role.tools?.join(", ") || "default set"}`,
|
|
91
|
-
role.skills
|
|
91
|
+
`skills: ${role.skills.length > 0 ? role.skills.join(", ") : "none"}`,
|
|
92
92
|
].filter(Boolean).join(" · ");
|
|
93
93
|
lines.push(` ${theme.fg("accent", role.name)} — ${role.description}`);
|
|
94
94
|
lines.push(` ${theme.fg("dim", configuration)}`);
|
|
@@ -200,7 +200,7 @@ export function createCollaborationTools(control: AgentControl): ToolDefinition[
|
|
|
200
200
|
const outcome = await control.waitForMailbox(ctx, params.timeout_ms, signal);
|
|
201
201
|
if (outcome.aborted) throw new Error("wait_agent was aborted");
|
|
202
202
|
const notices = control.drainPendingMail(sender);
|
|
203
|
-
const agents = control.list(ctx);
|
|
203
|
+
const agents = control.list(ctx, sender).filter((agent) => agent.path !== sender);
|
|
204
204
|
const text = notices.length > 0
|
|
205
205
|
? `Mailbox activity received:\n\n${notices.join("\n\n")}`
|
|
206
206
|
: outcome.timedOut
|