UNPKG

agentfootprint

Version:

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

94 lines (93 loc) • 4.52 kB
/** * pooledClient — one client INCARNATION: the conversation it serves, the plan it * was opened from, its leases, its own tool list, and where it is in its life. * * Pattern: a plain record the pool owns; no behaviour beyond its own counters. * Role: § 5 of the design. A client is OPENING until its open settles, OPEN * while it can serve, ENDING from the decision to end it until that * ending's work has settled, then ENDED. It is BUSY while any lease is * open — the library's, one per operation, or the app's — while an * operation that waited for its open has not yet taken its lease (a * RESERVATION), and while it opens; IDLE otherwise. A busy client is * never evicted, closed for idleness or ended. "Used" is the last lease * taken or released. * * Its `clientId` is the pool's own random id; its `generation` counts the key's * incarnations (1 = the key's first client). A replacement is a new record with * a new id, a new list and a count of its own: nothing of an old incarnation * can match it. */ import type { McpClient, McpTerminateOutcome } from '../types.js'; import type { ClientPort } from '../clientPort.js'; import type { RequestGuard } from '../requestGuard.js'; import { DefinitionList } from './definitions.js'; import type { PoolKey } from './identityKey.js'; import type { ClientPlan } from './plan.js'; import type { Work } from './work.js'; /** Where a client is in its life. */ export type ClientState = 'opening' | 'open' | 'ending' | 'ended'; /** Why a client ended — the record's `reason`. */ export type EndReason = 'idle' | 'evicted' | 'terminated' | 'closed' | 'expired' | 'handle-lost' | 'abandoned-open'; /** One client incarnation. */ export declare class PooledClient { readonly key: PoolKey; readonly plan: ClientPlan; /** 1 = the key's first client, 2 = its first replacement, … */ readonly generation: number; readonly clientId: string; state: ClientState; /** The ordinary `McpClient`, once opened. */ client: McpClient | undefined; /** The port back (`clientPort.ts`), once opened. */ port: ClientPort | undefined; /** Open leases: one per library operation, one per app lease. */ leases: number; /** * Operations waiting for its open, each holding it until it takes its lease — * so between the open settling and that lease nothing can evict or end it. */ reserved: number; /** The last lease taken or released, on the pool's clock. */ usedAt: number; /** No new lease: `terminate` named it, its session expired, or its handle was lost. */ closedToNew: boolean; /** Its open ran past `initTimeoutMs`: refused to every waiter, still counted until it settles. */ abandoned: boolean; /** Waiting for an ending slot and an operation slot, and why. */ deferredEnd: EndReason | undefined; /** This incarnation's own tool list. */ readonly list: DefinitionList; /** * The guard of the open, listing or ending in progress on this client — what * a request that is not a pooled tool call is checked against and counted by. */ phase: RequestGuard | undefined; /** The open in flight, with the work it owns. */ opening: { readonly ready: Promise<void>; readonly work: Work; readonly startedAt: number; } | undefined; /** How long the open took, once it settled within its deadline. */ initMs: number | undefined; /** Why it left its key without an ordinary ending: its session expired, or its handle was lost. */ lost: 'expired' | 'handle-lost' | undefined; /** The outcome of its ending, once one started. */ endingOutcome: Promise<McpTerminateOutcome> | undefined; /** * The definitions context its tools are served under now. It starts as its * plan's; the app's `share` is asked again at every use, and a changed answer * moves it here — its connection, the plan's transport, never changes. */ definitions: { readonly context: string; readonly shared: boolean; }; constructor(key: PoolKey, plan: ClientPlan, /** 1 = the key's first client, 2 = its first replacement, … */ generation: number, now: number); /** Busy: a lease is open, an operation holds it between its open and its lease, or it is still opening. */ get busy(): boolean; /** Can it serve a new lease right now? */ get serving(): boolean; }