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