5b35cd626b
Adds optional autoloadSkills field to agent frontmatter that automatically loads listed skills when a sub-agent is spawned. Uses the same buildSkillPromptMessage + sendCustomMessage mechanism as interactive skill loading, queued via sendCustomMessage({ triggerTurn: false }) before the first session.prompt(task). No extra agent turns, no new injection path. Skills stay in listing for sub-resource access. Compaction behavior matches manual loading. Unknown skill names silently skipped.
Lore-id: f85fdbdc
Constraint: autoload must use buildSkillPromptMessage + sendCustomMessage, never modify systemPrompt or use contextFiles
Constraint: triggerTurn must be false to avoid extra agent turns
Rejected: append to systemPrompt | agent cannot distinguish skill content from own instructions
Rejected: contextFiles injection | agent sees opaque file blob, cannot discover sub-resources
Rejected: promptCustomMessage per skill | N extra agent turns with model inference
Directive: autoload skill names are resolved against parent session skill list at spawn time in task/index.ts
Tested: TypeScript compiles clean with tsc --noEmit
Tested: parseAgentFields parses array and CSV string frontmatter
Tested: parseAgentFields returns undefined for absent and empty fields
Not-tested: bun test cannot run locally due to missing pi_natives native addon (requires Rust toolchain)
Confidence: high
Scope-risk: moderate
Reversibility: clean
113 lines
2.8 KiB
TypeScript
113 lines
2.8 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { Effort } from "@oh-my-pi/pi-ai";
|
|
import { parseAgentFields } from "../../src/discovery/helpers";
|
|
|
|
describe("parseAgentFields", () => {
|
|
test("parses blocking from boolean frontmatter", () => {
|
|
const fields = parseAgentFields({
|
|
name: "reviewer",
|
|
description: "desc",
|
|
blocking: true,
|
|
});
|
|
|
|
expect(fields).toBeDefined();
|
|
expect(fields?.blocking).toBe(true);
|
|
});
|
|
|
|
test("parses blocking from string frontmatter", () => {
|
|
const fields = parseAgentFields({
|
|
name: "reviewer",
|
|
description: "desc",
|
|
blocking: "false",
|
|
});
|
|
|
|
expect(fields).toBeDefined();
|
|
expect(fields?.blocking).toBe(false);
|
|
});
|
|
|
|
test("ignores invalid blocking values", () => {
|
|
const fields = parseAgentFields({
|
|
name: "reviewer",
|
|
description: "desc",
|
|
blocking: "sometimes",
|
|
});
|
|
|
|
expect(fields).toBeDefined();
|
|
expect(fields?.blocking).toBeUndefined();
|
|
});
|
|
test("parses legacy thinking key", () => {
|
|
const fields = parseAgentFields({
|
|
name: "reviewer",
|
|
description: "desc",
|
|
thinking: "medium",
|
|
});
|
|
|
|
expect(fields).toBeDefined();
|
|
expect(fields?.thinkingLevel).toBe(Effort.Medium);
|
|
});
|
|
|
|
test("prefers thinking-level over legacy thinking", () => {
|
|
const fields = parseAgentFields({
|
|
name: "reviewer",
|
|
description: "desc",
|
|
thinking: "minimal",
|
|
thinkingLevel: Effort.High,
|
|
});
|
|
|
|
expect(fields?.thinkingLevel).toBe(Effort.High);
|
|
});
|
|
|
|
test("lowercases tool names", () => {
|
|
const fields = parseAgentFields({
|
|
name: "reviewer",
|
|
description: "desc",
|
|
tools: ["Read", "Search"],
|
|
});
|
|
|
|
expect(fields?.tools).toEqual(["read", "search", "yield"]);
|
|
});
|
|
|
|
test("parses autoloadSkills from array frontmatter", () => {
|
|
const fields = parseAgentFields({
|
|
name: "oracle",
|
|
description: "desc",
|
|
autoloadSkills: ["user-created-skill-a", "user-created-skill-b"],
|
|
});
|
|
|
|
expect(fields).toBeDefined();
|
|
expect(fields?.autoloadSkills).toEqual(["user-created-skill-a", "user-created-skill-b"]);
|
|
});
|
|
|
|
test("parses autoloadSkills from CSV string", () => {
|
|
const fields = parseAgentFields({
|
|
name: "oracle",
|
|
description: "desc",
|
|
autoloadSkills: "user-created-skill-a, user-created-skill-b",
|
|
});
|
|
|
|
expect(fields).toBeDefined();
|
|
expect(fields?.autoloadSkills).toEqual(["user-created-skill-a", "user-created-skill-b"]);
|
|
});
|
|
|
|
test("returns undefined autoloadSkills when field absent", () => {
|
|
const fields = parseAgentFields({
|
|
name: "oracle",
|
|
description: "desc",
|
|
});
|
|
|
|
expect(fields).toBeDefined();
|
|
expect(fields?.autoloadSkills).toBeUndefined();
|
|
});
|
|
|
|
test("returns undefined autoloadSkills for empty array", () => {
|
|
const fields = parseAgentFields({
|
|
name: "oracle",
|
|
description: "desc",
|
|
autoloadSkills: [],
|
|
});
|
|
|
|
expect(fields).toBeDefined();
|
|
expect(fields?.autoloadSkills).toBeUndefined();
|
|
});
|
|
});
|