UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

360 lines (359 loc) • 26.3 kB
import type { AssertAllKeysHandled } from "./ask-origin.js"; /** Retry class of a governance code: `transient` = a later retry can self-heal (control-plane * absence/outage); `terminal` = policy adjudicated, re-issuing changes nothing. */ export type GovernanceRetryClass = "transient" | "terminal"; /** * The closed governance-code registry. tsc forces every entry to a valid class; the gate test * forces the naming convention and pack-family completeness. Adding a code = one deliberate row. */ export declare const GOVERNANCE_CODES: { readonly "usage.window_exhausted": "terminal"; readonly "memory.admission_required": "transient"; readonly "memory.admission_denied": "terminal"; readonly "config.compliance_required": "transient"; readonly "config.compliance_denied": "terminal"; readonly "config.locked_key": "terminal"; readonly "memory.capture_optout_denied": "terminal"; }; export type GovernanceCode = keyof typeof GOVERNANCE_CODES; /** * `memory.*` error codes DELIBERATELY outside governance: write-gate and engine incident codes * (secret detection, promotable-gate refusals, announce/partition incidents, tail truncation) — * mechanical faults and content-safety refusals, not per-principal policy verdicts; they classify * as `logic`. The gate test forces every `memory.*` literal minted in src/ to appear EITHER in * {@link GOVERNANCE_CODES} or here — a new code gets NAMED and dispositioned, never silently * classified. * * THREE dispositions cover every row below, and each group NAMES the one it takes instead of * re-deriving it: * · POSTURE — a disclosure about something that already happened (a mark, a hold, a withholding, a * recommendation, a declared trust boundary). The act is done when the code mints, so no principal * is judged and there is no retry decision to carry. * · CONTROL-PLANE IO — a mechanical fault on the engine's own account (a durable write, a sweep, a * lease, a backend, a rebuildable projection). Operator attention, never a verdict. * · CALLER SHAPE — a refusal thrown at a HOST valve API (missing audit attribution, an * out-of-vocabulary verdict or action, an unknown id, an unresolvable row state). Retrying the same * wrong call cannot succeed, which is why no retry class fits it either. */ export declare const NON_GOVERNANCE_MEMORY_CODES: ReadonlySet<string>; /** * Look up a code's governance retry class. Registered code ⇒ its table class; unregistered * `usage.*` ⇒ `"terminal"` (the prefix family's shipped classification); anything else ⇒ * `undefined` (NOT governance — the caller falls through to its ordinary taxonomy). */ export declare function governanceRetryClass(code: string): GovernanceRetryClass | undefined; /** * The CLOSED set of codes the `spec.tools` DECLARATION door refuses a caller's tool entry with, at prepare, * before anything mounts: the entry cannot be built from its own members (`config.tool_mount_denied`), a * member over a roster row's wire bound (`config.tool_roster_bound` / `config.tool_name_too_long` / * `config.tool_contract_too_long`), a schema over the row's key bounds (`config.tool_schema_bound`), a * declared face or result card the schema / namespace cannot carry (`config.tool_face_invalid`), a name or * alias in the engine's protocol namespace (`config.tool_name_invalid`), an egress tool declared other than * `write` (`config.egress_requires_write_effect` — also minted, same meaning, for a protocol tool's resolved * axes), a name the run reserves for a tool the engine injects (`config.reserved_tool_name` — structured output, * the skill tool, tool search, the offload reader, an injected protocol tool; `runGoal`'s completion tool, which * refuses before any run). Each ends the run `failed` with the code on `terminal.code`. A caller-shape refusal, not a policy * verdict: none of these is a governance code ({@link GOVERNANCE_CODES}); re-issuing the same declaration * changes nothing. Every mint site at the door types its code against this set. */ export declare const TOOL_DECLARATION_CODES: readonly ["config.tool_mount_denied", "config.tool_roster_bound", "config.tool_name_too_long", "config.tool_contract_too_long", "config.tool_schema_bound", "config.tool_face_invalid", "config.tool_name_invalid", "config.egress_requires_write_effect", "config.reserved_tool_name"]; /** A code in {@link TOOL_DECLARATION_CODES}. */ export type ToolDeclarationCode = (typeof TOOL_DECLARATION_CODES)[number]; /** * The CLOSED registry of reasons a permission-rule sync round may refuse an inbound record or move a * local row into the quarantine area (design/182 §4.3/§5.2/§8.1). Same doctrine as * {@link GOVERNANCE_CODES}: the machine reads THIS table, never free text — "silently dropped" is a * contract violation, so every drop names a registered code and a consumer can branch on it. * * These are DISCLOSURE codes, not subagent error codes: they never enter {@link GOVERNANCE_CODES} * (that table classifies a failed child's error for retry, and its gate enforces a suffix convention * these codes do not carry). The value states which side of the wire loses bytes: * `inbound-refused` = the peer's copy was refused here (the peer still holds it — no loss); * `local-quarantined` = a LOCAL row left the live view into the quarantine area (bytes preserved, * disclosed, re-enterable only through a new consent). */ export declare const RULE_SYNC_DROP_CODES: { /** The single validator refused the rule text (e.g. a bare-interpreter prefix). Both directions. */ readonly invalid_rule_text: "inbound-refused-or-local-quarantined"; /** Stored tool/match/command disagree with the re-projection of the rule text. Both directions. */ readonly metadata_mismatch: "inbound-refused-or-local-quarantined"; /** An inbound dot claims THIS replica's actor above its minted counter — forgery on our own name. * Covers adds, a tombstone's `deletedBy`, AND a tombstone's `removedDots` (a tombstone naming our * future dot would pre-position a kill for an approval not yet given). */ readonly own_actor_forged: "inbound-refused"; /** An inbound add reuses a dot that already identifies a DIFFERENT (rule, scope) row — a dot is * minted once for one add, so a reuse is damage or forgery, and admitting it would let quarantine * or tombstone identity on one row reach the other. */ readonly dot_identity_conflict: "inbound-refused"; /** A live local add at-or-below the collected GC frontier and absent from the inbound state — the * residue of an already-recycled tombstone. Never resurrected; quarantined and disclosed. */ readonly below_gc_frontier: "local-quarantined"; /** The server refused this local row (its response `dropped` names it); it leaves the live view so * it does not ride — and get refused on — every future round. */ readonly server_rejected: "local-quarantined"; /** design/382 §4.3 — the row carries a SESSION scope, which the durable face (store, sync wire, * at-rest bytes) structurally never holds: a session authorization lives in its session's overlay * and dies with it. The row is dropped and disclosed, never landed and never quarantined (the * quarantine area is itself durable — parking a session row there would persist it). Inbound- * refused in every reachable case: the direct write arms refuse session scopes LOUDLY * (`unsupported.session_scope_store`) before one can become local. */ readonly session_scope_not_durable: "inbound-refused"; }; /** Every reason a sync round may drop or quarantine a record. Closed set; free text is not a member. */ export type RuleSyncDropReason = keyof typeof RULE_SYNC_DROP_CODES; /** The subset that may appear on a LOCAL quarantined row (design/182 §8.1 `quarantine` instruction / * fence arm / local screening). `own_actor_forged` is inbound-only by construction; * `session_scope_not_durable` never quarantines — the quarantine area is durable, and a session row * parked there would be a session row persisted (design/382 §4.3). */ export type RuleQuarantineReason = Exclude<RuleSyncDropReason, "own_actor_forged" | "session_scope_not_durable">; /** * WHO a notice code is for. `"user"` = a session-scoped disclosure the end user of that session is * entitled to see (safe to project onto that session's event stream); `"operator"` = a * deployment/config/ops fact for whoever runs the process. * * Two values, deliberately. "Can this notice be routed to a session" is NOT an audience value — it * is the presence of `EngineNotice.sessionId`, a per-EMISSION fact. A third value would fold a * routing property into an entitlement vocabulary, and the two answer different questions: several * codes below carry a session attribution while the person entitled to the fact is still the * operator (a failed offload write, a routing fallback, a consolidation recommendation). */ export type NoticeAudience = "user" | "operator"; /** * The CLOSED catalog of EngineNotice codes — every code this engine mints, plus the few a server mints through the * same sink ({@link NOTICE_MINTER}) — the enumeration half of the presentation registry below, and the thing a * consumer's own audience table can be diffed against (that is the point of exporting it: a downstream table with a * row missing, or a row for a code no longer minted, is a mechanically detectable disagreement rather than an * argument). * * Kept in LOCKSTEP with {@link NOTICE_AUDIENCE} and {@link NOTICE_MINTER} by the compiler (`satisfies * Record<EngineNoticeCode, …>` below: a catalog entry with no row, or a row for a non-member, is a tsc error — a * mirrored enumeration that is only checked at runtime is a mirror that drifts). The other half — "is the catalog * itself still complete?" — cannot be a type: `EngineNotice.code` is declared `string` (a host may forward its own), * so the gate test (governance-codes.test.ts) scans src/ for notice mint shapes and names any code that is minted but * unregistered, an engine-minted code that is no longer minted, or a server-minted code minted here. * * Each row's own story — what fires it, its `detail` shape, its dedup unit and its audience — lives at * the union's catalog ({@link EngineNotice.code}). The groups below say only which family a row joins, * so the catalog is not written a second time here and the two cannot drift. */ export declare const ENGINE_NOTICE_CODES: readonly ["config.autocompact_window_clamped", "config.env_timeout_discarded", "config.materialize_env_discarded", "config.models_swapped", "config.context_settings_swapped", "config.read_face_swapped", "config.read_face_deployment_clamped", "config.write_face_swapped", "config.write_face_deployment_clamped", "config.tool_model_gate_removed", "config.tool_model_gate_unknown_class", "config.tool_model_gate_env_invalid", "config.artifact_host_invalid", "config.task_root_not_canonical", "config.write_protection_target_view_absent", "config.write_protection_unresolved", "config.execution_env_capability_invalid", "config.tool_card_undeclared", "config.tool_face_undeclared", "config.tool_face_invalid", "config.forward_sink_failed", "config.durable_gate_unavailable", "config.peer_admission_out_of_range", "config.peer_lane_unmounted", "config.secret_env_scrubbed", "config.permission_mode_unavailable", "permission.ask_released_by_mode", "permission.read_deny_unapplied", "permission.rule_store_unavailable", "permission.allowed_tool_not_granted", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "classifier.fallback", "classifier.role_defaulted", "classifier.contract_broken", "classifier.unavailable", "checkpoint.execution_outcome_unrecorded", "delegation.transcript_integrity", "delegation.ask_unresolvable", "mcp.injection_dropped", "mcp.revocation_probe_failed", "mcp.server_redialed", "workflow.governance_key_stripped", "workflow.agent_option_ignored", "memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.content_class_declared", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "memory.consolidation_recommended", "memory.consolidation_committed", "memory.consolidation_conflict", "memory.consolidation_incomplete", "memory.consolidation_refused", "memory.consolidation_withheld", "memory.restore_withheld", "memory.project_scope_absent", "route.fallback_to_primary", "route.classifier_unroutable", "route.base_url_changed_key_unchanged", "route.response_model_mismatch", "route.tool_call_id_folded", "context.tool_turn_repaired", "task.user_steer_undrained", "task.user_followup_undrained", "steering.parked_input_blocked", "task.turn_interrupted", "task.halt_unconsumed", "task.late_approval", "task.interrupt_unconsumed", "task.tool_turn_incomplete", "approval.read_root_granted", "approval.read_root_grant_rejected", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "skills.listing_truncated", "agents.listing_truncated", "tool_result.offload_put_failed", "instructions.source_changed", "session.records_skipped", "memory.layer_locked_legacy", "server.model_unreachable"]; /** A catalogued code (see {@link ENGINE_NOTICE_CODES}); {@link NOTICE_MINTER} says who mints it. NOT the type of * `EngineNotice.code`, which stays `string` — a host forwarding its own notices through the same * sink is a supported shape, and narrowing that field would break it. */ export type EngineNoticeCode = (typeof ENGINE_NOTICE_CODES)[number]; /** * The presentation-tier registry (the server's wire whitelist retires into this table once * shipped): one row per {@link ENGINE_NOTICE_CODES} member. Presentation tier is a property of the * CODE (closed set, one code one tier) — never of an individual emission, which is why this is a * registry and not an EngineNotice field. Codes absent from the table (a host's own code forwarded * through the same sink) read as `"operator"`: the conservative default, never push an unclassified * code at an end user. Orthogonal to {@link NON_GOVERNANCE_MEMORY_CODES} (a retry-semantics table, * not presentation). * * The judgment applied per row: WHO IS ENTITLED to the fact, not who could be shown it. A notice * that a session can be attributed to is still an operator's fact when the person who would act on * it runs the deployment — three rows below are exactly that case and say so. */ declare const NOTICE_AUDIENCE_TABLE: { readonly "memory.session_polluted": "user"; readonly "memory.harvest_quarantined": "user"; readonly "memory.delegation_static_mark_waived": "user"; readonly "memory.hold_opened": "user"; readonly "memory.hold_released": "user"; readonly "memory.hold_disposed": "user"; readonly "task.user_steer_undrained": "user"; readonly "task.user_followup_undrained": "user"; readonly "classifier.denial_limit": "user"; readonly "classifier.unavailable": "user"; readonly "classifier.fallback": "operator"; readonly "classifier.role_defaulted": "operator"; readonly "classifier.contract_broken": "operator"; readonly "task.turn_interrupted": "user"; readonly "steering.parked_input_blocked": "user"; readonly "task.halt_unconsumed": "user"; readonly "task.late_approval": "user"; readonly "task.interrupt_unconsumed": "user"; readonly "task.tool_turn_incomplete": "user"; readonly "approval.read_root_granted": "user"; readonly "approval.read_root_grant_rejected": "user"; readonly "config.durable_gate_unavailable": "user"; readonly "config.permission_mode_unavailable": "user"; readonly "permission.ask_released_by_mode": "user"; readonly "permission.read_deny_unapplied": "user"; readonly "permission.rule_store_unavailable": "user"; readonly "permission.allowed_tool_not_granted": "user"; readonly "memory.capture_opted_out": "user"; readonly "memory.capture_optout_unpersisted": "user"; readonly "memory.consolidation_withheld": "operator"; readonly "delegation.ask_unresolvable": "user"; readonly "config.autocompact_window_clamped": "operator"; readonly "config.env_timeout_discarded": "operator"; readonly "config.materialize_env_discarded": "operator"; readonly "config.models_swapped": "operator"; readonly "config.context_settings_swapped": "operator"; readonly "config.read_face_swapped": "operator"; readonly "config.read_face_deployment_clamped": "operator"; readonly "config.write_face_swapped": "operator"; readonly "config.write_face_deployment_clamped": "operator"; readonly "config.tool_model_gate_removed": "operator"; readonly "config.tool_model_gate_unknown_class": "operator"; readonly "config.tool_model_gate_env_invalid": "operator"; readonly "config.artifact_host_invalid": "operator"; readonly "config.task_root_not_canonical": "operator"; readonly "config.write_protection_target_view_absent": "operator"; readonly "config.write_protection_unresolved": "operator"; readonly "config.execution_env_capability_invalid": "operator"; readonly "config.tool_card_undeclared": "operator"; readonly "config.tool_face_undeclared": "operator"; readonly "config.tool_face_invalid": "operator"; readonly "config.peer_lane_unmounted": "operator"; readonly "config.peer_admission_out_of_range": "operator"; readonly "config.secret_env_scrubbed": "operator"; readonly "peer.inbound_disposition": "user"; readonly "peer.held_settled": "user"; readonly "peer.idle_subscription": "user"; readonly "delegation.transcript_integrity": "operator"; readonly "checkpoint.execution_outcome_unrecorded": "operator"; readonly "mcp.injection_dropped": "user"; readonly "mcp.revocation_probe_failed": "operator"; readonly "mcp.server_redialed": "operator"; readonly "workflow.governance_key_stripped": "operator"; readonly "workflow.agent_option_ignored": "operator"; readonly "memory.content_class_declared": "operator"; readonly "memory.consolidation_recommended": "operator"; readonly "memory.consolidation_committed": "operator"; readonly "memory.consolidation_conflict": "operator"; readonly "memory.consolidation_incomplete": "operator"; readonly "memory.consolidation_refused": "operator"; readonly "memory.restore_withheld": "operator"; readonly "memory.project_scope_absent": "operator"; readonly "route.fallback_to_primary": "operator"; readonly "route.classifier_unroutable": "operator"; readonly "route.base_url_changed_key_unchanged": "operator"; readonly "route.response_model_mismatch": "operator"; readonly "route.tool_call_id_folded": "operator"; readonly "context.tool_turn_repaired": "operator"; readonly "skills.listing_truncated": "operator"; readonly "agents.listing_truncated": "operator"; readonly "tool_result.offload_put_failed": "operator"; readonly "config.forward_sink_failed": "operator"; readonly "instructions.source_changed": "user"; readonly "session.records_skipped": "user"; readonly "server.model_unreachable": "user"; readonly "memory.layer_locked_legacy": "operator"; }; /** Compile-time fence: every catalogued code has an audience row (and, via `satisfies`, only those). */ export type AudienceTableCoversEveryNoticeCode = AssertAllKeysHandled<Exclude<EngineNoticeCode, keyof typeof NOTICE_AUDIENCE_TABLE>>; /** * The presentation-tier registry — see {@link NOTICE_AUDIENCE_TABLE} for the per-row judgment. * The exported TYPE stays the open `Record<string, …>` on purpose: a consumer indexing it with a * runtime string (a code off a wire, a host's own) must keep compiling. The lockstep with * {@link ENGINE_NOTICE_CODES} is enforced on the table above, where narrowing costs nobody anything. */ export declare const NOTICE_AUDIENCE: Readonly<Record<string, NoticeAudience>>; /** The audience for `code` — table lookup with the conservative `"operator"` default. */ export declare function noticeAudienceOf(code: string): NoticeAudience; /** * WHO MINTS a catalogued code: `"engine"` = this package (the catalog gate finds its mint site in src/); `"server"` = a * server process that forwards its own notices through the same sink — registered here so its audience comes from * {@link NOTICE_AUDIENCE} like every other row, and NEVER minted by this package (the catalog gate reds a mint site for * one in src/). One code, one minter: a code two processes mint would be two facts under one spelling. * * Member-level exception, stated where a consumer reads the minter: `task.user_steer_undrained` is an engine row, and * its `detail.cause: "crashed"` arm is minted by the server — the engine's process is gone when that loss is counted * (see `USER_STEER_UNDRAINED_CAUSES`). The code keeps one row here and one spelling for both arms. */ export type NoticeMinter = "engine" | "server"; declare const NOTICE_MINTER_TABLE: { readonly "config.autocompact_window_clamped": "engine"; readonly "config.env_timeout_discarded": "engine"; readonly "config.materialize_env_discarded": "engine"; readonly "config.models_swapped": "engine"; readonly "config.context_settings_swapped": "engine"; readonly "config.read_face_swapped": "engine"; readonly "config.read_face_deployment_clamped": "engine"; readonly "config.write_face_swapped": "engine"; readonly "config.write_face_deployment_clamped": "engine"; readonly "config.tool_model_gate_removed": "engine"; readonly "config.tool_model_gate_unknown_class": "engine"; readonly "config.tool_model_gate_env_invalid": "engine"; readonly "config.artifact_host_invalid": "engine"; readonly "config.task_root_not_canonical": "engine"; readonly "config.write_protection_target_view_absent": "engine"; readonly "config.write_protection_unresolved": "engine"; readonly "config.execution_env_capability_invalid": "engine"; readonly "config.tool_card_undeclared": "engine"; readonly "config.tool_face_undeclared": "engine"; readonly "config.tool_face_invalid": "engine"; readonly "config.forward_sink_failed": "engine"; readonly "config.durable_gate_unavailable": "engine"; readonly "config.peer_admission_out_of_range": "engine"; readonly "config.peer_lane_unmounted": "engine"; readonly "config.secret_env_scrubbed": "engine"; readonly "config.permission_mode_unavailable": "engine"; readonly "permission.ask_released_by_mode": "engine"; readonly "permission.read_deny_unapplied": "engine"; readonly "permission.rule_store_unavailable": "engine"; readonly "permission.allowed_tool_not_granted": "engine"; readonly "peer.inbound_disposition": "engine"; readonly "peer.held_settled": "engine"; readonly "peer.idle_subscription": "engine"; readonly "classifier.denial_limit": "engine"; readonly "classifier.fallback": "engine"; readonly "classifier.role_defaulted": "engine"; readonly "classifier.contract_broken": "engine"; readonly "classifier.unavailable": "engine"; readonly "checkpoint.execution_outcome_unrecorded": "engine"; readonly "delegation.transcript_integrity": "engine"; readonly "delegation.ask_unresolvable": "engine"; readonly "mcp.injection_dropped": "engine"; readonly "mcp.revocation_probe_failed": "engine"; readonly "mcp.server_redialed": "engine"; readonly "workflow.governance_key_stripped": "engine"; readonly "workflow.agent_option_ignored": "engine"; readonly "memory.session_polluted": "engine"; readonly "memory.harvest_quarantined": "engine"; readonly "memory.delegation_static_mark_waived": "engine"; readonly "memory.content_class_declared": "engine"; readonly "memory.hold_opened": "engine"; readonly "memory.hold_released": "engine"; readonly "memory.hold_disposed": "engine"; readonly "memory.consolidation_recommended": "engine"; readonly "memory.consolidation_committed": "engine"; readonly "memory.consolidation_conflict": "engine"; readonly "memory.consolidation_incomplete": "engine"; readonly "memory.consolidation_refused": "engine"; readonly "memory.consolidation_withheld": "engine"; readonly "memory.restore_withheld": "engine"; readonly "memory.project_scope_absent": "engine"; readonly "route.fallback_to_primary": "engine"; readonly "route.classifier_unroutable": "engine"; readonly "route.base_url_changed_key_unchanged": "engine"; readonly "route.response_model_mismatch": "engine"; readonly "route.tool_call_id_folded": "engine"; readonly "context.tool_turn_repaired": "engine"; readonly "task.user_steer_undrained": "engine"; readonly "task.user_followup_undrained": "engine"; readonly "steering.parked_input_blocked": "engine"; readonly "task.turn_interrupted": "engine"; readonly "task.halt_unconsumed": "engine"; readonly "task.late_approval": "engine"; readonly "task.interrupt_unconsumed": "engine"; readonly "task.tool_turn_incomplete": "engine"; readonly "approval.read_root_granted": "engine"; readonly "approval.read_root_grant_rejected": "engine"; readonly "memory.capture_opted_out": "engine"; readonly "memory.capture_optout_unpersisted": "engine"; readonly "skills.listing_truncated": "engine"; readonly "agents.listing_truncated": "engine"; readonly "tool_result.offload_put_failed": "engine"; readonly "instructions.source_changed": "server"; readonly "session.records_skipped": "server"; readonly "memory.layer_locked_legacy": "server"; readonly "server.model_unreachable": "server"; }; /** Compile-time fence: every catalogued code has a minter row (and, via `satisfies`, only those). */ export type MinterTableCoversEveryNoticeCode = AssertAllKeysHandled<Exclude<EngineNoticeCode, keyof typeof NOTICE_MINTER_TABLE>>; /** The minter registry — see {@link NoticeMinter}. Frozen: a caller writing a row would move the catalog gate's verdict. */ export declare const NOTICE_MINTER: Readonly<Record<EngineNoticeCode, NoticeMinter>>; export {};