agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
76 lines • 4.15 kB
TypeScript
/**
* frozenCopyOf — a callback's copy of a value, frozen all the way down.
*
* Role: Support. A leaf: it reads its argument and nothing else.
* Reads: its argument.
* Emits: one dev-mode warning per kind of callback ({@link warnFrozenWrite}).
*
* The boundary between a call's arguments and the app code that looks at them
* before the call runs (a `checkIn` predicate, the evidence assembler, the
* permission checker, a `tool_start` listener). App callbacks are trusted
* code, and trusted code can still be buggy: a predicate that writes into the
* object it was handed would otherwise write into the arguments the tool then
* runs with — after a person approved them, or after the predicate itself
* answered "no check-in needed". So the callback is handed a copy
* (`structuredClone`) that the tool never runs with, frozen at every depth: a
* write to it throws in strict code and is ignored in sloppy code, and either
* way the arguments that run are untouched.
*
* A copy freezing SEALS ({@link isSealed}) cannot change, so ONE is shared by
* every callback and event that sees a call before it runs ({@link frozenView}):
* a large argument is copied once, not once per callback. That is every JSON
* value — all a model ever proposes. A copy holding a container `Object.freeze`
* cannot seal — a `Map` or `Set` (their own `set`/`add`/`delete`), a `Date`
* (its setters), an `ArrayBuffer` or a typed array or view (their bytes) — is
* NOT sealed: one callback could still change what the next one judges, so
* such a copy is never shared and each callback is handed its own. (Refusing
* such arguments instead would break a tool an app hands a `Date` or a `Map`
* through its own provider or middleware; a copy per callback costs only those
* calls their extra copies.) A `SharedArrayBuffer` is shared, not copied, by
* `structuredClone` — its bytes would be every copy's and the tool's — so each
* one (and every view over one) is copied into a plain buffer first.
*
* `undefined` when no copy can be made (a function, a symbol, a foreign proxy
* — what `structuredClone` refuses). The caller decides what that means, and
* fails closed: a consent gate trips, a permission check denies.
*
* Never throws.
*/
export declare function frozenCopyOf<T>(value: T): T | undefined;
/**
* A frozen, detached projection of `value` for an event that must carry
* SOMETHING when no copy can be made ({@link frozenCopyOf} gave `undefined`):
* what JSON writes down of it (a function is dropped), or a frozen empty
* object when JSON cannot write it either. Never a live object of `value`.
*/
export declare function frozenProjectionOf<T>(value: T): T;
/**
* Whether `value` is (part of) a copy {@link frozenCopyOf} made that freezing
* sealed — nothing in it can change, so it may be shared between callbacks.
* `false` for a copy holding a container freezing cannot seal (a `Map`, a
* `Set`, a `Date`, an `ArrayBuffer`, a typed array or view), and for any value
* this module did not copy.
*/
export declare function isSealed(value: unknown): boolean;
/**
* `value` itself when it is already (part of) a sealed copy ({@link isSealed}),
* so sharing it is safe — else a new copy, which is the caller's alone when it
* holds a container freezing cannot seal.
*/
export declare function frozenView<T>(value: T): T | undefined;
/**
* Whether `error` is what strict code throws on a write to a frozen object —
* the engines' own words for assigning a read-only property, adding to an
* object that is not extensible, deleting or redefining a property.
*/
export declare function isFrozenWriteError(error: unknown): boolean;
/**
* In dev mode, once per kind of callback: say that `who` wrote into the frozen
* copy it was handed, and what that did (`consequence`). A no-op for any other
* error, outside dev mode, and after the first warning for `who`.
*
* @example
* warnFrozenWrite('permission checker', err, 'the call was denied');
*/
export declare function warnFrozenWrite(who: string, error: unknown, consequence: string): void;
//# sourceMappingURL=frozenCopy.d.ts.map