agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
132 lines (131 loc) • 6.95 kB
TypeScript
/**
* `recordingView` — ONE indexed pass over a recording, filtered to THIS run.
*
* Every reader of the account asks the view, never the raw `events` array, so
* "which event is where" has one owner (and `failureCauses`, when it ships,
* reuses it).
*
* Whose events: the rule `bridge/eventMeta.ts` · `eventBelongsToRun` owns (an
* event that names a run belongs to that run; one that names none, to runs of
* its session). The run is identified by the agentfootprint run id — NOT
* `snapshot.runId`, which is footprintjs's executor id and a different id space
* (filtering on it would drop every event). In order:
* 1. `options.runId` — the stored artifact's `meta.origin.runId`;
* 2. else the one run id on the recording's `agent.run_configured` events;
* 3. with more than one (a shared-agent recording made before runs kept their
* own events): the run that owns `turn_end` — never simply the first;
* 4. with none of these, NOTHING is filtered and `scope` says `'unfiltered'`.
*
* Tolerance: an event that is not an object with a string `type` and an object
* `payload` is passed over and counted in `unread`. Indices are the RECORDING's
* indices, so a pointer lands on the event the reader can open.
*
* A REDACTED recording (a run under an agent's `redact`) holds a placeholder
* where the policy selected a value: `[REDACTED]` for a payload field (or for a
* whole payload, under `emitPatterns`), and `REDACTED` for a state key. Its
* snapshot says it was served under a policy (`redaction/marker.ts`); in such
* a record — and ONLY there; a tool can return the string `'REDACTED'` too —
* a placeholder is NO value: a field or key that holds one reads as absent,
* never as a result to judge or a pause to report — and it is NAMED
* (`ViewEvent.redacted`, `RecordingView.stateKeptOut`), so a fact that would
* otherwise say "not recorded" can say "kept out" (`keptOut`,
* `RecordingView.isStateKeptOut`). An event whose whole payload is kept out
* is still an event of the run: its type and meta are read, its payload is
* empty.
*
* THE GUARD. A reader that touches a kept-out field without asking about it
* would state a fact about a placeholder ("no tool ran" from a kept-out
* `toolCallId`). So the view watches: every kept-out field or state key a
* reader TOUCHES (reads, or tests with `in`) is noted, and so is every one it
* ASKS about; `keptOutRead()` lists the touched ones never asked about, and
* the account refuses to tell over them (`account.ts` · `notToldAccount`).
* An unredacted recording is read through no guard at all.
*/
import { isPlaceholder } from '../redaction/marker.js';
/** An event of the run, narrowed to what a reader may touch, at its recording index. */
export interface ViewEvent {
readonly index: number;
readonly type: string;
readonly payload: Readonly<Record<string, unknown>>;
readonly meta: Readonly<Record<string, unknown>>;
/**
* What the record keeps out of this payload (a redaction policy left its
* placeholder there): the names of the fields that hold it, or `'whole'`
* when the policy kept the whole payload out. A kept-out field reads as
* absent in `payload`; ask {@link keptOut} before saying a value does not
* exist. Absent when nothing was kept out.
*/
readonly redacted?: readonly string[] | 'whole';
}
/**
* Whether the record keeps `field` of `event`'s payload out (see
* `ViewEvent.redacted`) — and a reader that asks has handled it, so touching
* the field afterwards is not a read of a placeholder (the view's guard).
*/
export declare function keptOut(event: ViewEvent | undefined, field: string): boolean;
export interface RecordingView {
/** This run's events, in recording order. */
readonly events: readonly ViewEvent[];
/** The run id the filter keyed on (absent when `scope` is `'unfiltered'`). */
readonly runId?: string;
readonly sessionId?: string;
readonly scope: 'own-run' | 'unfiltered';
/** Events of another run — never read. */
readonly foreign: number;
/** Events passed over because their shape did not fit. */
readonly unread: number;
/**
* The record was SERVED under a redaction policy — its snapshot carries the
* marker (`redaction/marker.ts`). Only then is a placeholder a value the
* record keeps out; in any other record it is a value like any other.
*/
readonly servedUnderPolicy: boolean;
/** `snapshot.sharedState`, when it is an object — without the keys it keeps out. */
readonly state?: Readonly<Record<string, unknown>>;
/** The state keys the record keeps out (they hold the redaction placeholder). */
readonly stateKeptOut: readonly string[];
/** Whether the record keeps state `key` out — asking handles it (the view's guard). */
isStateKeptOut(key: string): boolean;
/**
* `snapshot.sharedState` exactly as the record holds it, placeholders and
* all — for a reader that judges kept-out keys itself (the standing fold,
* `core/agent/assessment/assess.ts` · `assessAnswer`). Every other reader
* reads `state`.
*/
readonly stateAsRecorded?: Readonly<Record<string, unknown>>;
/**
* `snapshot.initialState`, when it is an object with a `history` — on a
* resumed leg, the state the run PAUSED with (a fresh run's is empty). The
* part of the answer before the pause is read from it
* (`facts/pausedLeg.ts`).
*/
readonly pausedWith?: Readonly<Record<string, unknown>>;
/** Every event of one type (the agentfootprint prefix is optional). */
ofType(type: string): readonly ViewEvent[];
/**
* What readers read but the record keeps out: every kept-out payload field
* (`<event type> · <field>`) and state key (`state · <key>`) a reader
* touched without asking about it first (`keptOut`, `isStateKeptOut`). A
* fact read from one would be a fact about a placeholder. Empty when there
* is none — always, for a recording nothing was kept out of.
*/
keptOutRead(): readonly string[];
first(type: string): ViewEvent | undefined;
last(type: string): ViewEvent | undefined;
}
export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
export declare const str: (value: unknown) => string | undefined;
export declare const num: (value: unknown) => number | undefined;
/**
* Whether `value` is a redaction placeholder — a value the record keeps out.
* Asked only of a record SERVED under a policy (`redaction/marker.ts` ·
* `servedUnderPolicy`): anywhere else the same string is a value a tool or a
* person really produced.
*/
export declare const isKeptOut: typeof isPlaceholder;
export declare function recordingView(recording: {
readonly events?: unknown;
readonly snapshot?: unknown;
}, options?: {
readonly runId?: string;
}): RecordingView;