agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
45 lines (44 loc) • 2.65 kB
TypeScript
/**
* plainData — copy the JSON data domain out of an untrusted value.
*
* MCP `structuredContent` arrives from a transport the library does not own,
* so the value may be anything: a class instance, a Proxy, an object with
* getters, or a plain object built in another realm (jest's environment,
* `node:vm`, an iframe). This module answers one question — is this plain JSON
* data? — and, when it is, hands back a COPY made of this realm's own objects
* and arrays, built from property descriptors read once each.
*
* Why a copy rather than the value itself: whatever the source does after it
* was checked (a Proxy trap that redefines a property it already reported, a
* foreign prototype whose methods were replaced) cannot reach the copy. The
* copy keeps every own key as a data property (`__proto__` included), keeps a
* null prototype null, and holds nothing else: no getter, no foreign prototype, no Proxy.
*
* Plain objects and arrays are recognised by STRUCTURE, not by identity with
* this realm's `Object.prototype`, because each realm has its own intrinsics:
*
* - `Object.prototype` of a realm: its own prototype is null;
* - `Array.prototype` of a realm: an array whose own prototype is a realm's
* `Object.prototype`;
* - its own `constructor` is a data property holding that realm's native
* `Object` / `Array` (source text `function Object() { [native code] }`),
* whose own `prototype` data property points straight back at it — a link
* a user-made object or a Proxy cannot forge, because a native
* constructor's `prototype` is non-writable and non-configurable;
* - it carries the same own keys as this realm's intrinsic, each with the
* same descriptor kind (data or accessor), so an added getter is refused;
* - `Object.prototype.toString` names it `[object Object]` / `[object Array]`.
*
* Only descriptors are read: no getter, `toJSON` or `valueOf` runs. A Proxy is
* refused before any trap runs wherever the runtime can say what a Proxy is
* (Node's `util.types.isProxy`, reached through `process.getBuiltinModule` at
* call time, so nothing is imported and the module stays browser-clean).
* Elsewhere a Proxy's traps answer the walk like any object's descriptors do,
* and only what they answered reaches the copy.
*/
/**
* A copy of `value` when it is a JSON object (not an array, not a scalar)
* within the bounds, made of this realm's objects; `undefined` otherwise.
* Never throws for a hostile value: any trap or check that throws refuses.
*/
export declare function copyJsonObject(value: unknown): Record<string, unknown> | undefined;