UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

88 lines (87 loc) • 3.07 kB
function joinParts(parts) { return parts.filter((p) => Boolean(p && p.trim())).join("\n\n"); } export function validatePack(pack) { const ids = new Set(); const ranks = new Set(); for (const s of pack.sections) { if (!s.id || !s.id.trim()) throw new Error(`prompt-pack ${pack.packId}: section with empty id`); if (ids.has(s.id)) throw new Error(`prompt-pack ${pack.packId}: duplicate section id "${s.id}"`); ids.add(s.id); if (ranks.has(s.rank)) throw new Error(`prompt-pack ${pack.packId}: duplicate rank ${s.rank} ("${s.id}")`); ranks.add(s.rank); if (s.blockJoiner !== undefined && s.blockJoiner !== "\n" && s.blockJoiner !== "\n\n") { throw new Error(`prompt-pack ${pack.packId}: section "${s.id}" has invalid blockJoiner`); } } } function renderSection(s, inputs) { if (s.admit && !s.admit(inputs)) return undefined; const text = s.content(inputs); if (!text || !text.trim()) return undefined; return { id: s.id, slot: s.slot, rank: s.rank, owner: s.owner, trust: s.trust, mutability: s.mutability, cadence: s.cadence, cacheClass: s.cacheClass, carrier: s.carrier, text, blockId: s.blockId, blockJoiner: s.blockJoiner ?? "\n\n", ...(s.declaredContentHash ? { declaredContentHash: s.declaredContentHash } : {}), ...(s.origin ? { origin: s.origin } : {}), }; } export function compose(pack, inputs) { validatePack(pack); const ordered = [...pack.sections].sort((a, b) => a.rank - b.rank); const sections = []; for (const s of ordered) { const compiled = renderSection(s, inputs); if (compiled) sections.push(compiled); } const text = joinParts(sections.map((s) => s.text)); const blocks = []; for (const s of sections) { const last = blocks[blocks.length - 1]; if (last && last.id === s.blockId) { last.text = `${last.text}${s.blockJoiner}${s.text}`; } else { blocks.push({ id: s.blockId, text: s.text }); } } return { text, sections, blocks }; } export const SINGLE_BLOCK_LAYOUT = { groups: [{ groupId: "body", untilRank: Number.POSITIVE_INFINITY, cacheControlBoundary: true }] }; export function layoutSystemBlocks(composed, layout = SINGLE_BLOCK_LAYOUT) { const blocks = []; let g = 0; let bucket = []; const flush = () => { if (bucket.length > 0) { const grp = layout.groups[Math.min(g, layout.groups.length - 1)]; blocks.push({ groupId: grp.groupId, text: bucket.join("\n\n"), cacheControlBoundary: grp.cacheControlBoundary }); bucket = []; } }; for (const s of composed.sections) { while (g < layout.groups.length - 1 && s.rank > layout.groups[g].untilRank) { flush(); g++; } bucket.push(s.text); } flush(); return blocks; }