Squashed 'third_party/pi/' content from commit d981de122
git-subtree-dir: third_party/pi git-subtree-split: d981de1229ef899957bbe968bc8dcda02a21f477
This commit is contained in:
170
packages/coding-agent/test/system-prompt.test.ts
Normal file
170
packages/coding-agent/test/system-prompt.test.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import type { Skill } from "../src/core/skills.ts";
|
||||
import { createSyntheticSourceInfo } from "../src/core/source-info.ts";
|
||||
import { buildSystemPrompt } from "../src/core/system-prompt.ts";
|
||||
|
||||
const testSkill: Skill = {
|
||||
name: "test-skill",
|
||||
description: "A test skill.",
|
||||
filePath: "/skills/test-skill/SKILL.md",
|
||||
baseDir: "/skills/test-skill",
|
||||
sourceInfo: createSyntheticSourceInfo("/skills/test-skill/SKILL.md", { source: "test" }),
|
||||
disableModelInvocation: false,
|
||||
};
|
||||
|
||||
describe("buildSystemPrompt", () => {
|
||||
describe("empty tools", () => {
|
||||
test("shows (none) for empty tools list", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: [],
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
expect(prompt).toContain("Available tools:\n(none)");
|
||||
});
|
||||
|
||||
test("shows file paths guideline even with no tools", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: [],
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
expect(prompt).toContain("Show file paths clearly");
|
||||
});
|
||||
});
|
||||
|
||||
describe("default tools", () => {
|
||||
test("includes all default tools when snippets are provided", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
toolSnippets: {
|
||||
read: "Read file contents",
|
||||
bash: "Execute bash commands",
|
||||
edit: "Make surgical edits",
|
||||
write: "Create or overwrite files",
|
||||
},
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
expect(prompt).toContain("- read:");
|
||||
expect(prompt).toContain("- bash:");
|
||||
expect(prompt).toContain("- edit:");
|
||||
expect(prompt).toContain("- write:");
|
||||
});
|
||||
|
||||
test.each([
|
||||
[["powershell"], "Use PowerShell for file operations"],
|
||||
[["bash", "powershell"], "Use bash or PowerShell for file operations"],
|
||||
] as const)("uses shell-specific guidance for %j", (selectedTools, expected) => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: [...selectedTools],
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
expect(prompt).toContain(expected);
|
||||
});
|
||||
|
||||
test("instructs models to resolve pi docs and examples under absolute base paths", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
expect(prompt).toContain(
|
||||
"- When reading pi docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory",
|
||||
);
|
||||
expect(prompt).toContain("environment variables (docs/environment-variables.md)");
|
||||
});
|
||||
});
|
||||
|
||||
describe("custom tool snippets", () => {
|
||||
test("includes custom tools in available tools section when promptSnippet is provided", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: ["read", "dynamic_tool"],
|
||||
toolSnippets: {
|
||||
dynamic_tool: "Run dynamic test behavior",
|
||||
},
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
expect(prompt).toContain("- dynamic_tool: Run dynamic test behavior");
|
||||
});
|
||||
|
||||
test("omits custom tools from available tools section when promptSnippet is not provided", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: ["read", "dynamic_tool"],
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
expect(prompt).not.toContain("dynamic_tool");
|
||||
});
|
||||
});
|
||||
|
||||
describe("prompt guidelines", () => {
|
||||
test("appends promptGuidelines to default guidelines", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: ["read", "dynamic_tool"],
|
||||
promptGuidelines: ["Use dynamic_tool for project summaries."],
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
expect(prompt).toContain("- Use dynamic_tool for project summaries.");
|
||||
});
|
||||
|
||||
test("deduplicates and trims promptGuidelines", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: ["read", "dynamic_tool"],
|
||||
promptGuidelines: ["Use dynamic_tool for summaries.", " Use dynamic_tool for summaries. ", " "],
|
||||
contextFiles: [],
|
||||
skills: [],
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
expect(prompt.match(/- Use dynamic_tool for summaries\./g)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("skills", () => {
|
||||
test.each([
|
||||
{ name: "default prompt", customPrompt: undefined },
|
||||
{ name: "custom prompt", customPrompt: "Custom system prompt" },
|
||||
])("includes skills with only bash in the $name", ({ customPrompt }) => {
|
||||
const prompt = buildSystemPrompt({
|
||||
customPrompt,
|
||||
selectedTools: ["bash"],
|
||||
contextFiles: [],
|
||||
skills: [testSkill],
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
expect(prompt).toContain("<available_skills>");
|
||||
expect(prompt).toContain("<name>test-skill</name>");
|
||||
expect(prompt).toContain("Use bash to load a skill's file");
|
||||
});
|
||||
|
||||
test("omits skills without read or bash", () => {
|
||||
const prompt = buildSystemPrompt({
|
||||
selectedTools: ["write"],
|
||||
contextFiles: [],
|
||||
skills: [testSkill],
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
expect(prompt).not.toContain("<available_skills>");
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user