UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

47 lines (46 loc) • 1.85 kB
const SKILL_ROOT_PLACEHOLDERS = /\$\{(?:SKILL_ROOT|CLAUDE_PLUGIN_ROOT)\}/g; export const SKILL_BASE_DIR_INVALID_CODE = "config.skill_base_dir_invalid"; export function skillBaseDirOf(value) { if (value === undefined) return undefined; if (typeof value === "string" && value !== "") return value; const e = new Error(`SkillSpec.baseDir must be a non-empty string naming its own directory (got ${value === "" ? '""' : typeof value}) — ` + `omit the key where no directory is stated; an empty one resolves the body's \${SKILL_ROOT} placeholders to nothing.`); e.code = SKILL_BASE_DIR_INVALID_CODE; throw e; } export function substituteSkillRoot(text, baseDir) { return text.replace(SKILL_ROOT_PLACEHOLDERS, () => baseDir); } export function substitutedSkillLength(text, baseDir) { const dir = skillBaseDirOf(baseDir); if (dir === undefined) return text.length; return substituteSkillRootBounded(text, dir, 0).totalChars; } export function skillLoadReading(skill, limit) { const delivered = substitutedSkillLength(skill.content, skill.baseDir); return { loads: delivered <= limit, delivered }; } export function substituteSkillRootBounded(text, baseDir, maxChars) { const parts = []; let totalChars = 0; let built = 0; const push = (piece) => { totalChars += piece.length; if (built >= maxChars) return; const kept = piece.length > maxChars - built ? piece.slice(0, maxChars - built) : piece; parts.push(kept); built += kept.length; }; let last = 0; for (const m of text.matchAll(SKILL_ROOT_PLACEHOLDERS)) { push(text.slice(last, m.index)); push(baseDir); last = m.index + m[0].length; } push(text.slice(last)); return { text: parts.join(""), totalChars }; }