@sema-agent/core
Version:
Stateless, task-oriented AI agent core
96 lines (95 loc) • 5.96 kB
TypeScript
import type { PromptCatalog } from "./catalog/schema.js";
/** Deterministic canonical JSON (sorted keys) — the one identity encoding (the catalog digest, the identity, the
* center artifact digest). */
export declare function canonical(node: unknown): string;
/** `sha256:<hex>` over a canonical encoding. */
export declare function digestOf(node: unknown): string;
/** The bundled catalog's digest. Array positions that carry no meaning are normalized (sections by rank, messages and
* bands by id), so the digest does not depend on how a module lays out its arrays; variant order is meaning (first
* match wins) and stays. */
export declare function catalogDigestOf(catalog: PromptCatalog): string;
/** The inputs of a run's prompt identity. Only `center` is pinned (resolved by digest on resume); the rest are what
* the run computed, kept so a later run can say what changed. Absent `center` / `deploy` / `task` = that layer
* contributed nothing. */
export interface PromptIdentityLayers {
readonly catalog: string;
readonly renderers: Readonly<Record<string, number>>;
/** The adopted center artifact's digest. */
readonly center?: string;
readonly deploy?: string;
readonly task?: string;
/** H(the run's selector values). */
readonly binding: string;
}
/** A run's prompt identity inputs plus its pinned center layer's provenance — what the epoch record carries. */
export interface RunPromptIdentity {
readonly layers: PromptIdentityLayers;
readonly sourceRevision?: string;
}
/** The one identity digest over the four inputs. */
export declare function promptIdentityOf(layers: PromptIdentityLayers): string;
/** How a recorded epoch came to be: a legal boundary (`session_start`, `compaction`), or a record that code or
* inputs moved (`code_change`, naming the changed layers when they are known) or that only the selector values
* did (`selection_change`). */
export declare const PROMPT_EPOCH_ACTIVATIONS: readonly ["session_start", "compaction", "code_change", "selection_change"];
export type PromptEpochActivation = (typeof PROMPT_EPOCH_ACTIVATIONS)[number];
/** What a `code_change` record names as changed. `published_schema` is the one replacement of a retired-shape center
* pin by the current center layer. */
export declare const PROMPT_EPOCH_CHANGES: readonly ["catalog", "renderers", "deploy", "task", "published_schema"];
export type PromptEpochChange = (typeof PROMPT_EPOCH_CHANGES)[number];
/** The durable record, persisted as a first-class session entry and restated in every compaction entry's
* `details.promptEpoch`. */
export interface PromptEpochDescriptor {
/** Monotonic per-session record counter. */
readonly epoch: number;
/** The run's prompt identity ({@link promptIdentityOf}). */
readonly identity: string;
readonly layers: PromptIdentityLayers;
readonly activatedBy: PromptEpochActivation;
/** Present only on `code_change` records whose changed layers are known. */
readonly changed?: readonly PromptEpochChange[];
/** Opaque publish provenance of the pinned center layer (present only with `layers.center`; never digested). */
readonly sourceRevision?: string;
}
/** What a stored epoch record reads as on the resume path: a v3 pin, or a retired shape recognized by name. */
export type StoredPromptEpoch = {
readonly kind: "pin";
readonly descriptor: PromptEpochDescriptor;
} | {
readonly kind: "legacy";
readonly centerPinned: boolean;
};
/**
* Shape-normalize an untrusted v3 descriptor — the current shape's one judge (the first reading of
* {@link readStoredPromptEpoch}; a session backend judges a record with it). Strict: a bounded positive epoch, a full
* digest identity that MATCHES its layers, the closed activation and change vocabularies, provenance only beside a
* center layer. Members it does not read (a session entry's own `type` / `id` / `parentId` / `timestamp`) are ignored.
* Undefined for anything else — including every retired shape.
*/
export declare function normalizePromptEpoch(raw: unknown): PromptEpochDescriptor | undefined;
/**
* The resume path's reading of one stored record: a valid v3 pin, `legacy` (a retired shape, recognized by its field
* names — nothing in it is parsed but whether `centerArtifactDigest` is a digest, the only value the retired reader
* took for a pin), or undefined (malformed: the walk skips it).
*/
export declare function readStoredPromptEpoch(raw: unknown): StoredPromptEpoch | undefined;
/**
* The record a run leaves at prepare, or undefined when the stored pin already names this run's identity.
* - no record: `session_start` for a session with no prior conversation; otherwise `code_change` (a session that
* predates epochs — what changed is unknown);
* - a v3 pin: the same identity ⇒ nothing; else `code_change` naming the changed code / input layers, or
* `selection_change` when only the selector values moved;
* - `legacy`: `code_change` — naming `published_schema` when the retired record pinned a center artifact (the caller
* applied the center source's tri-state to it), otherwise unknown. The retired record's counter is not read; the
* v3 line starts at 1.
*/
export declare function prepareEpochRecord(stored: StoredPromptEpoch | undefined, layers: PromptIdentityLayers, ctx: {
readonly priorConversation: boolean;
readonly sourceRevision?: string;
}): PromptEpochDescriptor | undefined;
/**
* The record a compaction restates or advances: the current pin restated when the run's identity is unchanged (the
* boundary is stamped), otherwise a new record with the run's layers after the boundary — an adopted center
* candidate, or an emptied center layer after an explicit revocation.
*/
export declare function selectCompactionEpoch(current: PromptEpochDescriptor | undefined, layers: PromptIdentityLayers, sourceRevision?: string): PromptEpochDescriptor;