UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

239 lines (238 loc) • 11.2 kB
import { createHash } from "node:crypto"; import { GIT_SNAPSHOT_CC_PREAMBLE, buildGitSnapshot } from "../../prompts/default.js"; import { inlineUntrusted } from "../untrusted-text.js"; import { openSystemReminder } from "../reminder-mint.js"; import { engineRegionCovers, protectGitFrame } from "../context-guard.js"; import { gitFrameContextVisible } from "../../internal/harness.js"; import { thrownText } from "../thrown-value.js"; export const GIT_STATUS_FRAME_FORMAT_VERSION = 1; export const GIT_STATUS_FRAME_PREAMBLE = "This is the git status observed while preparing this request. When the visible snapshot changes it will be re-sent in a later message — the most recent git status frame supersedes earlier ones."; export const GIT_STATUS_UNAVAILABLE_BODY = "Git status is currently unavailable; the most recent git status frame above may be stale."; export const GIT_STATUS_NON_REPO_BODY = "The working directory is no longer a git repository; earlier git status frames no longer apply."; export const GIT_STATUS_ECHO_PREVIEW = { full: "git status updated", degraded: "git status updated (degraded: branch and dirtiness only)", unavailable: "git status unavailable", "non-repo": "git status: no longer a git repository", }; function toWellFormedText(s) { const native = s.toWellFormed; if (typeof native === "function") return native.call(s); return s.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "�"); } export function renderGitStatusFrameBody(outcome) { switch (outcome.kind) { case "full": { const body = outcome.snapshot.startsWith(GIT_SNAPSHOT_CC_PREAMBLE) ? GIT_STATUS_FRAME_PREAMBLE + outcome.snapshot.slice(GIT_SNAPSHOT_CC_PREAMBLE.length) : `${GIT_STATUS_FRAME_PREAMBLE}\n\n${outcome.snapshot}`; return toWellFormedText(body); } case "degraded": { const lines = [GIT_STATUS_FRAME_PREAMBLE]; lines.push(`Current branch: ${inlineUntrusted(outcome.branch ?? "HEAD")}`); if (outcome.dirty !== undefined) { lines.push(`Git working tree: ${outcome.dirty ? "has uncommitted changes" : "clean"}`); } return toWellFormedText(lines.join("\n\n")); } case "unavailable": return GIT_STATUS_UNAVAILABLE_BODY; case "non-repo": return GIT_STATUS_NON_REPO_BODY; } } export function hashGitStatusFrame(kind, body, canonicalRoot) { return `sha256:${createHash("sha256") .update(`${GIT_STATUS_FRAME_FORMAT_VERSION}\u0000${canonicalRoot}\u0000${kind}\u0000${body}`) .digest("hex")}`; } export function resolveGitStatusFrame(outcome, canonicalRoot, degradedMaterial) { const body = renderGitStatusFrameBody(outcome); const resolved = { kind: outcome.kind, body, hash: hashGitStatusFrame(outcome.kind, body, canonicalRoot), }; if (outcome.kind === "full") { const shrunkBody = renderGitStatusFrameBody({ kind: "degraded", ...(degradedMaterial ?? {}) }); resolved.shrunk = { body: shrunkBody, hash: hashGitStatusFrame("degraded", shrunkBody, canonicalRoot) }; } return resolved; } export async function probeGitStatusLane(args) { const { executionEnv, envFacts, handsEnabled, taskRoot, onDegrade } = args; const ref = {}; if (!handsEnabled) return ref; let outcome; if (envFacts.isGitRepo === true) { const SEP = "@@SEMA_ENV_GIT_SPLIT@@"; outcome = { kind: "degraded", ...(envFacts.gitBranch !== undefined ? { branch: envFacts.gitBranch } : {}), ...(envFacts.gitDirty !== undefined ? { dirty: envFacts.gitDirty } : {}), }; try { const snap = await executionEnv.exec(`(m=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null); m=\${m#origin/}; for s in "$m" main master; do if [ -n "$s" ] && git show-ref --verify --quiet "refs/remotes/origin/$s"; then echo "$s"; break; fi; done) || true; echo "${SEP}"; (git config user.name 2>/dev/null || true); echo "${SEP}"; gs=$(git --no-optional-locks status --short) || exit 41; printf '%s\\n' "$gs"; echo "${SEP}"; gl=$(git --no-optional-locks log --oneline -n 5) || exit 42; printf '%s\\n' "$gl"`, { cwd: envFacts.cwd, timeout: 10 }); if (snap.ok && snap.value.exitCode === 0) { const parts = snap.value.stdout.split(`${SEP}\n`); if (parts.length === 4) { outcome = { kind: "full", snapshot: buildGitSnapshot({ branch: envFacts.gitBranch ?? "HEAD", mainBranch: parts[0].trim() || "main", ...(parts[1].trim() ? { userName: parts[1].trim() } : {}), status: parts[2], log: parts[3], }), }; } else { onDegrade(`sentinel mis-split (${parts.length} sections, expected 4)`); } } else { onDegrade(snap.ok ? snap.value.exitCode === 41 ? "git status failed (exit 41)" : snap.value.exitCode === 42 ? "git log failed (exit 42)" : `git exited ${snap.value.exitCode}` : `exec failed: ${snap.error.message}`); } } catch (err) { onDegrade(thrownText(err)); } } else if (envFacts.isGitRepo === false) { outcome = { kind: "non-repo" }; } else { outcome = { kind: "unavailable" }; } const rootRaw = envFacts.gitWorktreeRoot ?? envFacts.cwd ?? taskRoot; let canonicalRoot = rootRaw; try { const c = await executionEnv.canonicalPath(rootRaw); if (c.ok) canonicalRoot = c.value; } catch { } ref.canonicalRoot = canonicalRoot; ref.frame = resolveGitStatusFrame(outcome, canonicalRoot, { ...(envFacts.gitBranch !== undefined ? { branch: envFacts.gitBranch } : {}), ...(envFacts.gitDirty !== undefined ? { dirty: envFacts.gitDirty } : {}), }); return ref; } export function applyGitFrameGuard(args) { const { before, trimmed, budgetTokens, ref, charsPerToken, onDegrade } = args; if (ref.protectedText === undefined) return trimmed; const guarded = protectGitFrame(before, trimmed, budgetTokens, { protectedText: ref.protectedText, ...(ref.frame?.kind === "full" && ref.frame.shrunk !== undefined && ref.wrappedShrink !== undefined ? { substitute: ref.wrappedShrink } : {}), }, charsPerToken); if (guarded.action === "over_budget") { ref.terminalCode = "irreducible_core_over_budget"; throw Object.assign(new Error("irreducible core over budget: the compaction summary plus the git status frame alone exceed the request budget — no trim can produce an honest request"), { code: "irreducible_core_over_budget" }); } if (guarded.action === "shrunk" && !ref.overBudgetShrunk) { ref.overBudgetShrunk = true; if (ref.announced !== undefined) ref.announced = { ...ref.announced, pending: true }; onDegrade("git status frame degraded under budget pressure: the full snapshot no longer fits the request budget — requests carry the branch+dirty residual; the degraded view will be re-announced"); } return guarded.messages; } export function newestEngineGitFrame(branch, mark) { const heads = [`${openSystemReminder(undefined)}\n${GIT_STATUS_FRAME_PREAMBLE}`, ...(mark !== undefined ? [`${openSystemReminder(mark)}\n${GIT_STATUS_FRAME_PREAMBLE}`] : [])]; const tombUnits = [GIT_STATUS_UNAVAILABLE_BODY, GIT_STATUS_NON_REPO_BODY].flatMap((body) => [ `${openSystemReminder(undefined)}\n${body}\n</system-reminder>`, ...(mark !== undefined ? [`${openSystemReminder(mark)}\n${body}\n</system-reminder>`] : []), ]); const topLevel = (text, at) => { if (at === 0) return true; const before = text.slice(0, at).replace(/\n+$/, ""); return before === "" || before.endsWith("</system-reminder>"); }; const allTopLevel = (text, needle, m) => { const out = []; for (let at = text.indexOf(needle); at !== -1; at = text.indexOf(needle, at + 1)) { if (topLevel(text, at) && engineRegionCovers(m, at, needle.length)) out.push(at); } return out; }; for (let i = branch.length - 1; i >= 0; i--) { const entry = branch[i]; if (entry === undefined || entry.type !== "message") continue; const m = entry.message; if (m.role !== "user") continue; const c = m.content; const text = typeof c === "string" ? c : Array.isArray(c) && c.length >= 1 && c[0].type === "text" ? (c[0].text ?? "") : undefined; if (text === undefined) continue; let best; for (const head of heads) { for (const at of allTopLevel(text, head, m)) { if (best === undefined || at > best.at) best = { at, positive: true }; } } for (const unit of tombUnits) { for (const at of allTopLevel(text, unit, m)) { if (best === undefined || at > best.at) best = { at, positive: false }; } } if (best !== undefined) return { entryId: entry.id, positive: best.positive }; } return undefined; } function hasNestedReminderOpenTag(seg) { const name = "<system-reminder"; for (let i = seg.indexOf(name); i !== -1; i = seg.indexOf(name, i + 1)) { const c = seg[i + name.length]; if (c === ">" || c === " ") return true; } return false; } export function stripGitStatusUnits(text, mark) { void mark; const close = "</system-reminder>"; const findHead = (out, from) => { for (let at = out.indexOf("<system-reminder", from); at !== -1; at = out.indexOf("<system-reminder", at + 1)) { const gt = out.indexOf(">", at); if (gt === -1) return undefined; if (out.startsWith(`\n${GIT_STATUS_FRAME_PREAMBLE}`, gt + 1)) return { at, bodyAt: gt + 1 }; } return undefined; }; let out = text; for (let hit = findHead(out, 0); hit !== undefined; hit = findHead(out, 0)) { const end = out.indexOf(close, hit.at); if (end === -1) break; if (hasNestedReminderOpenTag(out.slice(hit.bodyAt, end))) break; out = out.slice(0, hit.at) + out.slice(end + close.length); } return out; } export function branchCarriesVisiblePositiveGitFrame(branch, mark) { const newest = newestEngineGitFrame(branch, mark); return newest !== undefined && newest.positive && gitFrameContextVisible(branch, newest.entryId); }