UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

154 lines (153 loc) • 7.98 kB
/** * memberRun — WHO a composition member runs for: the run that mounted it. * * ── The defect this closes ─────────────────────────────────────────────────── * A composition (`Sequence`, `Parallel`, `Conditional`, `Loop`, `Workflow`, * `Graph`) mounts each member's chart in ITS OWN executor; the member's * `run()` never runs. So a member agent's per-run facts — the memory * namespace, a tool's `ctx.identity`, `ctx.runId` — were read off the member * INSTANCE, which every run of the composition shares: `'pending'` for an * instance never run on its own (one memory for every user of the * composition), or the last direct run's caller (another person's identity). * * ── The rule ───────────────────────────────────────────────────────────────── * The run decides, and only the engine can name it. The OUTERMOST * composition's `run()` OPENS one run — the identity its caller named, or * none, and that run's own id — in this module's private registry, and hands * its members only an unguessable LINK to it (`withParentRun`), nesting * included. A member agent looks the run up by that link (`stages/seed.ts`): * the caller's identity when one was named, else the run's own per-run * conversation `{ conversationId: runId }` — never a value its instance * holds, and never a run-shaped value it was handed: a `parentRun` that is not * a live link is refused by name (`ParentRunRefusedError`). A member mounted * where no run reaches it is refused too (`MemberIdentityError`). * * Per-run args are the carrier because they are the one thing two overlapping * runs of one composition cannot share. * * Pattern: value object + pure helpers. Role: core, run identity. */ import type { MemoryIdentity } from '../memory/identity/types.js'; import type { RequestContext } from '../identity/requestContext.js'; /** The state key a runner keeps the run it serves under. */ export declare const MEMBER_RUN_KEY = "memberRun"; /** The run a member is mounted in. */ export interface ParentRun { /** The outermost run's id — the member's `ctx.runId`, and its conversation when no identity was named. */ readonly runId: string; /** The identity the outermost run's caller named, if any. */ readonly identity?: MemoryIdentity; } /** * A run as a runner's state records it: the run, and the LINK that names it in * this module's registry. Only the link travels to members; what a member runs * for is looked up here, never read off what it was handed. */ export interface ParentRunRecord extends ParentRun { readonly link: string; } /** * A `parentRun` that is not a live link this module issued — forged, copied * from another run, or a run already over. Refused, never used. */ export declare class ParentRunRefusedError extends Error { readonly code: "ERR_PARENT_RUN_REFUSED"; constructor(door: string); } /** * Open the run a top-level composition run hands its members, and register it. * Close it with {@link closeParentRun} when the run returns (finished or paused). * * @throws TypeError (from `assertIdentityShape`) when `identity` is not one. */ export declare function openParentRun(runId: string, identity: MemoryIdentity | undefined, door: string, request?: RequestContext): ParentRunRecord; /** * Re-open, for a resumed leg, the run a paused composition was running — read * off the checkpoint's own state (the checkpoint is the record of that run; a * host keeps it server-side or signs it, as for every resume). `undefined` * when the paused run recorded none. */ export declare function reopenParentRun(sharedState: unknown, door: string, request?: RequestContext): ParentRunRecord | undefined; /** Release a run this module opened (`openParentRun` / `reopenParentRun`). */ export declare function closeParentRun(record: ParentRunRecord | undefined): void; /** * The request a live link's run serves, or `undefined` — for a dead link, a * value that is not a link, or a run opened without one. */ export declare function requestOfLink(link: unknown): RequestContext | undefined; /** * The request a member's stage serves, read from the stage's own input: the * request of the run its `parentRun` link names. A member with no link (a * chart a caller built and runs itself) serves NO request — never the * request of whatever run its instance is in elsewhere. */ export declare function memberRequestIn(scope: object): RequestContext | undefined; /** * A resume names a request while the run it resumes is still open under * another — its members would serve two requests. Refused before anything runs. */ export declare class ResumeRequestConflictError extends Error { readonly code: "ERR_RESUME_REQUEST_CONFLICT"; constructor(door: string); } /** The run a live link names, or `undefined`. */ export declare function runOfLink(link: unknown): ParentRun | undefined; /** * The run a runner was handed in its input, looked up by its link; `undefined` * when the input carries none. * * @throws ParentRunRefusedError when a `parentRun` is present but is not a live * link — a member never runs under a run it cannot prove. */ export declare function resolveParentRun(args: unknown, door: string): ParentRunRecord | undefined; /** * Register a runner that reads `parentRun` from its input — `Agent` and the * compositions call this in their constructors. Every other runner is handed * the input it always was, byte for byte. */ export declare function readsParentRun(runner: object): void; /** * A member's input with the LINK of the run it is mounted in — what every * composition's input mapper returns — for a runner that reads it; the input * unchanged for any other runner, or when there is no run to hand down. */ export declare function withParentRun<I extends object>(input: I, record: ParentRunRecord | undefined, runner: object): I | (I & { readonly parentRun: string; }); /** * A composition's seed: resolve the link it was handed — its own `run()` * opened one; a parent composition's mapper hands one down — and keep the run * in its state, under {@link MEMBER_RUN_KEY}, for its input mappers to hand on * (a run's input is not part of the state an input mapper reads). Written only * when there is one. * * @throws ParentRunRefusedError for a link that is not live. */ export declare function adoptParentRun(scope: object, args: unknown, door: string): void; /** The run a runner's state carries (`adoptParentRun`, or an agent's seed), for its input mappers. */ export declare function parentRunIn(state: unknown): ParentRunRecord | undefined; /** * What an inner mount of a member agent is handed of its run: the link, or — * for a chart a caller built — the identity it was given. Nothing on the * agent's own runs. */ export declare function memberRunArg(record: unknown): { readonly parentRun?: string; readonly memberIdentity?: MemoryIdentity; }; /** * The identity a member's stage runs for, read from the stage's own input: * the run its link names, else the identity a caller-built chart handed it. */ export declare function memberIdentityIn(scope: object): MemoryIdentity | undefined; /** The memory namespace a member runs under: the named identity, else the run's own conversation. */ export declare function memberIdentityOf(parentRun: ParentRun): MemoryIdentity; /** * A member mounted where no run reaches it — another runner's executor is * running this agent's chart, and neither a `parentRun` nor an `identity` * arrived in its input. Refused rather than run under its instance's last run. */ export declare class MemberIdentityError extends Error { readonly code: "ERR_MEMBER_NO_IDENTITY"; constructor(); }