UNPKG

agentfootprint

Version:

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

58 lines (57 loc) • 2.99 kB
/** * identityKey — the conversation a pooled client belongs to, as one key. * * Pattern: the library's one identity encoding, never a second. * Role: The client key is `identityNamespace` of the identity the CALLER * named — each field through `encodeIdentityField`, the encoding the * memory layer calls the tenant boundary. It is injective: tenant * `acme/hr` with principal `alice` and tenant `acme` with principal * `hr/alice` are two keys, and an absent field and a field named `_` * are two keys. A pool is one server, so the key needs no server * segment, and two pools never share a client. * * Two doors only: the run's caller identity (`ToolDispatchContext.callerIdentity`, * `ToolExecutionContext.identity`) and the identity app code passes to `acquire` * and `terminate`. Never tool arguments, model output, a message, a request * body, or a `sessionId` alone. No identity value is ever written to an error, * an event or a report: the wire carries `keyHash`, the tool-session digest. */ import type { McpPoolIdentity } from './options.js'; /** One conversation's key, and the coarser keys its budgets count by. */ export interface PoolKey { /** `identityNamespace` of the identity — the client key. */ readonly key: string; /** The tenant and principal segments — what `maxClientsPerPrincipal` counts by. */ readonly principal: string; /** The tenant segment — always part of a shared definitions context. */ readonly tenant: string; /** The digest the record carries in the key's place. */ readonly keyHash: string; /** The identity itself, as a frozen copy — what the transport factory and `share` are asked with. */ readonly identity: McpPoolIdentity; } /** What an identity must carry. */ export interface IdentityRules { readonly requirePrincipal: boolean; readonly requireTenant: boolean; } /** * The key for `identity`, or why there is none: `'no-identity'` when nothing was * named (a derived identity counts as none), `'incomplete-identity'` when it * lacks a `conversationId`, a required `principal` or a required `tenant`, or a * field is not a string. */ export declare function poolKeyOf(identity: unknown, rules: IdentityRules): PoolKey | 'no-identity' | 'incomplete-identity'; /** * Which keys a scope names. The tenant is matched exactly, always — an absent * tenant is the absent segment, never a wildcard, because the tenant is the * boundary. A scope that names a `conversationId` names exactly that one * conversation (an absent principal is then the absent segment, as in the key). * A scope without one names every conversation of its principal, and a scope * without a principal either names every conversation of its tenant. */ export declare function scopeMatcher(scope: { readonly tenant?: string; readonly principal?: string; readonly conversationId?: string; }): (key: PoolKey) => boolean;