UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

163 lines (162 loc) • 10.8 kB
import { createHash } from "node:crypto"; import { SEND_MESSAGE_TOOL_NAME } from "../../agents/send-message-tool.js"; import { assemblePrompt } from "../../prompt-assembly/assemble.js"; import { artifactDeclarations } from "../../prompt-assembly/artifact.js"; import { resolveEpochAgainstBundled } from "../../prompt-assembly/epoch.js"; import { SEMA_DEFAULT_PACK } from "../../prompt-assembly/packs/sema-default.js"; import { auditToolCollisions, projectToolManifest } from "../../prompt-assembly/tool-catalog.js"; import { buildEnvironmentContext, defaultPromptProvider } from "../../prompts/default.js"; import { protocolOf } from "../protocol-table.js"; import { reminderMarkDeclaration } from "../reminder-mint.js"; import { hasConversationContent } from "../session.js"; import { PROMPT_HASH_SALT } from "./prompt-hash-salt.js"; export async function preparePromptAssembly(input) { const { session, deps, internals, resume, provider, userSystemPrompt, userAppendSystemPrompt, featureFlags, mcpInstructionsBlock, memoryBlock, envFacts, promptProfile, fableMitigations, tools, model, sessionId, reminderMark, onceLedger } = input; let centerAdoption; let centerAdoptionFresh = false; { const failUnavailable = (digest, via) => { const e = new Error(`prompt snapshot unavailable: ${via} center prompt artifact ${digest.slice(0, 23)}… has no verified resolvable copy (artifact store miss/corrupt${deps.promptSource === undefined ? "; RunnerDeps.promptSource is not configured" : ""}) — refusing to recompose a hybrid prompt (protocol §9.2)`); e.code = "prompt.snapshot_unavailable"; throw e; }; const pinnedEarly = await session.getPromptEpoch(); if (pinnedEarly?.centerArtifactDigest !== undefined) { const art = await deps.promptSource?.get(pinnedEarly.centerArtifactDigest); if (art === undefined) failUnavailable(pinnedEarly.centerArtifactDigest, "this session is pinned to"); centerAdoption = { artifact: art, ...(pinnedEarly.sourceRevision !== undefined ? { sourceRevision: pinnedEarly.sourceRevision } : {}) }; } else if (pinnedEarly === undefined) { if (internals?.parentCenterArtifactDigest !== undefined) { const art = await deps.promptSource?.get(internals.parentCenterArtifactDigest); if (art === undefined) failUnavailable(internals.parentCenterArtifactDigest, "the spawning parent adopted"); centerAdoption = { artifact: art, ...(internals.parentCenterSourceRevision !== undefined ? { sourceRevision: internals.parentCenterSourceRevision } : {}), }; } else if (resume === undefined && internals?.parentTaskId === undefined && internals?.parentSessionId === undefined) { const candidate = deps.promptSource?.current(); if (candidate !== undefined && !hasConversationContent(await session.getBranch())) { centerAdoption = { artifact: candidate.artifact, sourceRevision: candidate.sourceRevision }; centerAdoptionFresh = true; } } } } const buildAssembleInputs = (centerDecls) => ({ provider, isDefaultProvider: provider === defaultPromptProvider, userSystemPrompt, userAppendSystemPrompt, tools: tools.map((t) => (t.aliases === undefined ? { ...t } : { ...t, aliases: [...t.aliases] })), facts: { supervisorEnabled: false, teammateEnabled: internals?.explicitAgentName !== undefined && tools.some((t) => t.name === SEND_MESSAGE_TOOL_NAME), ...featureFlags, orchestrationEnabled: featureFlags.orchestrationEnabled && tools.some((t) => t.name === "Workflow"), orchestrationDeferred: featureFlags.orchestrationDeferred && tools.some((t) => t.name === "Workflow"), promptProfile, fableMitigations, }, mcpInstructionsBlock, memoryBlock, buildEnvBlock: (date) => buildEnvironmentContext({ ...envFacts, date }) || undefined, date: envFacts.date, ...(model.promptGuidance && model.promptGuidance.length > 0 ? { modelGuidance: model.promptGuidance.join("\n\n") } : {}), onWarn: (message, phase) => deps.onError?.(new Error(message), { phase, sessionId }), ...(centerDecls !== undefined ? { centerDeclarations: centerDecls } : {}), }); const assembled = assemblePrompt(buildAssembleInputs(centerAdoption !== undefined ? artifactDeclarations(centerAdoption.artifact) : undefined)); if (centerAdoption !== undefined && assembled.centerMounted !== true) { const ownsWholePrompt = assembled.constitution === "provider-assembled"; const digest = centerAdoption.artifact.artifactDigest.slice(0, 23); if (ownsWholePrompt) { const e = new Error(`center prompt artifact ${digest}… cannot mount: this PromptProvider owns the whole prompt (assembled-identity pass-through) — upgrade the provider to stableBlocks/stableSystem or remove RunnerDeps.promptSource for this deployment`); e.code = "prompt.center_unmountable"; throw e; } deps.onError?.(new Error(centerAdoptionFresh ? `prompt-constitution: center prompt artifact ${digest}… contributed NO section to this prompt — every section it declares collides with a PromptProvider stableBlocks declaration of the same id, and the deployment-local declaration wins. This session runs on the bundled prompt and is deliberately NOT pinned to the artifact (a pin claiming content the model never received would be durable and wrong). Rename the colliding section ids on either side to adopt it; the per-section collisions are reported individually on this channel.` : `prompt-constitution: this session is pinned to center prompt artifact ${digest}…, but under the CURRENT PromptProvider every section that artifact declares collides with a stableBlocks declaration of the same id, so none of them compiled into this prompt. The session keeps its pin and continues on the bundled prompt — its epoch's declaredSections record what actually compiled. Rename the colliding section ids on either side to restore the artifact's content.`), { phase: "prompt-constitution", sessionId }); if (centerAdoptionFresh) centerAdoption = undefined; } let systemPrompt = assembled.systemPrompt; if (!systemPrompt.includes(reminderMarkDeclaration(reminderMark))) { deps.onError?.(new Error("reminder-mark declaration missing from the assembled system prompt: this run's PromptProvider owns the prompt and did not render the mark declaration, so engine <system-reminder> tags carry a mark the model is never told about (the impersonation defense is inactive for this deployment). Render `reminderMarkDeclaration(ctx.reminderMark)` (exported; the value rides StablePromptContext.reminderMark) in the provider, or accept the disclosure."), { phase: "config", sessionId }); } const renderWithDate = assembled.renderWithDate ? (date) => { systemPrompt = assembled.renderWithDate(date); return systemPrompt; } : undefined; const promptConstitution = assembled.constitution; const promptBlocks = assembled.blocks; const collisionAudit = auditToolCollisions(tools); for (const y of collisionAudit.yields) { onceLedger.onError(new Error(`tool mount: caller tool "${y.name}" shadows another tool with the same canonical name (deliberate last-write-wins yield — the later mount serves)`), { phase: "config", sessionId }); } for (const c of collisionAudit.aliasCollisions) { onceLedger.onError(new Error(`tool mount: alias "${c.alias}" is claimed by both "${c.owners[0]}" and "${c.owners[1]}" (design/141 warn face — name resolution serves the later mount)`), { phase: "config", sessionId }); } const saltedHash = (text) => createHash("sha256").update(PROMPT_HASH_SALT).update(text).digest("hex").slice(0, 12); const promptManifest = { constitution: promptConstitution, blocks: promptBlocks.map((b) => ({ id: b.id, chars: b.text.length, hash: saltedHash(b.text) })), ...(assembled.sections ? { sections: assembled.sections.map((s) => ({ id: s.id, slot: s.slot, carrier: s.carrier, cadence: s.cadence, cacheClass: s.cacheClass, chars: s.text.length, hash: saltedHash(s.text), ...(s.declaredContentHash !== undefined ? { contentHash: s.declaredContentHash } : {}) })) } : {}), tools: projectToolManifest(tools, (t) => protocolOf(t.name)?.id ?? "caller"), }; const epochDeclaredSections = (assembled.sections ?? []) .filter((s) => s.origin === "provider") .map((s) => ({ id: s.id, slot: s.slot, chars: s.text.length, ...(s.declaredContentHash !== undefined ? { contentHash: s.declaredContentHash } : {}) })); let epochArtifactDigestForSnapshot = ""; { const pinned = await session.getPromptEpoch(); const resolved = resolveEpochAgainstBundled(pinned, SEMA_DEFAULT_PACK, epochDeclaredSections); epochArtifactDigestForSnapshot = resolved.descriptor.artifactDigest; if (resolved.migrated) { const priorConversation = pinned === undefined ? hasConversationContent(await session.getBranch()) : true; const activatedBy = pinned === undefined && !priorConversation ? "session_start" : "legacy_migration"; await session.appendPromptEpoch({ ...resolved.descriptor, activatedBy, ...(centerAdoption !== undefined ? { centerArtifactDigest: centerAdoption.artifact.artifactDigest, ...(centerAdoption.sourceRevision !== undefined ? { sourceRevision: centerAdoption.sourceRevision } : {}), } : {}), }); } } return { systemPromptSeat: { get current() { return systemPrompt; }, set current(v) { systemPrompt = v; }, }, renderWithDate, systemBlocks: assembled.systemBlocks, promptManifest, epochDeclaredSections, epochArtifactDigestForSnapshot, buildAssembleInputs, centerAdoptionRef: { get current() { return centerAdoption; }, set current(v) { centerAdoption = v; }, }, }; }