UNPKG

agentfootprint

Version:

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

123 lines (122 loc) • 6.54 kB
/** * conversationRedaction — the names an agent's record carries the * conversation under, as one footprintjs `RedactionPolicy`. * * Pattern: a vocabulary the library owns, handed out as data (a policy), with * the caller's own selectors joined on (`unionRedactionPolicies`). * Role: the Map half of `src/redaction/` for the question "what do I name * to keep the conversation out?" — `Agent.create({ redact })` is the * one door; this is the value most callers hand it. * * WHY THE LIBRARY OWNS THE LIST. footprintjs selects by NAME: a policy keeps a * value out of every record when it names the state key, or the event field * (at any depth), the value travels under. An agent's record carries the * conversation under many names, nearly all of them the library's own — the * person's message, the model's words and thinking, tool arguments and * results, what memory and retrieval recalled, what was injected into the * model's context, a paused call's arguments, the draft a schema check * rejected. A caller cannot be expected to know them; the library can, and * `test/redaction/agent-redaction.vocabulary.test.ts` runs each feature listed * in `CONVERSATION_FEATURES` with a canary in every place the conversation * goes, and fails when a canary reaches any record. * * WHAT IS NOT ON IT, by design: * - values an app's own tools or rules put in the record under names of * their own (a tool's result is covered by `result`, but a field inside an * event your middleware emits is yours to name) — join them: * `conversationRedaction({ patterns: [/ssn|email/i] })`; * - error text written by code (`error`, `errorMessage`, `lastError`): a * message a tool or provider throws can quote what it failed on, and * `error` also names a flag the record's readers count on * (`stream.tool_end`'s `error: true`). On an EVENT it is kept out anyway, * under ANY policy: the value-kind rule serves every string that is not a * library word as the placeholder (`knownStrings.ts`) — a parser message * that quotes the model's draft included. In STATE the name is yours to * add; * - structure: counts, kinds, flags, timings and verdict words stay * readable — the record still shows WHAT happened, without the words; * - content the library quotes under names of its own (a validation issue's * quoted argument, a check-in's evidence pack, a matcher's witness, a * route guard's judged result, the words of a tool's coverage declaration * and a described result's data on their events, …) is not named here: * generic names (`value`, `text`, `note`, `checked`) would hide structure * across every event. On events it is kept out under ANY policy by the * value-kind rule (`knownStrings.ts`): no string survives that is not a * library word. * * Names it shares with structure, kept out with it: `permission.check`'s * `result` (its verdict word — a refused call still reads as refused, from * `stream.tool_end`'s `notExecuted`). */ import type { RedactionPolicy } from 'footprintjs'; import { type CarriedRedactionPolicy } from './policy.js'; /** The features whose records the vocabulary is proven against, by the test above. */ export declare const CONVERSATION_FEATURES: readonly string[]; /** * The vocabulary's VERSION — derived from its own contents (every key, pattern * and field selector, sorted), so it changes whenever the list does and never * waits on a hand bump. A carried policy that keeps the conversation out * records the version it was built under (`carriedRunPolicy`); a resumed leg * whose record names another version is covered by the CURRENT vocabulary as * well (`withCurrentVocabulary`) — fail closed, never the older list alone. */ export declare const VOCABULARY_VERSION: string; /** * `policy` as a run's state carries it (`AgentState.runRedaction`) — with the * vocabulary version it was built under when it keeps the conversation out. * * @internal */ export declare function carriedRunPolicy(policy: RedactionPolicy): CarriedRedactionPolicy; /** * A carried policy as a resumed leg is covered by it: joined with the CURRENT * vocabulary when its record names another version (`version`, read off the * checkpoint). An older list lacks the names an upgrade added — names that * keep the conversation out of the leg's STATE, its snapshot and its commit * log. Joining the current list keeps the leg at least as covered as the run * that paused. Same version, or none: the policy as carried. * * @internal */ export declare function withCurrentVocabulary(policy: RedactionPolicy | undefined, version: string | undefined): RedactionPolicy | undefined; /** * The policy that keeps an agent's conversation out of every record it * retains or serves — joined with `extra`, the names your own app adds. * * Hand it to the one door, `Agent.create({ redact })`. What it covers, what it * leaves readable and what it does not name are in this file's header and in * `src/redaction/README.md`. * * @param extra your own selectors (`keys`, `patterns`, `fields`, * `emitPatterns`, `diagnostics`), validated like `redact` * itself; joined, never replacing the library's names. * @returns a frozen `RedactionPolicy`. * * @example * ```ts * import { Agent } from 'agentfootprint'; * import { conversationRedaction } from 'agentfootprint/security'; * * const agent = Agent.create({ * provider, * model: 'claude-sonnet-4-5', * redact: conversationRedaction({ patterns: [/ssn|email|phone/i] }), * }).build(); * ``` */ export declare function conversationRedaction(extra?: RedactionPolicy): RedactionPolicy; /** * Whether `policy` keeps an agent's WHOLE conversation out of its records — * every name the vocabulary lists selected by its rule (a pattern of the * policy's own that covers a name counts), `conversationRedaction()` or more. * * The question a chart-backed tool asks before it hands the MODEL a value the * calling run's policy selects (`core/servableSnapshot.ts` · * `modelFacingState`): the value travels on in the calling run's conversation * — the tool's result in its history and events, whatever the model then * says — so only a calling run whose records keep the conversation out keeps * that value out of them too. * * @internal */ export declare function keepsConversationOut(policy: RedactionPolicy | undefined): boolean;