UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

95 lines (94 loc) • 7.39 kB
/** * The ONE receipt of a caller's object: how a value someone else's code built becomes a value the receiver owns. * Every reader of a caller's object reads it here — a constructor's configuration (`new Runner`'s deps, a brain's * config), a station's answer record, a mods handler's payload and answer — each with its own mode, never its own * copy of the walk. * * The walk: a primitive is itself. A CONTAINER — an ordinary record (prototype `Object.prototype` or none) or an * ordinary array — within `depth` levels is copied member by member off its own property descriptors, captured in * one call before any of the caller's code can run; each member lands as an enumerable data property of the copy (a * defined property, never an assignment, so an own `__proto__` key stays a plain key). Anything else — a function, an * object of another prototype, a container past `depth` — is handed as it is, refused, or (an object of another * prototype under `copy`) copied off its own members like a record, by `others`, which also says whether cycles and * shared references keep their shape or are refused / walked again. A refusal refuses the whole receipt, or — under * `contain` — only the member it was met in. The walk keeps its own stack (one frame per container being copied), so * neither how deep a value nests nor how deep its caller already stands decides a verdict: only `depth` does. * * Zero-dependency on purpose (this folder compiles on its own): a Proxy cannot be recognised from here, so the * host passes its probe (`isProxy`); with a probe, a Proxy is refused before anything is asked of it. */ /** How a receipt reads. */ export interface ReceiptMode { /** * `call-once`: every own string-keyed member is read — a data property's value, or an accessor's getter called exactly * once on the object (a getter that throws refuses the receipt; one that moves the object's prototype refuses it, but * under `others: "copy"`). * `refuse`: only own enumerable string-keyed DATA properties are members; an accessor, a non-enumerable property or * a symbol-keyed one refuses the receipt (no getter ever runs). */ readonly accessors: "call-once" | "refuse"; /** How many levels of containers are copied (`Infinity` = every level). */ readonly depth: number; /** What a value that is not copied is (a function, another prototype, a container past `depth`, a symbol or a * bigint): handed as it is, or a refusal of the receipt. Shared references keep their shape in the copy (one copy * each); under `as-is` a cycle does too, under `refuse` a cycle is refused and a shared reference must fit `depth` * where it sits each time it is met. `copy` is `refuse`, except that an object of another prototype within `depth` * — a class instance, another realm's object or array, an array of a subclass — is copied as an ordinary record (an * array as an ordinary array) off its OWN members: its prototype is not kept and no code of the prototype runs, so a * prototype's getters and a built-in's internal state (a `Date`'s time, a `Map`'s entries) are not members and are * not copied, while every own data member is (and an own accessor is read as `accessors` says; one that moves the * object's prototype changes nothing the copy holds). A Proxy and a cycle are still refused. */ readonly others: "as-is" | "refuse" | "copy"; /** `refuse`: a container (an ordinary record or array) past `depth` refuses the receipt (`too-deep`) even where * `others` hands other values as they are — a value of another kind there is still what `others` says — and a shared * reference must fit `depth` where it sits each time it is met, by the height its first walk found (a walk that ran * into a container still being walked — a cycle — counts that container as one level, and so does an object the * reader holds, met directly or in what holds it): `depth` is a bound, never a copy depth. Absent ⇒ a container past * `depth` is what `others` says. */ readonly past?: "refuse"; /** A fault met in a member — its getter threw, it is a value the receipt refuses, it holds a cycle, it runs too deep, * or it could not be copied at all (`uncopyable`) — leaves THAT member out of its container's copy and is reported in the * receipt's `faults` (where it was met); the walk goes on with the next member. A container refused where it was met * is refused again wherever else it is met (never read twice). Only a fault of the received value itself refuses the * receipt. Absent ⇒ the first fault refuses the receipt. */ readonly contain?: true; /** Every container the copy makes is frozen (a received value cannot be changed after it was received). */ readonly freeze?: boolean; /** The host's Proxy probe. */ readonly isProxy?: (value: object) => boolean; } /** Why a receipt was refused. `uncopyable` has two causes, and depth is neither (the walk keeps its own stack): reading * the value threw where none of its getters runs — a Proxy's trap, on a receipt given no Proxy probe; what it threw is * never read — or the value holds more objects than one receipt can index. */ export declare const RECEIPT_FAULTS: readonly ["proxy", "accessor", "hidden", "getter-threw", "prototype-moved", "not-data", "cycle", "too-deep", "uncopyable"]; export type ReceiptFaultKind = (typeof RECEIPT_FAULTS)[number]; /** A refusal and where in the value it was met (member names from the top). */ export interface ReceiptFault { readonly kind: ReceiptFaultKind; readonly path: readonly string[]; } /** A receipt: the copy (with, under `contain`, every fault a member was left out for), or the refusal. */ export type Receipt = { readonly ok: true; readonly value: unknown; readonly faults?: readonly ReceiptFault[]; } | { readonly ok: false; readonly fault: ReceiptFault; }; /** Whether `v` is an ordinary record: an object whose prototype is `Object.prototype` or none (an array is not one). */ export declare function isPlainRecord(v: unknown): v is Record<string, unknown>; /** * Receive `value` by `mode`. `held` names objects the reader already owns: met in the walk, each is kept as itself — not * received again, never walked — so a member handed back unchanged keeps its identity. The set is consulted as it is, * never copied, so one set serves every receipt of the same owner. */ export declare function receive(value: unknown, mode: ReceiptMode, held?: ReadonlySet<object>): Receipt; /** The mods bus's mode: a payload and an answer received whole — no accessor runs, no depth limit, cycles and shared * references kept, a function or a class instance handed as it is, every copied container frozen (so a member the * bus holds cannot be changed under it by a handler that holds it too). The engine's own event is received in it as it * is; what a handler gives the bus — a payload, an answer, a `$` call's arguments — in it held to the bus's one depth * (the site rules set `depth` and `past: "refuse"`). */ export declare const MODS_PAYLOAD_MODE: ReceiptMode; /** One clause naming a fault for a sentence ("an accessor at input.deep.x"). */ export declare function describeFault(fault: ReceiptFault): string;