/** * AgentThinkingTraceRecorder — produce an AgentThinkingUI `Trace` from a run. * * AgentThinkingUI (the "watch it think" player) consumes a framework-agnostic * `Trace` — a list of beats: `prompt → ask → return → answer`, where a tool * reply is `data` (reason) or an `instruction` (a skill that says how to act). * This recorder builds that `Trace` from agentfootprint's emit stream AS THE RUN * TRAVERSES (no post-processing) — so any agentfootprint agent gets the * domain-expert view for free, and AgentThinkingUI stays vendor-agnostic (it * just renders the `Trace` JSON, exactly as it renders the OTLP adapter's output). * * Mapping (from the events already on the stream): * stream.llm_end (toolCalls>0) → the brain reasoned; content + usage become * the upcoming ask's `brain` + `cost`. * stream.llm_end (toolCalls==0) → the final `answer`. * stream.tool_start → `ask` (read_skill → reaching for a skill). * stream.tool_end → `return` (read_skill → replyType:'instruction' * + skill; any other tool → replyType:'data'). * * Commentary (each beat's `brain`): filled from agentfootprint's OWN commentary * engine — the SAME `selectCommentaryKey`/`extractCommentaryVars`/`renderCommentary` * the Lens uses — so AgentThinkingUI's Notepad / bottom caption read identically * to the Lens commentary panel (one engine, consumer-overridable via * `commentaryTemplates`). The LLM's own reasoning still wins on the first ask of * an iteration; the engine fills every other beat so no line is ever blank. * * Convention 1 (one purpose) + Convention 4 (run-scoped — resets per run). */ import type { EmitRecorder } from 'footprintjs'; import { type CommentaryTemplates } from './commentary/commentaryTemplates.js'; export interface AttCost { ms: number; tokens: number; tokensIn?: number; tokensOut?: number; tokensCached?: number; } export interface AttAnswer { headline: string; [key: string]: unknown; } /** One tool the model had at its disposal for an LLM call — what it "saw" when it * decided. Lets a domain expert expand and read the menu next to the model's * reasoning, to debug WHY it chose (or skipped) a tool. */ export interface AttToolSeen { readonly name: string; readonly description?: string; } export type AttStep = { kind: 'prompt'; brain: string; cost: AttCost; } | { kind: 'ask'; tool: string; toolName?: string; input: Record; brain: string; cost: AttCost; /** Model's extended-thinking chain-of-thought for this iteration (when the * provider emitted reasoning blocks). Rendered as the "thinking" callout. */ thinking?: string; /** The tools the model saw (name + description) for this iteration's call — * the menu it chose from. On the iteration's first ask only. */ toolsSeen?: readonly AttToolSeen[]; } | { kind: 'return'; tool: string; toolName?: string; replyType: 'data' | 'instruction' | 'both'; output: Record; brain: string; cost: AttCost; brainMode?: 'reason' | 'act'; skill?: string; error?: string; } | { kind: 'answer'; to: string; brain: string; answer: AttAnswer; cost: AttCost; error?: string; /** Model's extended-thinking chain-of-thought before the final answer. */ thinking?: string; /** The tools the model saw (name + description) for the final call. */ toolsSeen?: readonly AttToolSeen[]; }; export interface AttTrace { task: string; title?: string; agent: string; model: string; asker: string; steps: AttStep[]; } export interface AgentThinkingTraceOptions { readonly id?: string; readonly agent?: string; readonly model?: string; readonly asker?: string; /** * Override agentfootprint's bundled commentary templates — the SAME shape as * the Lens's `commentaryTemplates` prop (partial; spread over the defaults). * Drives each beat's `brain` narration, so AgentThinkingUI's Notepad / bottom * caption read like the Lens commentary panel — one engine, one voice, * consumer-overridable. Omit to use the bundled English defaults. */ readonly commentaryTemplates?: Partial; } export interface AgentThinkingTraceHandle extends EmitRecorder { /** The AgentThinkingUI `Trace` for the run so far. `task` (the headline of the * replay pill) defaults to the captured user message; override any field. */ getTrace(overrides?: Partial>): AttTrace; clear(): void; } export declare function agentThinkingTrace(options?: AgentThinkingTraceOptions): AgentThinkingTraceHandle;