UNPKG

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
/** * 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; }