UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

138 lines (137 loc) • 8.01 kB
import { type BandId, type CatalogSection, type OverlayOp, type OverlaySource, type VariantWhen } from "./catalog/schema.js"; /** One overlay: an operation on a target, carrying text (or a catalog message reference). */ export interface PromptOverlay { /** `<namespace>/<name>`; the `core/` namespace is the task sugar's alone. Names an added entry. */ readonly id: string; readonly op: OverlayOp; /** A message id (`replace` / `append`), a band id (`add`), or a section / added-entry id (`drop`). */ readonly target: string; /** The overlay's text (`replace` / `append` / `add`); exclusive with `message`. */ readonly text?: string; /** A catalog message whose selected variant is the overlay's text; exclusive with `text`. */ readonly message?: string; /** The overlay applies to this run only when this holds (the variant selector's own vocabulary, the binding * included) — the one applicability condition of every source class. */ readonly when?: VariantWhen; } /** The source classes in application order (later wins). `bundled` is the catalog itself and writes no overlay. */ export declare const OVERLAY_SOURCE_ORDER: readonly ["bundled", "task", "center", "deploy"]; /** Who contributed an overlay: its source class and, within it, the contributor (`sugar`, a mods registration, the center). */ export interface OverlayOrigin { readonly source: OverlaySource; readonly by: string; } export interface SourcedOverlay { readonly overlay: PromptOverlay; readonly origin: OverlayOrigin; } /** An overlay a later one on the same target overrode (or a drop removed), or one that changed nothing this run. */ export interface SupersededOverlay { readonly id: string; readonly source: OverlaySource; readonly by: string; readonly target: string; /** The overlay id that won, or {@link ABSENT_THIS_RUN}. */ readonly supersededBy: string; } /** `supersededBy` of an overlay that changed nothing this run: the selector chose no variant of its target, or of * the catalog message it takes its text from. */ export declare const ABSENT_THIS_RUN = "(absent this run)"; /** The section a message id is placed by, when the catalog places it. */ export declare function sectionOfMessage(id: string): CatalogSection | undefined; export interface LockedEntry { readonly message: string; readonly variant: string; readonly text: string; } /** Every constitution entry the guard compares: each message a constitution section places, every variant, whole. */ export declare function lockedEntries(): readonly LockedEntry[]; /** The constitution entries (`message#variant`) whose canonical text `text` contains verbatim. */ export declare function lockedTextIn(text: string): string[]; /** The task sugar's one violation: a role-layer text that carries locked text (an already-assembled prompt). */ export declare function assembledRoleRefused(field: string, hits: readonly string[]): Error; /** Receive a source's prompt data ({@link PROMPT_DATA}): its frozen copy, or the clause naming what in it is not data. */ export declare function receivePromptData(raw: unknown): { readonly value: unknown; } | { readonly notData: string; }; /** The longest binding a task may name (`TaskSpec.promptBinding`), counted in Unicode code points (`[...s].length`) — not * in UTF-16 code units; every binding a `when.binding` list names is held to the same bound. Exported so a host screens * with the engine's number and the engine's unit. Code points are the one unit of every character bound of the prompt * artifact verifier ({@link codePointsOver}: a binding, an overlay id, `sourceRevision`, `evidence.intent`, a * reference), so a character outside the BMP (an emoji, a rare CJK ideograph) counts one, not two; the overlay text * budgets are UTF-8 bytes and are named so. */ export declare const PROMPT_BINDING_MAX_CHARS = 128; /** The most bindings one `when.binding` list names — it bounds what a publisher can make the conflict check walk. */ export declare const PROMPT_BINDING_LIST_MAX = 64; /** Whether `s` holds more than `max` Unicode code points — the one length unit of the prompt artifact verifier's * character bounds. A string of at most `max` code units fits (a code point is one or two of them); one of more than * twice `max` does not; only a string in between is counted — counted, never copied whole. */ export declare function codePointsOver(s: string, max: number): boolean; /** * The run's binding (`TaskSpec.promptBinding`): the scenario a `when.binding` condition reads, on an overlay of any * source class. Its one writer is the task (a deployment names its scenario); absent ⇒ undefined. A value outside the * grammar is refused by name (`config.prompt_selector_invalid`), never read as absent. */ export declare function resolvePromptBinding(task: { readonly promptBinding?: unknown; }): string | undefined; /** What a validation needs besides the overlay: its source class, which mods event (if any) carries it, and the * entries lower classes added (the only entries a `drop` may name besides a built-in section). */ export interface OverlayValidationContext { readonly source: OverlaySource; /** The mods event the overlay arrived on; absent for the sugar and the center. */ readonly event?: "prompt.compose"; /** The request-body sugar may use the `core/` namespace; nothing else may. */ readonly sugar?: boolean; /** Ids of entries lower source classes added (`add`) and the band each landed in. */ readonly lowerAdds?: ReadonlyMap<string, BandId>; } /** * Validate one overlay for one source class. Returns the overlay (a frozen copy of its known members, its `when` in * normal form — {@link canonicalWhen}) or why it is a violation: shape, namespace, op, text/message, `when`, target existence, band authorization (and the band's mods * write port), and the locked-text guard. */ export declare function validateOverlay(raw: unknown, ctx: OverlayValidationContext): { readonly overlay: PromptOverlay; } | { readonly violation: string; }; /** One added entry as the fold leaves it. */ export interface AddedEntry { readonly id: string; readonly band: BandId; readonly rank: number; readonly text: string; readonly origin: OverlayOrigin; } /** One overlay in a section's history, in application order; `superseded` once a later one overrode it. The * composition puts the catalog's own text (`bundled`) first for a catalog section. */ export interface ChainLink { readonly source: "bundled" | OverlaySource; readonly overlay?: string; readonly op?: OverlayOp; readonly superseded?: true; } /** The fold's result: per-message text the overlays set, dropped sections, added entries, superseded overlays. */ export interface OverlayFold { /** Message id → its text after the overlays (absent ⇒ the selected variant's text stands). */ readonly messageText: ReadonlyMap<string, { readonly text: string; readonly origin: OverlayOrigin; readonly replaced: boolean; }>; /** Built-in section ids a drop removed. */ readonly dropped: ReadonlySet<string>; readonly added: readonly AddedEntry[]; readonly superseded: readonly SupersededOverlay[]; /** Section id (or added-entry id) → the overlays applied to it, in order, superseded ones marked. */ readonly chains: ReadonlyMap<string, readonly ChainLink[]>; } /** * Apply sourced overlays, already validated and already in application order, over the selected texts. * `selectedText(messageId)` answers the text the selector chose (undefined ⇒ the message is absent this run); * `applies(overlay)` answers its `when`. */ export declare function foldOverlays(ordered: readonly SourcedOverlay[], selectedText: (messageId: string) => string | undefined, applies: (o: PromptOverlay) => boolean, overlayText: (o: PromptOverlay) => string | undefined): OverlayFold;