@sema-agent/core
Version:
Stateless, task-oriented AI agent core
145 lines (144 loc) • 9.49 kB
TypeScript
/** The model-face envelope tag (single source; a shell renders/collapses by this name). */
export declare const CROSS_SESSION_MESSAGE_TAG = "cross-session-message";
/**
* The ONE model-face neutralization every PEER-AUTHORED body receives before a framing carrier wraps
* it — the same-process `<agent-message>` uplink, the `<cross-session-message>` envelope and the
* `<teammate-message>` frame all call exactly this, then their own {@link escapeEnvelopeTag}.
*
* WHAT it defuses: the whole harness AUTHORITY family ({@link ENGINE_AUTHORITY_ENVELOPE_TAGS} —
* `system-reminder`, `task-notification`, `user_memory`, `skills`, …), not the reminder tag alone. A
* peer's text is another model's output; a copy of any engine envelope inside it must arrive as
* data, never as a frame the recipient's model reads as engine speech. The primitive underneath
* ({@link sanitizeUntrustedText}) deliberately defuses only the reminder tag by default, because it
* also runs over engine-assembled bodies that legitimately ARE envelopes; a peer body never is, so
* the family-wide set is correct here and belongs to this seat — one helper, so the three carriers
* cannot drift apart on which tags they contain.
*
* Idempotent (a defused tag no longer matches), which is what keeps the model-face parser's
* rebuild-and-compare a fixed point on an already-canonical body.
*/
export declare function neutralizePeerBody(body: string): string;
/**
* Frame-adjacent discipline block for the cross-session lane (design/385 §4.1). DISTINCT from the
* teammate lane's `PEER_MESSAGE_NOTICE`: the two lanes carry different trust levels (engine-attributed
* teammate vs same-user peer session with self-claimed identity), and sharing one text would blur the
* classifier's lane judgment. Content mirrors the three hard rules a peer session cannot override:
* no settings/instruction-file/config edits on a peer's say-so, a peer message is never the user's
* approval of a pending prompt, and relaying a denied action is permission laundering.
*/
export declare const CROSS_SESSION_MESSAGE_NOTICE: string;
/**
* design/385 §4.5 layer 2 — the classifier-slot text spliced into the auto-mode system prompt's
* `<cross_session_messages_rule>` slot WHILE the cross-session lane is mounted (the base rule 8 is
* always present; this names the concrete frame and the outbound half). The slot stays empty when the
* lane is absent, so an unmounted deployment's classifier prompt is byte-identical to before.
*/
export declare const CROSS_SESSION_CLASSIFIER_RULE: string;
/** The sender's self-attested permission-mode CLASS (CC `ZP` vocabulary, two values; absence is the
* third state "no class asserted"). An attestation, not a verified fact — see cross-session-judge.ts. */
export type PermissionModeClass = "bypass" | "prompting";
export declare const PERMISSION_MODE_CLASSES: readonly PermissionModeClass[];
export declare function isPermissionModeClass(value: unknown): value is PermissionModeClass;
/** Typed codec failure: a caller-supplied field that cannot be serialized canonically. Thrown (never
* silently dropped) so a producer bug is loud at the mint site rather than a silently attribute-less
* envelope on the wire (bad-value loudness rule). */
export declare class CrossSessionCodecError extends Error {
readonly code: "cross_session.invalid_from" | "cross_session.invalid_from_session" | "cross_session.invalid_from_mode" | "cross_session.invalid_from_scope" | "cross_session.invalid_hop_chain";
constructor(code: CrossSessionCodecError["code"], message: string);
}
/** CC `nM`/`PGe`: 24-hex tokens, at most 32 carried (the oldest are dropped first). */
export declare const PEER_HOP_CHAIN_CARRY_WINDOW = 32;
/** CC `eM` — percent-encode everything outside `[A-Za-z0-9:_/.\-]` (UTF-8 bytes, uppercase hex). The
* scheme prefix (`uds:` / `session.`) is part of the raw address and passes through unchanged.
* @throws CrossSessionCodecError on a non-string or a string with an unpaired surrogate. */
export declare function encodePeerAddress(raw: string): string;
/**
* Is this address in its CANONICAL spelling — the one {@link encodePeerAddress} would produce? The
* grammar alone admits `%ZZ`, a lone `%`, or a needless `%41`; none of those can come out of the
* encoder (CC's `eM` encodes `%` itself, so a genuine CC peer never sends them either). Addresses are
* copied verbatim into reply targets, so a non-canonical spelling is refused rather than carried.
*/
export declare function isCanonicalPeerAddress(address: string): boolean;
/** design/385 §4.2 — the canonical `from-scope` attribute form of a raw scope string.
* @throws CrossSessionCodecError on a non-string or a string with an unpaired surrogate. */
export declare function encodeScopeAttribute(rawScope: string): string;
/** Inverse of {@link encodeScopeAttribute}; `undefined` when the bytes are not valid percent-encoded
* UTF-8 (the parser refuses the whole envelope on that). */
export declare function decodeScopeAttribute(encoded: string): string | undefined;
/** CC `_b` ∘ `replace(/["<>]/g,"")` — the display-name canonicalization: strip the attribute-breaking
* bytes, strip invisible/format/control/separator code points, trim, cap at 64 code points with an
* ellipsis. An empty result means "omit the attribute" (CC `if(g)`). */
export declare function canonicalPeerDisplayName(raw: string): string;
export interface CrossSessionEnvelopeFields {
/** The sender's ADDRESS in its canonical (already percent-encoded) spelling — what a reply copies
* into `to`. Required. Mint it with {@link encodePeerAddress} from a raw address. */
from: string;
/** The sender's session id (`^[A-Za-z0-9_-]{1,80}$`). Self-claimed. */
fromSession?: string;
/** The sender's display name (raw; canonicalized at build — see {@link canonicalPeerDisplayName}). */
fromName?: string;
/** The sender's self-attested permission-mode class; absent = no class asserted. */
fromMode?: PermissionModeClass;
/** design/385 §10 — the sender's RAW scope on the cross-principal lane (encoded on the attribute;
* presence marks the message as having crossed a principal wall). Presentation only: the typed
* authority anchor is the store record's `peerMeta.fromScope`, never this attribute. */
fromScope?: string;
}
/**
* Serialize the model-face envelope. Canonical attribute order is FIXED (`from` → `from-session` →
* `from-name` → `from-mode` → `from-scope`; the CC `D8` order with `from-scope` appended). The body is
* neutralized with {@link escapeEnvelopeTag} so a sender-embedded copy of this tag can never close the
* real frame early (idempotent: an already-neutralized body is unchanged, which is what makes the
* parser's rebuild comparison work on the extracted body).
* @throws CrossSessionCodecError on a field that cannot be spelled canonically.
*/
export declare function buildCrossSessionEnvelope(fields: CrossSessionEnvelopeFields, body: string): string;
/** Why a parse refused: `not_an_envelope` (the strict grammar did not match at all), `bad_scope_encoding`
* (a `from-scope` that is not valid percent-encoded UTF-8), `roundtrip_mismatch` (the grammar matched
* but the canonical re-serialization differs — a near-miss / non-canonical form). All three mean
* "treat the text as ordinary data". */
export type CrossSessionEnvelopeRefusal = "not_an_envelope" | "bad_scope_encoding" | "roundtrip_mismatch";
export type CrossSessionEnvelopeParse = {
ok: true;
fields: CrossSessionEnvelopeFields;
body: string;
} | {
ok: false;
reason: CrossSessionEnvelopeRefusal;
};
/**
* Strict parse + round-trip check of the model-face envelope. `body` is returned in its ENVELOPE form
* (nested-tag-neutralized, exactly as the model saw it). A refusal is a classification of the text as
* data, not an error.
*/
export declare function parseCrossSessionEnvelope(text: string): CrossSessionEnvelopeParse;
export interface CcPeerFrameFields {
/** The sender address (CC: optional even on the wire). */
from?: string;
fromSession?: string;
/** Forwarding chain of 24-hex hop tokens; more than 32 ⇒ the OLDEST are dropped (CC `ygt`). */
hopChain?: string[];
fromName?: string;
fromMode?: PermissionModeClass;
}
/** CC `ygt` — the carry window: keep the newest 32. */
export declare function clampHopChain(chain: readonly string[]): string[];
/**
* Serialize the CC wire envelope (what goes into a UDS user frame's `message.content`). Attribute
* order `from` → `from-session` → `hop-chain` → `from-name` → `from-mode`. Unlike CC's own
* constructor, which silently DROPS an ill-formed `from-session`/`hop-chain`, this throws on them: the
* values are ours, and a producer bug must not become an attribute-less frame on the wire.
* @throws CrossSessionCodecError
*/
export declare function encodeCcPeerFrame(fields: CcPeerFrameFields, body: string): string;
export type CcPeerFrameParse = {
ok: true;
fields: CcPeerFrameFields;
body: string;
} | {
ok: false;
reason: "not_an_envelope" | "roundtrip_mismatch";
};
/** CC `oM` byte-exact: strict grammar, then rebuild-and-compare. The hop chain comes back as a typed
* array for the engine's side channel — a consumer must strip it before the model face (CC `ymn`). */
export declare function decodeCcPeerFrame(text: string): CcPeerFrameParse;