import type { Complete } from "./interviewer.js"; /** * Tracing staves' own interview turns. * * langfuse.ts reads somebody else's Langfuse for evidence about their agents. It has no way to record * what staves itself does — every function in it fetches, discovers or probes. So the one product * whose entire subject is other people's workflows has never been able to look at its own, and every * question about why a conversation went wrong has been answered by reading code and guessing. * * This wraps the single place every model call passes through. Three rules: * * - It never changes what the caller gets. A turn must not fail, slow down or read differently * because something could not be written to an observability tool. * - It is off unless keys are configured. Conversations are the person's account of their own work, * and shipping them to a third party is a decision somebody makes on purpose, not a default that * arrives with an upgrade. * - Failures are silent to the caller and visible in the log, once. A tracer that spams a terminal * when a network is down is worse than no tracer. */ export interface TraceConfig { baseUrl: string; publicKey: string; secretKey: string; release?: string; } /** * How much of a turn is recorded. * * "full" keeps the prompt and the reply, which is what makes a trace worth reading when a conversation * goes wrong. "metadata" keeps everything except those two: which model, which mode, how long it took, * how big the exchange was, and the error if it failed. * * The split exists because a hosted person's conversation is their account of their own work, and they * bring their own provider key — they are paying for the call, and the content of it travelling to * somebody else's observability account is not the bargain they signed up for. An owner tracing their * own boards is a different thing entirely. So: full on the accounts that run the product, metadata on * everybody else, and errors from everybody, because a failure nobody can see is a failure nobody fixes. */ export type TraceContent = "full" | "metadata"; export interface TraceMeta { /** what kind of turn: the whole board, one job, an assessment */ name: string; /** the board it is about — never its contents, just which one */ board?: string; /** which model answered, when the caller knows */ model?: string; sessionId?: string; tags?: string[]; /** default "metadata": recording somebody's words is the thing you opt into, not out of */ content?: TraceContent; } export declare function traceConfig(env?: NodeJS.ProcessEnv): TraceConfig | null; /** * Wrap a completion so every call to it becomes a trace with one generation inside. * * Streaming is preserved exactly: the onText callback is passed straight through, so the person sees * tokens at the same moment they would have without this. The trace is written after the call * settles, from what already happened, and an error is recorded as the generation's output rather * than swallowed — a turn that failed is the one you most want to be able to look at. */ export declare function traced(complete: Complete, meta: TraceMeta, deps?: { config?: TraceConfig | null; fetch?: typeof fetch; }): Complete;