UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

139 lines (138 loc) • 7.84 kB
/** * The prompt catalog's shape: every model-visible system-prompt text is one catalog MESSAGE, placed into * the system prompt by a catalog SECTION, and chosen among its VARIANTS by a closed selector (traits and * facts). Catalog entries are literal data — no closures — so the catalog is hashable as a whole and the * hash moves whenever any field of any entry moves. * * What stays code is a RENDERER (renderers.ts): a section whose bytes come from prepare-time inputs (the * role base the caller chose, the environment tail, the memory tail, the MCP instructions frame, the * reminder-mark declaration). Renderers carry a version; changing a renderer's output means bumping it. */ /** The band a section belongs to: a POLICY class (who may write it, which sink it reaches), never a position. * Position is the section's own `rank`. */ export type BandId = "role" | "scenario" | "task-append" | "behavior" | "core-behavior" | "constitution" | "discovery" | "environment" | "memory"; /** The source classes that write a band through overlays; `bundled` is the catalog itself. */ export type OverlaySource = "center" | "deploy" | "task"; /** Whether `v` is one of a closed set's words — the one membership reading the selector vocabularies share. */ export declare function isWordOf<W extends string>(words: readonly W[], v: unknown): v is W; /** The four overlay operations (a closed set; docs/CLOSED-SETS.md). */ export declare const OVERLAY_OPS: readonly ["replace", "append", "add", "drop"]; export type OverlayOp = (typeof OVERLAY_OPS)[number]; export interface BandRow { readonly id: BandId; /** The policy class in words (the band table's first column). */ readonly policy: "overridable" | "add-only" | "overridable-restricted" | "locked" | "fact"; /** The ops each overlay source may apply in this band. All empty ⇒ the band is locked. */ readonly ops: Readonly<Record<OverlaySource, readonly OverlayOp[]>>; /** Where an `add` lands, when the band admits one. */ readonly addRank?: number; /** The one mods event whose answers may write this band (absent ⇒ no mods event writes it). */ readonly modsEvent?: "prompt.compose" | "prompt.section"; } /** The host role a run is assembled for — which role base `core/role.base` selects. Written by whoever builds the * task (`TaskSpec.promptRole`); absent ⇒ `general`. */ export declare const HOST_ROLES: readonly ["general", "code", "coordinator", "cowork"]; export type HostRole = (typeof HOST_ROLES)[number]; /** The host form: `minimal` leaves the core-behavior band out (the locked bands stay). Written only by * `TaskSpec.promptForm`; absent ⇒ `standard`. */ export declare const HOST_FORMS: readonly ["standard", "minimal"]; export type HostForm = (typeof HOST_FORMS)[number]; export interface HostCondition { readonly role?: HostRole; readonly form?: HostForm; } /** * The model-capability traits a variant may be selected on — the reference's capability names, spelled * as the reference spells them, so an anchor upgrade can be diffed mechanically. The producer * ({@link import("../select.js").promptTraitsOf}) yields exactly these two today; a name joins this set when a * producer can yield it, never before. */ export declare const PROMPT_TRAITS: readonly ["lean_prompt", "fable_5_mitigations"]; export type PromptTrait = (typeof PROMPT_TRAITS)[number]; /** The boolean facts a section admit or a variant `when` may test. All but the last are runtime facts the * prepare phase produces; `executionEnvironmentDeclared` is derived once from two of them, so no `when` * ever needs a disjunction. An optional fact that is absent reads as `false`. */ export declare const PROMPT_FACT_NAMES: readonly ["policyEnabled", "hooksEnabled", "isolationEnabled", "readFaceOpen", "writeFaceOpen", "withinTaskCompactionEnabled", "supervisorEnabled", "orchestrationEnabled", "orchestrationDeferred", "awarenessEnabled", "goalEnabled", "worktreeIsolated", "teammateEnabled", "isSubagent", "executionEnvironmentDeclared"]; export type PromptFactName = (typeof PROMPT_FACT_NAMES)[number]; /** A conjunction of fact equalities — the whole predicate language. No disjunction, no expressions. */ export type FactConjunction = Readonly<Partial<Record<PromptFactName, boolean>>>; export interface TraitCondition { readonly allOf?: readonly PromptTrait[]; readonly noneOf?: readonly PromptTrait[]; } /** How a text relates to the reference. `cc` entries use the byte-span locator grammar the anchor gate resolves * (scripts/verify-anchor-claims.mjs): corpus file, byte span, and a backticked identifier that occurs in it. */ export interface Attribution { readonly form: "verbatim" | "adapted" | "sema-owned"; readonly cc?: readonly string[]; } export interface Variant { /** Reported in the manifest — one of the answers to "why this sentence". */ readonly id: string; readonly when: CatalogVariantWhen; readonly text: string; } /** A condition on the run's binding (`TaskSpec.promptBinding`, a deployment's scenario name): exactly one list. A run * with no binding is outside every `anyOf` and inside every `noneOf`. */ export type BindingCondition = { readonly anyOf: readonly string[]; readonly noneOf?: never; } | { readonly noneOf: readonly string[]; readonly anyOf?: never; }; /** The selector condition a variant (or an overlay) is chosen on: a conjunction over traits, host, facts and binding. */ export interface VariantWhen { readonly traits?: TraitCondition; readonly host?: HostCondition; readonly facts?: FactConjunction; readonly binding?: BindingCondition; } /** The condition a BUNDLED catalog variant is chosen on: a {@link VariantWhen} without the binding. A binding is a * deployment's own vocabulary (scenario names the engine cannot know), so no catalog variant can name one — the type * refuses it where the catalog data is written. */ export type CatalogVariantWhen = Omit<VariantWhen, "binding">; export interface CatalogMessage { /** `core/<area>.<name>`. */ readonly id: string; /** Variants in declaration order; the first whose `when` holds is selected. None holds ⇒ the message is absent. */ readonly variants: readonly [Variant, ...Variant[]]; readonly attribution: Attribution; } /** The renderers the catalog may place by id — data here, so the catalog checks its sections without loading the * renderer code; renderers.ts holds the code and the version table, one row per id (its record type is total). */ export declare const RENDERER_IDS: readonly ["role-base", "model-guidance", "mcp-instructions", "reminder-mark", "environment", "memory"]; export type RendererId = (typeof RENDERER_IDS)[number]; export type SectionBody = { readonly message: string; } /** One message per line, each with an optional line-level admit, joined by `joiner`. */ | { readonly lines: readonly { readonly message: string; readonly admit?: FactConjunction; }[]; readonly joiner: "\n" | "\n\n"; } | { readonly renderer: RendererId; }; export interface CatalogSection { /** `core/…` — the id the manifest, `context_usage` and the center tier read. */ readonly id: string; readonly band: BandId; /** Global emission order (unique). */ readonly rank: number; /** The `prompt.assembled` block view: adjacent sections sharing a block id merge into one block. */ readonly block: { readonly id: string; readonly joiner?: "\n" | "\n\n"; }; readonly admit?: FactConjunction; readonly body: SectionBody; } export interface PromptCatalog { readonly id: string; readonly bands: readonly BandRow[]; readonly messages: readonly CatalogMessage[]; readonly sections: readonly CatalogSection[]; }