UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

237 lines (236 loc) • 15.5 kB
import { classifyToolContentOrigin, contentOriginPollutes, delegationCallIsExternal } from "../memory-engine/content-origin.js"; import { narrowContentSafety, readCardAttestation } from "../memory-engine/delegation-provenance.js"; import { recordSyncUnattestable, sessionSettlements } from "../memory-engine/delegation-settlement.js"; import { protocolOf } from "../protocol-table.js"; import { deliverEngineNotice } from "../types.js"; import { inlineUntrusted } from "../untrusted-text.js"; import { fileArgPath } from "../../tools/fs/safety.js"; import { RosterBuilder } from "../tool-roster.js"; import { thrownText } from "../thrown-value.js"; export function prepareMemoryEngineSession(input) { const { memoryEngineSession, internals, memoryDelegationEvidence, externalContentTargetActive, lockedPreflight, mcp, sessionId, runId, deps, provenanceForChildrenRef, delegationSettlementRef, spec, envHandToolNames, roster, contentOriginWrapRef } = input; const tools = roster.tools; const delegationProvenanceChannel = internals?.delegationProvenance; if (memoryEngineSession !== undefined || delegationProvenanceChannel !== undefined) { const pollution = memoryEngineSession?.pollution; const delegationEvidenceAttestedOnly = memoryDelegationEvidence === "attested-only"; let staticMarkWaiverAnnounced = false; const effectiveSafety = narrowContentSafety(delegationProvenanceChannel?.contentSafety, memoryEngineSession?.contentSafety); const trustedTools = effectiveSafety.trustedTools; const execIsExternalContent = effectiveSafety.execIsExternalContent || externalContentTargetActive; provenanceForChildrenRef.current = { trustedTools: [...trustedTools], execIsExternalContent }; announceDeclaredMcpContentClasses({ entries: lockedPreflight.mcp, statuses: mcp.statuses, execIsExternalContent, sessionId, runId, onNotice: deps.onNotice, }); if (memoryEngineSession?.settlement !== undefined) { delegationSettlementRef.current = { controlDir: memoryEngineSession.settlement.controlDir, sessionId: memoryEngineSession.settlement.sessionId }; } const recordExternal = () => { if (delegationProvenanceChannel !== undefined) delegationProvenanceChannel.ref.current.sawExternal = true; }; const recordIncomplete = () => { if (delegationProvenanceChannel !== undefined) delegationProvenanceChannel.ref.current.incomplete = true; }; const callerToolNames = new Set((spec.tools ?? []).map((t) => t.name)); const contentOriginWrapped = new WeakSet(); const classOf = (t) => externalContentTargetActive && envHandToolNames.has(t.name) ? "external" : classifyToolContentOrigin({ declared: t.contentOrigin, isProtocolTool: protocolOf(t.name) !== undefined, isCallerTool: callerToolNames.has(t.name), trusted: trustedTools.has(t.name), }); const delegationByName = new Map(); for (const t of spec.tools ?? []) { const withFaces = t; if (withFaces.agentToolFaces === undefined && t.agentListing === undefined) continue; delegationByName.set(t.name, { faces: withFaces.agentToolFaces, pool: withFaces.agentToolPool }); } const poolToolPollutes = (t) => contentOriginPollutes(classifyToolContentOrigin({ declared: t.contentOrigin, isProtocolTool: protocolOf(t.name) !== undefined, isCallerTool: true, trusted: trustedTools.has(t.name), }), execIsExternalContent); const recallTaintJudge = memoryEngineSession?.recallTaint?.judgeDeliveredPath; contentOriginWrapRef.current = () => { for (let i = 0; i < tools.length; i++) { const t = tools[i]; if (contentOriginWrapped.has(t)) continue; const origin = classOf(t); const delegation = delegationByName.get(t.name); const isDelegation = delegation !== undefined; const pollutes = contentOriginPollutes(origin, execIsExternalContent); const readsMemoryPlane = recallTaintJudge !== undefined && t.name === "Read"; if (!pollutes && !isDelegation && !readsMemoryPlane) { contentOriginWrapped.add(t); continue; } const inner = t.execute.bind(t); const mark = (reason, cause) => { try { pollution?.markPolluted(reason, cause); } catch { } }; const wrapped = { ...t, execute: async (toolCallId, params, signal, onUpdate) => { if (pollutes) { mark(`tool "${t.name}" (${origin} content class) was invoked in this session`, "observed"); recordExternal(); } if (!isDelegation) { if (!readsMemoryPlane) return inner(toolCallId, params, signal, onUpdate); const result = await inner(toolCallId, params, signal, onUpdate); const raw = result; const contentField = typeof raw === "object" && raw !== null ? raw.content : undefined; const headText = typeof raw === "string" ? raw : typeof contentField === "string" ? contentField : Array.isArray(contentField) && typeof contentField[0]?.text === "string" ? contentField[0].text : ""; const delivered = result?.isError !== true && result?.details?.type !== "file_unchanged" && !headText.startsWith("<system-reminder"); const fp = fileArgPath(params); if (delivered && fp !== undefined && recallTaintJudge(fp)) { mark(`the "${t.name}" tool delivered the content of an external-origin memory entry file`, "derived"); } return result; } let preCallLaunchRows; if (delegationEvidenceAttestedOnly && memoryEngineSession?.settlement !== undefined) { try { preCallLaunchRows = new Set(sessionSettlements(memoryEngineSession.settlement.controlDir, memoryEngineSession.settlement.sessionId) .filter((r) => r.row.lane === "background" && r.row.toolUseId === toolCallId) .map((r) => r.row.settleId)); } catch { preCallLaunchRows = undefined; } } const requested = params?.subagent_type; const external = delegationCallIsExternal({ requestedType: typeof requested === "string" ? requested : undefined, faces: delegation.faces, pool: delegation.pool, isPolluting: poolToolPollutes, }); const result = await inner(toolCallId, params, signal, onUpdate); const att = readCardAttestation(result?.details); if (att === "external") { mark(`tool "${t.name}" returned the output of a delegated agent that invoked an external-content-class tool at runtime` + (typeof requested === "string" ? ` (subagent_type "${requested}")` : ""), "observed"); recordExternal(); } else if (att !== "clean") { if (external) { const staticFaceReason = `tool "${t.name}" returned the output of a delegated agent whose tool face can reach external content` + (typeof requested === "string" ? ` (subagent_type "${requested}")` : " (no subagent_type named — classified fail-closed)"); if (!delegationEvidenceAttestedOnly) { mark(staticFaceReason, "static"); } else { const receiptDetails = result?.details; const claimsLaunchReceipt = receiptDetails !== undefined && receiptDetails !== null && receiptDetails.status === "async_launched"; const claimedSettleId = claimsLaunchReceipt && typeof receiptDetails.settle_id === "string" ? receiptDetails.settle_id : undefined; const settlementSeat = memoryEngineSession?.settlement; let isLaunchReceipt = false; if (claimsLaunchReceipt && settlementSeat !== undefined) { try { isLaunchReceipt = preCallLaunchRows !== undefined && claimedSettleId !== undefined && !preCallLaunchRows.has(claimedSettleId) && sessionSettlements(settlementSeat.controlDir, settlementSeat.sessionId).some((r) => r.row.lane === "background" && r.row.settleId === claimedSettleId && r.row.toolUseId === toolCallId); } catch { isLaunchReceipt = false; } } if (!isLaunchReceipt && settlementSeat !== undefined) { try { recordSyncUnattestable(settlementSeat.controlDir, { sessionId: settlementSeat.sessionId, toolCallId, now: Date.now }); } catch (err) { const e = new Error(`delegated output withheld (fail-closed): the delegation delivered without a provable attestation and the settlement account could not record the fact (${thrownText(err)}) — repair the memory control plane or retry`); e.code = "memory.settlement_record_failed"; throw e; } } } if (delegationEvidenceAttestedOnly && pollution !== undefined && !staticMarkWaiverAnnounced) { staticMarkWaiverAnnounced = true; const waivedReason = inlineUntrusted(staticFaceReason, 200); deliverEngineNotice(deps.onNotice, { code: "memory.delegation_static_mark_waived", message: `Delegation static-face pollution mark waived: ${waivedReason}. The deployment configured ` + `memoryDelegationEvidence="attested-only", so a static tool-face verdict alone does not mark this ` + `session's memory polluted; a delivered "external" attestation and a direct polluting-class ` + `invocation still mark, and on a provenance-armed chain this delegation still records as ` + `incomplete. At most one notice per prepared task leg.`, detail: { reason: waivedReason, ...(typeof requested === "string" ? { subagentType: inlineUntrusted(requested, 120) } : {}), sessionId, runId, }, }); } } recordIncomplete(); } return result; }, }; contentOriginWrapped.add(wrapped); roster.replaceAt(i, wrapped); } }; contentOriginWrapRef.current(); } return { armed: memoryEngineSession !== undefined || delegationProvenanceChannel !== undefined }; } function announceDeclaredMcpContentClasses(args) { for (const entry of args.entries ?? []) { const declaredClass = entry.contentOrigin; if (declaredClass === undefined) continue; const server = inlineUntrusted(String(entry.name), 160); const toolCount = args.statuses?.find((s) => s.name === entry.name)?.toolNames?.length ?? 0; const resourceFaceCaveat = " (Not covered: the cross-server resource faces — ListMcpResourcesTool/ReadMcpResourceTool/ReadMcpResourceDirTool — stay externally classified and still mark.)"; const posture = declaredClass === "local" ? `this server's mounted tools' invocations will not mark this session's memory as externally exposed.${resourceFaceCaveat}` : declaredClass === "execution" ? `this server's mounted tools' invocations will not mark this session's memory unless the execIsExternalContent strict upgrade is armed (currently: ${args.execIsExternalContent ? "armed" : "off"}).${resourceFaceCaveat}` : "its tools stay externally classified and this declaration PINS that — the trustedTools allowlist no longer exempts them, and invocations mark this session's memory."; deliverEngineNotice(args.onNotice, { code: "memory.content_class_declared", message: `MCP server "${server}" (${toolCount} tool(s) mounted) is declared ` + `contentOrigin "${declaredClass}" by this deployment's configuration — ${posture}`, detail: { server, contentOrigin: declaredClass, toolCount, ...(declaredClass === "execution" ? { execIsExternalContent: args.execIsExternalContent } : {}), sessionId: args.sessionId, runId: args.runId, }, }); } }