UNPKG

agentfootprint

Version:

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

99 lines • 4.59 kB
"use strict"; /** * 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. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.scopeMatcher = exports.poolKeyOf = void 0; const encode_js_1 = require("../../memory/identity/encode.js"); const types_js_1 = require("../../memory/identity/types.js"); const toolSessions_js_1 = require("../../tools/toolSessions.js"); /** * 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. */ function poolKeyOf(identity, rules) { if (identity === undefined || identity === null) return 'no-identity'; if (typeof identity !== 'object' || Array.isArray(identity)) return 'incomplete-identity'; const raw = identity; const fields = {}; for (const name of ['tenant', 'principal', 'conversationId']) { let value; try { value = raw[name]; } catch { return 'incomplete-identity'; } if (value === undefined || value === null || value === '') continue; if (typeof value !== 'string') return 'incomplete-identity'; fields[name] = value; } if (fields.conversationId === undefined) return 'incomplete-identity'; if (rules.requirePrincipal && fields.principal === undefined) return 'incomplete-identity'; if (rules.requireTenant && fields.tenant === undefined) return 'incomplete-identity'; const named = Object.freeze({ conversationId: fields.conversationId, ...(fields.tenant !== undefined && { tenant: fields.tenant }), ...(fields.principal !== undefined && { principal: fields.principal }), }); const key = (0, types_js_1.identityNamespace)(named); const tenant = (0, encode_js_1.encodeIdentityField)(named.tenant); return { key, principal: `${tenant}/${(0, encode_js_1.encodeIdentityField)(named.principal)}`, tenant, keyHash: (0, toolSessions_js_1.hashSessionKey)(key), identity: named, }; } exports.poolKeyOf = poolKeyOf; /** * 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. */ function scopeMatcher(scope) { const tenant = (0, encode_js_1.encodeIdentityField)(scope.tenant); if (scope.conversationId !== undefined && scope.conversationId !== '') { const exact = (0, types_js_1.identityNamespace)({ conversationId: scope.conversationId, ...(scope.tenant !== undefined && { tenant: scope.tenant }), ...(scope.principal !== undefined && { principal: scope.principal }), }); return (key) => key.key === exact; } if (scope.principal !== undefined && scope.principal !== '') { const principal = `${tenant}/${(0, encode_js_1.encodeIdentityField)(scope.principal)}`; return (key) => key.principal === principal; } return (key) => key.tenant === tenant; } exports.scopeMatcher = scopeMatcher; //# sourceMappingURL=identityKey.js.map