UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

46 lines (45 loc) • 3.46 kB
/** * The one reading of a {@link ToolSpec} object. A spec is the caller's own mutable object graph, and the factory and the * run's roster snapshot both turn it into something that outlives the moment it was read; each takes its copy through * here, so a member is read once, by name, through an ordinary property read (an inherited, non-enumerable or * Proxy-answered declaration included — how every phase reads a declaration), and the copy holds no object the caller can * reach: declaration data (lists, schemas, faces, hints) is copied level by level — own string AND symbol keys, so a * TypeBox schema keeps its kind marks — and frozen, and the only values kept by reference are the functions a ToolSpec * declares as functions ({@link FUNCTION_MEMBERS}). * * A declaration the copy cannot take is refused, naming the member path, with the declaration door's code: a function inside * data, an object with a prototype (a class instance, a Date, a Map), an accessor, a graph past the node or depth budget. * A tool-name list is the one lenient place, and only at the places its judge reads one ({@link NAME_LIST_MEMBERS}, * {@link FACE_LIST_KEYS}): it is taken through the judge's own snapshot ({@link snapshotToolNameList}), so a container that * cannot be read becomes the judge's failure marker and an entry the copy cannot take stands in as an inert value of the same * JS type — the judge refuses either with the sentence it always had, without the caller's object ever being on the face. */ import type { ToolSpec } from "./tool-spec.js"; /** Every {@link ToolSpec} member, by name — the type's own key set, fenced both ways (a member added to `ToolSpec` and not * listed here, or a name here that `ToolSpec` does not declare, is a compile error). */ export declare const TOOL_SPEC_MEMBERS: readonly string[]; /** One copy's ledger: the nodes charged so far (a value is a node; a container is charged for all its slots / keys when it is * entered, before anything is allocated, and its children are not charged again), the source objects already copied (a graph * that shares a sub-node copies it once and charges it once — strict and lenient copies kept apart) and the sources being * copied now (a cycle is refused). */ export interface CopyState { nodes: number; readonly seen: WeakMap<object, object>; readonly seenLenient: WeakMap<object, object>; readonly inflight: Set<object>; } export declare const newCopyState: () => CopyState; /** One member's value, as the face and the factory's copy hold it. `state` is the ledger of the whole spec / entry. */ export declare function frozenMember(name: string, value: unknown, state: CopyState): unknown; /** A value under a key that is no ToolSpec member (a contract symbol, a decoration): the engine reads no declaration off it, so * it is carried when it is plain data and left off the face when it is not. */ export declare function frozenExtra(key: string, value: unknown, state: CopyState): { kept: true; value: unknown; } | { kept: false; }; /** A spec as it stands now: a frozen object holding each {@link TOOL_SPEC_MEMBERS} member as read once (a member the spec does * not answer for stays absent). The caller keeping its own object and changing it afterwards — a member, or anything inside a * list or a schema — changes nothing here. */ export declare function frozenToolSpec<T extends ToolSpec>(spec: T): Readonly<T>;