/** * Child system prompt construction for subagents. * * Builds the system prompt that will be passed to the child pi process. * Includes the agent body and optional skill injection. */ import type { AgentDefinition } from "../types.ts"; import { escapeXml } from "../utils/format.ts"; import { resolveSkills, type ResolveSkillsResult } from "./skills.ts"; export interface BuildPromptOptions { agent: AgentDefinition; cwd: string; agentDir?: string; } export interface BuildPromptResult { prompt: string; skills: ResolveSkillsResult; } /** * Format resolved skills as an XML block for injection into the system prompt. */ function formatSkillsForPrompt( skills: Array<{ name: string; description: string; location: string }>, ): string { if (skills.length === 0) return ""; const lines = [ "\n\nThe following skills provide specialized instructions for specific tasks.", "Use the read tool to load a skill's file when the task matches its description.", "When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.", "", "", ]; for (const skill of skills) { lines.push(" "); lines.push(` ${escapeXml(skill.name)}`); lines.push(` ${escapeXml(skill.description)}`); lines.push(` ${escapeXml(skill.location)}`); lines.push(" "); } lines.push(""); return lines.join("\n"); } /** * Build the system prompt for a subagent. * * Starts with the agent body, appends skill injection if the agent has skills. */ export async function buildSubagentPrompt(options: BuildPromptOptions): Promise { let prompt = options.agent.prompt; let skillsResult: ResolveSkillsResult = { resolved: [], missing: [], skippedPackages: [], warnings: [], }; if (options.agent.skills && options.agent.skills.length > 0) { skillsResult = await resolveSkills(options.agent.skills, { cwd: options.cwd, agentDir: options.agentDir, }); const injection = formatSkillsForPrompt(skillsResult.resolved); if (injection) { prompt = `${prompt}${injection}`; } } return { prompt, skills: skillsResult }; }