@sema-agent/core
Version:
Stateless, task-oriented AI agent core
320 lines (319 loc) • 13.8 kB
JavaScript
import { createHash } from "node:crypto";
import { DEFAULT_CHARS_PER_TOKEN, estimateTokens } from "../internal/harness.js";
import { isToolResult } from "./message-utils.js";
import { physicalWindowOf } from "./context-settings.js";
import { PERSISTED_OUTPUT_PREFIX, offloadPagebackHint } from "./tool-result-store.js";
import { assertNoRetiredKeys } from "./retired-keys.js";
import { compactableToolNames } from "./tool-registry.js";
import { wireOf } from "./tool-name-readings.js";
const CC_CLEARED_MARKER = "[Old tool result content cleared]";
const CC_CLEARED_EXTENDED_PREFIX = "[Old tool result content cleared —";
const refNote = (ref) => offloadPagebackHint(ref, "cleared");
const mediaNote = (blocks) => {
const byType = new Map();
for (const b of blocks) {
const t = b.type ?? "untyped";
byType.set(t, (byType.get(t) ?? 0) + 1);
}
const n = blocks.length;
if (byType.size === 1) {
const [t, c] = [...byType][0];
return `${c} ${t} attachment${c === 1 ? "" : "s"} no longer visible after this clear`;
}
const breakdown = [...byType].map(([t, c]) => `${c} ${t}`).join(", ");
return `${n} attachments (${breakdown}) no longer visible after this clear`;
};
const clearedMarker = (notes) => {
const present = notes.filter((n) => n !== undefined);
return present.length > 0 ? `${CC_CLEARED_EXTENDED_PREFIX} ${present.join("; ")}]` : CC_CLEARED_MARKER;
};
export const EDIT_FRACTION = 0.7;
export const CONTEXT_OUTPUT_RESERVE_TOKENS = 20000;
export const COMPACTION_TRIGGER_BUFFER_TOKENS = 13000;
export function contextEditFrontier(window) {
return Math.max(window - (CONTEXT_OUTPUT_RESERVE_TOKENS + COMPACTION_TRIGGER_BUFFER_TOKENS), Math.floor(window * EDIT_FRACTION));
}
export const MICRO_COMPACT_MACHINES = Object.freeze(["off", "cc"]);
export const CC_DEFAULT_KEEP_RECENT_TOOL_RESULTS = 5;
export const MIN_CLEAR_SAVINGS_TOKENS = 20000;
const MEDIA_BLOCK_SAVINGS_TOKENS = 2000;
export const MIN_KEEP_RECENT_TOOL_RESULTS = 1;
function resolveKeepRecentToolResults(value, defaultValue) {
if (value === undefined)
return defaultValue;
if (!Number.isSafeInteger(value) || value < 0) {
throw new TypeError(`keepRecentToolResults must be a non-negative safe integer (got ${String(value)}); ` +
`omit it for the default ${defaultValue}`);
}
return Math.max(MIN_KEEP_RECENT_TOOL_RESULTS, value);
}
const COMPACTABLE_TOOLS = compactableToolNames();
const compactableResult = (compactable, recorded, toolNameOf) => compactable.has(wireOf("compaction.compactableResult", { toolName: toolNameOf !== undefined ? toolNameOf(recorded) : recorded }));
function soleMarkerText(m) {
const content = m.content;
if (!Array.isArray(content) || content.length !== 1)
return undefined;
const text = content[0].text;
return typeof text === "string" ? text : undefined;
}
function isCleared(m) {
const text = soleMarkerText(m);
if (text !== undefined && (text === CC_CLEARED_MARKER || text.startsWith(CC_CLEARED_EXTENDED_PREFIX)))
return true;
const content = m.content;
if (!Array.isArray(content) || content.length === 0)
return false;
const first = content[0];
return first?.type === "text" && typeof first.text === "string" && first.text.startsWith(PERSISTED_OUTPUT_PREFIX);
}
export function dropEmptyFailureAssistants(messages) {
const isJunk = (m) => {
if (m.role !== "assistant")
return false;
const a = m;
if (a.stopReason !== "aborted" && a.stopReason !== "error")
return false;
return a.content.every((c) => c.type === "text" ? (c.text ?? "").trim() === "" : c.type === "thinking" ? (c.thinking ?? "").trim() === "" : false);
};
return messages.some(isJunk) ? messages.filter((m) => !isJunk(m)) : messages;
}
function structuralClearSavings(target) {
const content = Array.isArray(target.content) ? target.content : [];
let saved = 0;
for (const c of content) {
const block = c;
if (block?.type === "text") {
saved += typeof block.text === "string" ? Math.round(block.text.length / 4) : 0;
}
else {
saved += MEDIA_BLOCK_SAVINGS_TOKENS;
}
}
return saved;
}
function clearOneResult(target, offload) {
const rawContent = Array.isArray(target.content) ? target.content : [];
let ref;
if (offload) {
const fullText = rawContent
.filter((c) => c?.type === "text" && typeof c.text === "string")
.map((c) => c.text)
.join("\n");
if (target.toolCallId && fullText.trim().length > 0) {
try {
ref = refNote(offload.persist(target.toolCallId, fullText));
}
catch {
ref = undefined;
}
}
}
const mediaBlocks = rawContent.filter((c) => c?.type !== "text");
const marker = clearedMarker([ref, mediaBlocks.length > 0 ? mediaNote(mediaBlocks) : undefined]);
return { ...target, content: [{ type: "text", text: marker }] };
}
function reportCleared(onCleared, clears, tokensSavedEstimate) {
if (!onCleared || clears.length === 0)
return;
try {
onCleared({ clears, tokensSavedEstimate });
}
catch {
}
}
const CONTEXT_EDIT_OPTION_KEYS = new Set([
"budgetTokens",
"onCleared",
"keepRecentToolResults",
"offload",
"anchoredTotalTokens",
"charsPerToken",
"compactableTools",
"toolNameOf",
"clearSource",
]);
const RETIRED_CONTEXT_EDIT_OPTION_KEYS = {
machine: 'the pass runs one machine (the CC form); the frontier on/off switch is `RunnerDeps.microCompact.machine: "off" | "cc"`',
recognizeCcMarkers: "the cleared-marker forms are always recognized",
};
export function clearStaleToolResults(messages, opts) {
assertNoRetiredKeys(opts, RETIRED_CONTEXT_EDIT_OPTION_KEYS, "clearStaleToolResults option");
for (const key of Object.keys(opts)) {
if (CONTEXT_EDIT_OPTION_KEYS.has(key) || Reflect.get(opts, key) === undefined)
continue;
const replacement = RETIRED_CONTEXT_EDIT_OPTION_KEYS[key];
throw new TypeError(`clearStaleToolResults: option "${key}" is not one this pass reads` +
(replacement !== undefined ? ` — it is retired: ${replacement}` : "") +
`. Legal keys: ${[...CONTEXT_EDIT_OPTION_KEYS].join(", ")}. Refused rather than ignored: a silently dropped option reads to the caller as in force.`);
}
const cpt = opts.charsPerToken ?? DEFAULT_CHARS_PER_TOKEN;
let total;
if (opts.anchoredTotalTokens !== undefined) {
total = opts.anchoredTotalTokens;
}
else {
total = 0;
for (const m of messages) {
total += estimateTokens(m, cpt);
}
}
if (total <= opts.budgetTokens) {
return messages;
}
const keep = resolveKeepRecentToolResults(opts.keepRecentToolResults, CC_DEFAULT_KEEP_RECENT_TOOL_RESULTS);
const compactable = opts.compactableTools ?? COMPACTABLE_TOOLS;
const candidates = messages.flatMap((m, i) => isToolResult(m) && compactableResult(compactable, m.toolName, opts.toolNameOf) ? [{ idx: i, target: m }] : []);
const beyondKeep = candidates.slice(0, Math.max(0, candidates.length - keep));
const clearable = beyondKeep.filter(({ target }) => !isCleared(target));
if (clearable.length === 0) {
return messages;
}
const tokensSaved = clearable.reduce((sum, { target }) => sum + structuralClearSavings(target), 0);
if (tokensSaved < MIN_CLEAR_SAVINGS_TOKENS) {
return messages;
}
const out = messages.slice();
const clears = [];
for (const { idx, target } of clearable) {
const src = opts.clearSource?.[idx];
const source = src !== undefined && isToolResult(src) && src.toolCallId === target.toolCallId ? src : target;
out[idx] = clearOneResult(source, opts.offload);
clears.push({ index: idx });
}
reportCleared(opts.onCleared, clears, tokensSaved);
return out;
}
export function resolveTriggerWindow(model, overlay) {
const physical = physicalWindowOf(model, overlay);
const declared = overlay?.autoCompactTokens ?? model.autoCompactTokens;
if (declared !== undefined &&
Number.isFinite(declared) &&
declared > 0 &&
Number.isFinite(physical) &&
physical > 0 &&
declared > physical) {
return { window: physical, clamped: true, declaredAutoCompactTokens: declared, physicalWindow: physical };
}
return { window: declared ?? physical, clamped: false };
}
export function editBudget(model, overlay) {
const window = resolveTriggerWindow(model, overlay).window;
if (!Number.isFinite(window) || window <= 0) {
return Number.POSITIVE_INFINITY;
}
return contextEditFrontier(window);
}
export function fingerprintToolResultOccurrence(m) {
const content = Array.isArray(m.content)
? (m.content)
: [];
const canonical = content.map((c) => {
const block = c;
if (block?.type === "text" && typeof block.text === "string") {
return ["text", block.text];
}
return [block?.type ?? "?", block?.mimeType ?? "", typeof block?.data === "string" ? block.data : ""];
});
return createHash("sha256").update(JSON.stringify(canonical)).digest("hex");
}
export function createClearedProjectionLedger() {
return { entries: new Map() };
}
const OCCURRENCE_KEY_SEP = String.fromCharCode(0);
function occurrenceGroupId(m) {
return `${m.toolCallId}${OCCURRENCE_KEY_SEP}${m.timestamp ?? 0}`;
}
export function planRejectionClears(messages, opts) {
const keep = resolveKeepRecentToolResults(opts.keepRecentToolResults, CC_DEFAULT_KEEP_RECENT_TOOL_RESULTS);
const compactable = opts.compactableTools ?? COMPACTABLE_TOOLS;
const candidates = messages.flatMap((m) => (isToolResult(m) && compactableResult(compactable, m.toolName, opts.toolNameOf) ? [m] : []));
const beyondKeep = candidates.slice(0, Math.max(0, candidates.length - keep));
const clearable = beyondKeep.flatMap((m) => {
if (isCleared(m))
return [];
const at = opts.keyOf(m);
return at === undefined ? [] : [{ m, at }];
});
if (clearable.length === 0)
return { declined: "no_candidates" };
const tokensSavedEstimate = clearable.reduce((sum, { m }) => sum + structuralClearSavings(m), 0);
if (tokensSavedEstimate < MIN_CLEAR_SAVINGS_TOKENS)
return { declined: "below_min_savings" };
const cleared = clearable.map(({ m, at }) => {
const source = at.occurrence !== undefined && isToolResult(at.occurrence) ? at.occurrence : m;
const clearedMsg = clearOneResult(source, opts.offload);
return { key: at.key, groupCount: at.groupCount, marker: clearedMsg.content[0]?.text ?? CC_CLEARED_MARKER, fp: at.fp, toolCallId: m.toolCallId };
});
return { cleared, tokensSavedEstimate };
}
export function replayClearedProjection(messages, ledger) {
const groups = new Map();
const byIndex = new Map();
const byObject = new WeakMap();
messages.forEach((m, i) => {
if (!isToolResult(m))
return;
const g = occurrenceGroupId(m);
const list = groups.get(g) ?? [];
byIndex.set(i, { group: g, dupIdx: list.length });
byObject.set(m, { group: g, dupIdx: list.length });
list.push(i);
groups.set(g, list);
});
const mintKey = (hit) => {
if (hit === undefined)
return undefined;
const list = groups.get(hit.group) ?? [];
const occurrenceIdx = list[hit.dupIdx];
return {
key: `${hit.group}${OCCURRENCE_KEY_SEP}${hit.dupIdx}`,
groupCount: list.length,
fp: occurrenceIdx === undefined ? "" : fingerprintToolResultOccurrence(messages[occurrenceIdx]),
...(occurrenceIdx === undefined ? {} : { occurrence: messages[occurrenceIdx] }),
};
};
const index = {
keyAt: (i) => mintKey(byIndex.get(i)),
keyOf: (m) => {
const direct = byObject.get(m);
if (direct !== undefined)
return mintKey(direct);
if (!isToolResult(m))
return undefined;
const g = occurrenceGroupId(m);
const list = groups.get(g);
return list !== undefined && list.length === 1 ? mintKey({ group: g, dupIdx: 0 }) : undefined;
},
};
if (ledger.entries.size === 0) {
return { messages, index };
}
let out;
const rekeyed = new Map();
for (const [key, entry] of ledger.entries) {
const sep = key.lastIndexOf(OCCURRENCE_KEY_SEP);
const group = key.slice(0, sep);
const dupIdx = Number(key.slice(sep + 1));
const list = groups.get(group);
if (list === undefined)
continue;
const m = list.length;
const shrink = Math.max(0, entry.groupCount - m);
const mapped = dupIdx - shrink;
if (mapped < 0 || mapped >= m)
continue;
const targetIdx = list[mapped];
const target = messages[targetIdx];
if (soleMarkerText(target) !== entry.marker) {
if (fingerprintToolResultOccurrence(target) !== entry.fp)
continue;
out = out ?? messages.slice();
out[targetIdx] = { ...target, content: [{ type: "text", text: entry.marker }] };
}
rekeyed.set(`${group}${OCCURRENCE_KEY_SEP}${mapped}`, { marker: entry.marker, groupCount: m, fp: entry.fp });
}
ledger.entries.clear();
for (const [k, v] of rekeyed)
ledger.entries.set(k, v);
return { messages: out ?? messages, index };
}