UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

230 lines • 8.86 kB
import type { GenuiErrorCategory } from './genui/sandbox-validate.js'; import { type Latency } from './run-metrics.js'; /** * Generative-UI telemetry: one row per UI tool call (`ui__render`, `ui__sandbox`, `ui__show_*`, * `ui__show`), recorded by the loop through `AgentStore.recordGenuiCalls` and read back by the * dashboard's "Generative UI" page through `AgentGovernanceQueries.genuiStats`. * * PRIVACY: a row is metadata — names, counts, timings, an error's category and a scrubbed message. * The generated HTML/JSX and props are stored only when the tool was built with * `telemetry: { samplePayloads: true }` (off by default). */ import type { AgentStore, CostSource } from './spi/agent-store.js'; import type { GovernanceRange } from './spi/governance-queries.js'; import type { SinkWriter } from './spi/token-stream-sink.js'; import type { GenuiToolMarker } from './types.js'; export type { GenuiErrorCategory } from './genui/sandbox-validate.js'; /** * How a call fared: `first_try` — accepted on the turn's first UI attempt; `retried` — accepted * after one or more refused attempts; `failed` — refused (the model was handed the error). */ export type GenuiValidity = 'first_try' | 'retried' | 'failed'; /** One UI tool call, as the loop records it. */ export interface RecordGenuiCallInput { /** The tool call's id — the row's key (a replayed record overwrites, never duplicates). */ toolCallId: string; runId: string; threadId: string; actorRef: string; agentName?: string; /** The model step (0-based) that wrote the call. */ step: number; toolName: string; /** The turn's channel (`web`, `whatsapp`, …). */ channel: string; mode: GenuiToolMarker['mode']; modelId: string; /** 1 + the UI calls refused since the turn's last accepted one. */ attempt: number; outcome: 'ok' | 'error'; validity: GenuiValidity; errorCategory?: GenuiErrorCategory; /** The error, with quoted values replaced by `"…"` (verbatim with `samplePayloads`). At most 300 chars. */ errorMessage?: string; /** * The call's share of the step that wrote it — the step's tokens and cost split by the characters * each tool call's arguments (and the step's text) took. */ inputTokens: number; outputTokens: number; costUsd?: number; costSource?: CostSource; /** Turn start → the call's first `ui` frame (a streaming preview or the pushed component), in ms. */ firstFrameMs?: number; /** Turn start → the call's final (non-partial) `ui` frame, in ms. Absent for a refused call. */ completeFrameMs?: number; /** Size of the call's arguments, as JSON. */ payloadBytes: number; /** The call's arguments as JSON — ONLY with `telemetry.samplePayloads`. */ payload?: string; } /** A stored {@link RecordGenuiCallInput}. */ export interface GenuiCallRow extends RecordGenuiCallInput { createdAt: Date; } /** First-try success for one tool and model. */ export interface GenuiToolModelRow { toolName: string; modelId: string; mode: string; calls: number; /** Turns whose first UI attempt used this tool. */ firstAttempts: number; firstTrySuccesses: number; /** `firstTrySuccesses / firstAttempts`; null when there is none. */ firstTryRate: number | null; retried: number; failed: number; costUsd: number | null; } export interface GenuiErrorRow { category: string; /** The (scrubbed) message, as recorded. */ message: string; toolName: string; count: number; lastAt: string; } export interface GenuiDayRow { day: string; calls: number; turns: number; inputTokens: number; outputTokens: number; costUsd: number | null; firstTryRate: number | null; } /** Time to a UI tool's first and complete frame — the same distribution run latency reports. */ export type GenuiLatency = Latency; /** What the dashboard's Generative UI page shows. */ export interface GenuiStats { totals: { calls: number; turns: number; firstAttempts: number; firstTrySuccesses: number; firstTryRate: number | null; retried: number; failed: number; inputTokens: number; outputTokens: number; costUsd: number | null; }; byToolModel: GenuiToolModelRow[]; /** Most frequent first, at most 20. */ errors: GenuiErrorRow[]; byDay: GenuiDayRow[]; /** UI cost per turn (turns with at least one UI call). */ costPerTurn: { turns: number; avgUsd: number | null; p50Usd: number | null; p95Usd: number | null; }; /** * Per turn: turn start → its first UI frame, and → the first complete UI frame of an accepted call. */ latency: { firstFrame: GenuiLatency; complete: GenuiLatency; }; } /** Which kind of mistake a UI tool's error message is (what the genui tools and the registry throw). */ export declare function classifyGenuiError(message: string): GenuiErrorCategory; /** An error message without the values it quotes (a schema's "received 'Jane'"), at most 300 chars. */ export declare function scrubGenuiError(message: string): string; /** Rows created within the (inclusive, UTC) day range. */ export declare function genuiRowsInRange<T extends { createdAt: Date; }>(rows: readonly T[], range: GovernanceRange): T[]; /** {@link GenuiStats} from the rows of a range — the same numbers whichever store holds them. */ export declare function summarizeGenuiCalls(rows: readonly GenuiCallRow[]): GenuiStats; /** When each tool call's first and final `ui` frames went out on the turn's stream. */ export interface GenuiFrameTimes { first?: number; complete?: number; } /** * Wraps the turn's stream writer to note when each tool call's UI frames (`component`) are written — * what the user sees, so the time to first frame counts a streaming preview, and a frame a gate * held back counts when it was released. */ export declare function observeGenuiFrames(writer: SinkWriter, now?: () => number): { writer: SinkWriter; times: Map<string, GenuiFrameTimes>; }; /** What the loop knows about one step, to turn its UI calls into rows. */ export interface GenuiStepFacts { runId: string; threadId: string; actorRef: string; agentName?: string; step: number; channel: string; modelId: string; /** When the turn started; absent → no latency is recorded (an engine that cannot tell). */ startedAt?: number; /** The step's model usage and cost (the whole step: shared out by characters written). */ usage: { inputTokens: number; outputTokens: number; }; costUsd: number | null; costSource?: CostSource; text: string; calls: readonly { id: string; name: string; input: unknown; }[]; /** Each call's result: an `error` when it was refused or failed. */ results: readonly { id: string; error?: string; output?: unknown; }[]; /** A call's genui marker, or undefined for a tool that is not a UI tool. */ markerOf(name: string): GenuiToolMarker | undefined; frames: Map<string, GenuiFrameTimes>; /** When the step's results settled (a call whose frames went out unobserved completes here). */ now: number; } /** * Tracks the turn's UI attempts across steps: a refused UI call followed by another is a retry, * whichever UI tool the second one uses. */ export declare class GenuiTurnTelemetry { private refusedSinceAccepted; rows(facts: GenuiStepFacts): RecordGenuiCallInput[]; } /** One UI call made outside the agent loop, for {@link GenuiRunRecorder.track}. */ export interface GenuiOutOfLoopCall { store: Pick<AgentStore, 'recordGenuiCalls'>; /** The tool's `spec.genui`; not a UI tool (undefined) or telemetry off → nothing is recorded. */ marker: GenuiToolMarker | undefined; runId: string; threadId: string; actorRef: string; agentName?: string; channel: string; modelId: string; call: { id: string; name: string; input: unknown; }; } /** * Genui telemetry for an engine whose tools are called OUTSIDE the agent loop (OpenCode's MCP * endpoint, which its code mode calls): one row per UI call, attempts counted per run. There the * model's step is not split per call (tokens 0, no cost) and the frames are not timed (no latency). * Recording is best-effort and never changes what the call returns or throws. */ export declare class GenuiRunRecorder { private readonly maxRuns; private readonly runs; constructor(maxRuns?: number); track<T>(input: GenuiOutOfLoopCall, invoke: () => Promise<T>): Promise<T>; private turn; } //# sourceMappingURL=genui-telemetry.d.ts.map