UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

86 lines (85 loc) • 5.82 kB
import type { PromptPack } from "./types.js"; /** the provider-declared sections of THIS run's resolved prompt (the `origin:"provider"` * subset of the compiled IR), the declaration axis of the artifact identity. * * (S1 round 2): declaration TEXT deliberately does NOT enter this shape — the epoch * digest is a deterministic, unsalted value persisted in exportable session entries, and session * readers do not see system prompts; hashing private text into it would be a dictionary-preimage * surface (the exact class the salted prompt-manifest hashes exist to prevent). Identity instead * rides `(id, slot, chars)` plus the declarer's OPT-IN `contentHash` (the digest-tiering value, * already public by declaration): with contentHash — byte-precise re-pin detection (the center * publish path always mints it); without — length-level detection only, documented degradation * for private/forwarded text. */ export type EpochDeclaredSections = ReadonlyArray<{ id: string; slot: string; chars: number; contentHash?: string; }>; /** How an epoch became active (protocol §9.2 descriptor field; `clear` arrives with a future * first-class context_reset — v1 clear = new session = `session_start`). */ export type PromptEpochActivation = "session_start" | "compaction" | "legacy_migration"; /** The durable pin, persisted as a first-class session entry (root) and restated in every * compaction entry's `details.promptEpoch` (same-CAS atomicity; bounded-tail recoverable). */ export interface PromptEpochDescriptor { /** Monotonic per-session epoch counter (session_start = 1). */ epoch: number; artifactDigest: string; packId: string; assemblyApi: number; activatedBy: PromptEpochActivation; /** design/148 S1 (additive provenance, present only on center-adopted pins): the VERIFIED center * artifact this session composes from. `artifactDigest` above stays the computed * bundled+declarations identity (the existing re-pin machinery); this field is what the resume * path resolves through the artifact store — a miss is fail-loud (`prompt.snapshot_unavailable`), * never a silent hybrid recompose (protocol §9.2). */ centerArtifactDigest?: string; /** Opaque publish provenance of the adopted envelope (audit only — never enters any digest). */ sourceRevision?: string; } /** Deterministic canonical JSON (sorted keys) — shared identity encoding for the bundled-pack * digest AND the center artifact digests (design/148 S1: one canonicalization, never two). */ export declare function canonical(node: unknown): string; /** * Bundled-pack artifact digest: canonical hash over the pack's structural declaration PLUS each * section's probe-rendered content under the probe-fact vectors — all-off, all-on, and one * single-axis-flipped vector per axis (content- and admission-binding, incl. single-gate mixed * states). TOTALITY over the axes the pack forks on is the load-bearing property (see * PROBE_FACTS_OFF/PROBE_FACTS_ON); it is pinned behaviourally by * test/hardening-prompt-assembly.test.ts. Deterministic across processes and object insertion order; * changes to any section's prose, admission behavior, or structure change the digest. Build version * deliberately EXCLUDED (F3): a release that doesn't touch the pack keeps the same identity. */ export declare function computeBundledArtifactDigest(pack: PromptPack, declared?: EpochDeclaredSections): string; /** Mint the descriptor for a NEW session on the current bundled artifact. * Subagent/fork note (RB-16 ruling, 2026-07-17): children mint their OWN session_start pin rather * than inheriting the parent's descriptor — under v1 bundled-only resolution both produce the * identical pin (same process, same pack, same digest), so the protocol's "explicit inheritance * via RunInternals" is deferred to the multi-artifact era, where a parent pinned to a non-latest * artifact genuinely diverges from a fresh mint (lands with the center candidate machinery). */ export declare function mintSessionStartEpoch(pack: PromptPack, declared?: EpochDeclaredSections): PromptEpochDescriptor; /** Epoch selection at a compaction boundary (protocol §9.3 order steps 1-4, v1 bundled form): * the "latest validated candidate" IS the current bundled artifact. Same digest ⇒ restate the * current epoch (no advance); different digest (engine upgraded mid-session) ⇒ advance. */ export declare function selectCompactionEpoch(current: PromptEpochDescriptor | undefined, pack: PromptPack, declared?: EpochDeclaredSections, /** RB-31 (design/148 S2) — a compaction-boundary CENTER ADOPTION: the new candidate's provenance * rides the advanced descriptor (the caller pre-assembled with the candidate's declarations, so * `declared` already reflects the new closure — the digest moves, the epoch advances). */ centerAdoption?: { centerArtifactDigest: string; sourceRevision?: string; } | { clear: true; }): PromptEpochDescriptor; /** * Resolve the session's pinned epoch against the CURRENT bundled artifact (v1 resolution). * Returns the effective descriptor plus whether a legacy migration happened (pin from another * build, or a pre-epoch session with no pin at all) — the caller records the migration entry. */ export declare function resolveEpochAgainstBundled(pinned: PromptEpochDescriptor | undefined, pack: PromptPack, declared?: EpochDeclaredSections): { descriptor: PromptEpochDescriptor; migrated: boolean; }; /** Shape-normalize an untrusted candidate (session import face — RB-7: import-validate is a * consumer). Returns undefined for anything that isn't a plausible descriptor. */ export declare function normalizePromptEpoch(raw: unknown): PromptEpochDescriptor | undefined;