UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

76 lines (75 loc) • 6.21 kB
import { type RedactionReport } from "./redaction-passes.js"; export type { RedactionFinding, RedactionReport, RedactionConfidence, RedactionSource, SummarizableFinding, } from "./redaction-passes.js"; export { summarizeRedactions } from "./redaction-passes.js"; /** * Every exit that redacts — into a model's context, a host's event or error lane, a log line, a person's screen — does it * with ONE pass, its tier's, and nothing else redacts: a text through {@link egressText}, a thrown value's text through * {@link egressThrownText}, a value with members (a thrown error, a marks bag) through {@link egressValue}, which runs the * same pass over every string member. What comes out is an {@link Egress}: a string the type checker knows came out of * that tier. What a tool RETURNS is its content, read by the model that asked for it, and is not redacted (CC redacts * nothing there either); what is redacted is what the engine itself words or carries: errors, summaries, run rows. * * Two tiers, because the faces have two audiences (CC 2.1.212 alignment): * - **`same-principal`** — the model, the script and the host that launched the work (tool results, workflow agent * outputs / results / errors, run rows behind the scope-gated observe API, host error lanes): the credential * vocabulary only. Paths and URLs in a worker's answer are the caller's OWN machine's paths — redacting them killed the * cross-agent assertion pattern ("return the file you wrote" → `[redacted-path]`) while protecting no one; * cross-tenant isolation on these faces is ACCESS CONTROL (scope gates), not string surgery. CC redacts nothing here; * sema keeps the credential pass as a declared superset. * - **`human`** — text shown to a person or exported beyond the launching principal: the credential vocabulary plus * every URL and absolute path — host internals, and exfil-lure links in untrusted text. * {@link untrustedEgressForHuman} additionally FENCES its text (design/97 CORE-2), so untrusted content cannot pose as * instructions to its reader. */ export type EgressTier = "same-principal" | "human"; declare const EGRESS_TIER: unique symbol; /** A string that came out of tier `T`'s pass. Only this module mints one. */ export type Egress<T extends EgressTier> = string & { readonly [EGRESS_TIER]: T; }; /** Tier `tier`'s one pass over a text. */ export declare function egressText<T extends EgressTier>(tier: T, text: string, report?: RedactionReport): Egress<T>; /** The text a thrown value reads as (`thrownText`), through tier `tier`'s pass: the one form a thrown value's words take * on their way out of the engine. */ export declare function egressThrownText<T extends EgressTier>(tier: T, err: unknown): Egress<T>; /** The `same-principal` tier's pass, under the name hosts call it by (the engine calls {@link egressText}). */ export declare function redactSecrets(s: string, report?: RedactionReport): Egress<"same-principal">; /** * An extension's own words — its registration name, a bus reason, a key it wrote — made fit for an operator line: the * `same-principal` egress pass first, then one line and bounded. The pass runs before the cut, so a cut never leaves part * of a credential the pass would have recognised whole. Every station sentence that carries such words reads them here. * It lives beside the pass, not in the stations module: a value import of the stations graph from a station's consumer * closed a load-order cycle through the fs tools' barrel (an export the barrel copied before it existed). */ export declare function extensionWords(s: string, max: number): string; /** The `human` tier's pass, under the name hosts call it by (the engine calls {@link egressText}). */ export declare function redactHostLeaks(s: string, report?: RedactionReport): Egress<"human">; /** * Tier `tier`'s pass over every string member of `value`, returned as a DATA SNAPSHOT — never the value itself, so nothing * that leaves can run the value's code again (a getter, a serializer, a proxy trap): a host's serializer, a log's inspector * and the loop's own readers (`thrownText`, `thrownMarksOf`) reach what was read, once, and passed. The rules, one each: * - a string goes through {@link egressText}, and so does every member NAME; a function is code, not data, and is not * carried at any depth (the value handed in included: it comes back `undefined`); any other primitive is itself; * - an error (any realm, any class) is re-minted as a plain `Error` — never on the thrown value's prototype, whose * serializers and accessors would run again — carrying EVERY own member (`message`, `stack`, `cause`, `errors`, * `details`, `code` …) and its `name`, `message`, `code` and `stack` read once through its chain, all as own data; * - any other object is what JSON reads: its `toJSON(name)` when it has one (a `URL` is its `href`, a `Date` its ISO * text; one that answers itself is read for its members), otherwise its own enumerable members; * - a member whose name is a credential name (the vocabulary's record-key view: `password`, `Authorization`, * `x-api-key`) and whose reading is a string is the marker whole; * - cycles and shared members stay shared on the snapshot. */ export declare function egressValue<T extends EgressTier, V>(tier: T, value: V): V; /** The `same-principal` tier's pass + size-bound (NO injection fence): workflow outputs/results/errors riding back to * the launching model/script, run rows behind scope-gated observe. Paths/URLs survive (the assertion pattern depends on * them); secrets never do. */ export declare function boundedRedactedSummary(value: unknown, max: number): Egress<"same-principal">; /** * The FULL untrusted-egress transform (design/97 CORE-2): the `human` tier's pass + size-bound + FENCE. Use * for any worker prompt/output (#5 transcript) or steer content (#6) shown to a HUMAN or exported beyond the * launching principal, so untrusted text can neither leak host internals nor pose as instructions. */ export declare function untrustedEgressForHuman(value: unknown, opts: { label: string; max: number; }): Egress<"human">;