UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

100 lines (99 loc) • 4.88 kB
import { isCentralAuthorityScope, parseScopeKey } from "./scope-contract.js"; import { CONTROL_PLANE_DIR } from "./layout.js"; import { join } from "node:path"; export function derivePersonalMemoryDir(configRoot) { return join(configRoot, "personal", "memory"); } export function derivePersonalControlDir(configRoot) { return join(configRoot, "personal", CONTROL_PLANE_DIR); } export function classifyScopePlanes(scopes, writeScope) { const project = []; const personal = []; for (const s of scopes) { (isCentralAuthorityScope(parseScopeKey(s)) ? personal : project).push(s); } const writePlane = writeScope === null ? null : isCentralAuthorityScope(parseScopeKey(writeScope)) ? "personal" : "project"; return { project, personal, writePlane }; } export function needsDualRoots(planes) { const projectActive = planes.project.length > 0 || planes.writePlane === "project"; const personalActive = planes.personal.length > 0 || planes.writePlane === "personal"; return projectActive && personalActive; } export function parsedProjectPlane(planes, writeScope) { const keys = [...planes.project, ...(planes.writePlane === "project" && writeScope !== null ? [writeScope] : [])]; return keys.map(parseScopeKey); } export function mergeInjections(project, personal) { if (!project) return personal ?? { instruction: "", block: "" }; if (!personal) return project; const instruction = project.instruction || personal.instruction; const readOnlyNotice = instruction === "" && project.readOnlyNotice !== undefined && personal.readOnlyNotice !== undefined ? project.readOnlyNotice : undefined; const indexParts = [project.index, personal.index].filter((s) => Boolean(s && s.trim())); const announcements = [...(project.announcements ?? []), ...(personal.announcements ?? [])]; const announceParts = [project.announceBlock, personal.announceBlock].filter((s) => Boolean(s && s.trim())); const blockParts = [instruction || readOnlyNotice, ...indexParts, ...announceParts]; const indexSeed = project.indexSeed ?? personal.indexSeed; return { instruction, ...(readOnlyNotice !== undefined ? { readOnlyNotice } : {}), ...(indexParts.length > 0 ? { index: indexParts.join("\n\n") } : {}), ...(announcements.length > 0 ? { announcements } : {}), ...(announceParts.length > 0 ? { announceBlock: announceParts.join("\n\n") } : {}), ...(indexSeed !== undefined ? { indexSeed } : {}), block: blockParts.filter((s) => s && s.trim()).join("\n\n"), }; } export function mergeHarvestReports(a, b) { const merged = { ok: a.ok && b.ok, patches: { add: a.patches.add + b.patches.add, update: a.patches.update + b.patches.update, delete: a.patches.delete + b.patches.delete, }, conflicts: [...a.conflicts, ...b.conflicts], rejections: [...a.rejections, ...b.rejections], quarantined: [...a.quarantined, ...b.quarantined], movedToQuarantine: [...a.movedToQuarantine, ...b.movedToQuarantine], missing: [...a.missing, ...b.missing], restored: [...a.restored, ...b.restored], warnings: [...a.warnings, ...b.warnings], }; const reportId = a.reportId ?? b.reportId; if (reportId !== undefined) merged.reportId = reportId; const parts = [...new Set([a.reportId, b.reportId].filter((x) => x !== undefined))]; if (parts.length > 1) merged.mergedFrom = parts; const incident = a.incident ?? b.incident; if (incident !== undefined) merged.incident = incident; const degraded = a.degraded ?? b.degraded; if (degraded !== undefined) merged.degraded = degraded; const inbound = [...(a.inboundFindings ?? []), ...(b.inboundFindings ?? [])]; if (inbound.length > 0) merged.inboundFindings = inbound; const qf = [...(a.quarantineFailures ?? []), ...(b.quarantineFailures ?? [])]; if (qf.length > 0) merged.quarantineFailures = qf; const rec = a.consolidationRecommended ?? b.consolidationRecommended; if (rec !== undefined) merged.consolidationRecommended = rec; const ac = a.containment; const bc = b.containment; if (ac !== undefined || bc !== undefined) { merged.containment = { indexRolledBack: ac?.indexRolledBack === true || bc?.indexRolledBack === true, quarantinedInstruction: [...(ac?.quarantinedInstruction ?? []), ...(bc?.quarantinedInstruction ?? [])], heldInstruction: [...(ac?.heldInstruction ?? []), ...(bc?.heldInstruction ?? [])], releasedHolds: [...(ac?.releasedHolds ?? []), ...(bc?.releasedHolds ?? [])], disposedHolds: [...(ac?.disposedHolds ?? []), ...(bc?.disposedHolds ?? [])], }; } return merged; }