agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
69 lines (68 loc) • 3.12 kB
TypeScript
/**
* ContextRecorder — observes footprintjs subflow + scope events, emits
* grouped `context.*` domain events via the EventDispatcher.
*
* Pattern: Observer (GoF) + Pipes & Filters (Hohpe & Woolf, 2003).
* Role: Core semantic grouping layer for the 3-slot model. Watches
* slot subflows (sf-system-prompt / sf-messages / sf-tools) and
* translates raw writes into context.injected / evicted /
* slot_composed / budget_pressure events.
* Emits: agentfootprint.context.injected
* agentfootprint.context.evicted
* agentfootprint.context.slot_composed
* agentfootprint.context.budget_pressure
*/
import type { CombinedRecorder, FlowSubflowEvent, WriteEvent } from 'footprintjs';
import type { EventDispatcher } from '../../events/dispatcher.js';
import { type RunContext } from '../../bridge/eventMeta.js';
import type { RunRedaction } from '../../redaction/runRedaction.js';
/**
* Supplies the recorder with run-level context. Passed at construction
* time (static fields) OR updated via `updateRunContext` between runs
* when reusing one recorder across multiple executor runs.
*/
export interface ContextRecorderOptions {
readonly dispatcher: EventDispatcher;
readonly id?: string;
readonly getRunContext: () => RunContext;
/**
* The run's write relay. Under a redaction policy that selects a slot key
* (`systemPromptInjections`, `slotCompositions`, …) the scope channel serves
* its write as the placeholder; the slot builders hand the value they wrote
* to the run (`redaction/runRedaction.ts` · `setEventSource`), and this
* recorder derives its events from that — so they exist, and the
* dispatcher serves them by name like every event. Absent (or nothing
* relayed): the write as the scope channel served it.
*/
readonly realWrites?: Pick<RunRedaction, 'takeRealWrite'>;
}
export declare class ContextRecorder implements CombinedRecorder {
readonly id: string;
private readonly dispatcher;
private readonly getRunContext;
private readonly realWrites;
private readonly seenInjections;
constructor(options: ContextRecorderOptions);
onSubflowEntry(event: FlowSubflowEvent): void;
onSubflowExit(event: FlowSubflowEvent): void;
onWrite(event: WriteEvent): void;
/**
* The value the stage wrote: the one it relayed (`realWrites`), else the
* write as the scope channel served it. Taken ONCE per write, so a relayed
* value is matched to the write it came with. `keptOut`: the run's policy
* selects the key itself, so every record derived from the value keeps that
* verdict — its content is served as the placeholder, its structure stays
* (`structureOf`).
*/
private written;
private handleInjectionsWrite;
private handleSlotComposedWrite;
private handleEvictionsWrite;
private handleBudgetPressureWrite;
private emitInjected;
private dispatch;
private asInjectionArray;
private asSlotComposition;
private asEvictionArray;
private asPressureArray;
}