Skip to content

Recorders

agentObservability(options?: AgentObservabilityOptions): AgentObservabilityRecorder

Bundles TokenRecorder + ToolUsageRecorder + CostRecorder:

import { agentObservability } from 'agentfootprint/observe';
const obs = agentObservability({
pricing: { 'claude-sonnet-4-20250514': { input: 3, output: 15 } },
});
const agent = Agent.create({ provider })
.recorder(obs)
.build();
await agent.run('hello');
obs.tokens(); // TokenStats
obs.tools(); // ToolUsageStats
obs.cost(); // number (USD)
obs.costEntries(); // CostEntry[]
const rec = new TokenRecorder();
rec.getStats(); // TokenStats
FieldType
totalCallsnumber
totalInputTokensnumber
totalOutputTokensnumber
totalLatencyMsnumber
averageLatencyMsnumber
totalCostnumber (USD, 0 if no pricing)
callsLLMCallEntry[] (each has cost)

With pricing:

const rec = new TokenRecorder({
pricing: { 'claude-sonnet-4-20250514': { input: 3, output: 15 } },
});
const rec = new CostRecorder({
pricingTable: { 'claude-sonnet-4-20250514': { input: 3, output: 15 } },
});
rec.getTotalCost(); // number (USD)
rec.getEntries(); // CostEntry[]
const rec = new ToolUsageRecorder();
rec.getStats(); // ToolUsageStats
FieldType
totalCallsnumber
byToolRecord<string, ToolStats>

Score each response with a custom judge function:

const rec = new QualityRecorder({
judge: async (response) => ({ score: 0.9, reason: 'Good' }),
});

Flag policy violations:

const rec = new GuardrailRecorder({
check: async (response) => ({ passed: true }),
});

Track tool permission decisions:

const rec = new PermissionRecorder();
rec.getEvents(); // PermissionEvent[]

Track per-turn metadata (timing, message count):

const rec = new TurnRecorder();
rec.getTurns(); // TurnEntry[]

Export events as OpenTelemetry spans. Zero @opentelemetry dependency — bring your own tracer:

import { trace } from '@opentelemetry/api';
import { OTelRecorder } from 'agentfootprint/observe';
const rec = new OTelRecorder(trace.getTracer('agentfootprint'));
// Spans: agent.turn, gen_ai.chat, tool.*, agent.error
// Attributes follow OpenTelemetry GenAI semantic conventions

Collect grounding evidence during traversal (no post-processing):

import { ExplainRecorder } from 'agentfootprint/explain';
const rec = new ExplainRecorder();
agent.recorder(rec);
await agent.run('...');
rec.getSources(); // tool results (ground truth)
rec.getClaims(); // LLM responses (to verify)
rec.getDecisions(); // tool call decisions
rec.explain(); // structured summary