refactor: reuse shared skills prompt formatter

This commit is contained in:
Shakker
2026-05-29 18:11:36 +01:00
committed by Shakker
parent f382a36458
commit 2009bec87a
+2 -33
View File
@@ -7,6 +7,7 @@ import type { ResourceDiagnostic } from "../../agents/sessions/diagnostics.js";
import { createSyntheticSourceInfo, type SourceInfo } from "../../agents/sessions/source-info.js";
import { parseFrontmatter } from "../../agents/utils/frontmatter.js";
import { canonicalizePath } from "../../agents/utils/paths.js";
import { formatSkillsForPrompt as formatSkillContractForPrompt } from "./skill-contract.js";
/** Max name length per spec */
const MAX_NAME_LENGTH = 64;
@@ -343,39 +344,7 @@ function loadSkillFromFile(
*/
export function formatSkillsForPrompt(skills: Skill[]): string {
const visibleSkills = skills.filter((s) => !s.disableModelInvocation);
if (visibleSkills.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.",
"",
"<available_skills>",
];
for (const skill of visibleSkills) {
lines.push(" <skill>");
lines.push(` <name>${escapeXml(skill.name)}</name>`);
lines.push(` <description>${escapeXml(skill.description)}</description>`);
lines.push(` <location>${escapeXml(skill.filePath)}</location>`);
lines.push(" </skill>");
}
lines.push("</available_skills>");
return lines.join("\n");
}
function escapeXml(str: string): string {
return str
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&apos;");
return formatSkillContractForPrompt(visibleSkills);
}
export interface LoadSkillsOptions {