import type { FabricEvent, SubmissionTelemetrySink, TelemetrySpan } from "@fabric-harness/sdk"; import type { DatabricksRawProtocolClient } from "./raw-protocol-client.js"; /** * MLflow trace export (v2 migration, workstream C6): one MLflow trace per * settled submission, so agent activity shows up in the workspace's MLflow * experiment UI next to models and evaluations. * * Wiring: `sink` goes into `createSubmissionRunner({ telemetry })` and * `onEvent` fans in with the app's `onEvent` callback. A `submission_started` * telemetry event opens a span buffer keyed by the store session id * (`agent:::` — the `sessionId` stamped on * `FabricEvent`s during the attempt); every event that matches an open buffer * and converts via the SDK's `eventToTelemetrySpan` (i.e. carries * `data.durationMs`) is appended as a child span. `submission_settled` builds * the trace and POSTs it to the MLflow **V3 traces API** * (`POST /api/3.0/mlflow/traces`), then drops the buffer. * * The V3 payload ({@link buildMlflowTrace}) is implemented to the published * API spec — OTLP-shaped spans with base64 ids, unix-nano timestamps and * typed attributes — but live verification requires a workspace. Set * `DATABRICKS_LIVE_TEST=1` and `DATABRICKS_MLFLOW_EXPERIMENT_ID`, then run * `pnpm --filter @fabric-harness/databricks test:live` before relying on it. * * Both `sink.record` and `onEvent` never throw — failures (including the * async POST) are reported through `onError`. */ export interface MlflowTraceExporterOptions { client: DatabricksRawProtocolClient; /** MLflow experiment receiving the traces. */ experimentId: string; /** Failure reporter (default console.error). */ onError?: (context: string, error: unknown) => void; } export interface MlflowTraceExporter { /** Wire into `createSubmissionRunner({ telemetry })`. */ sink: SubmissionTelemetrySink; /** Fan in with the app's `onEvent` to capture per-turn/tool spans. */ onEvent: (event: FabricEvent) => void; } export declare function mlflowTraceExporter(options: MlflowTraceExporterOptions): MlflowTraceExporter; export interface MlflowTraceInput { submissionId: string; agent: string; instanceId: string; session: string; experimentId: string; /** Epoch ms when the submission started executing. */ startedAtMs: number; /** Epoch ms when the submission settled. */ settledAtMs: number; state: "OK" | "ERROR"; /** Child spans (from `eventToTelemetrySpan`) buffered during execution. */ spans: TelemetrySpan[]; attemptCount?: number; tenantId?: string; error?: string; } interface OtlpAttribute { key: string; value: { string_value: string; } | { double_value: number; } | { int_value: string; }; } interface MlflowSpan { trace_id: string; span_id: string; parent_span_id?: string; name: string; start_time_unix_nano: string; end_time_unix_nano: string; attributes: OtlpAttribute[]; status: { code: "STATUS_CODE_OK" | "STATUS_CODE_ERROR"; message?: string; }; } export interface MlflowTracePayload { trace: { trace_info: { trace_id: string; trace_location: { type: "MLFLOW_EXPERIMENT"; mlflow_experiment: { experiment_id: string; }; }; request_time: string; execution_duration: string; state: "OK" | "ERROR"; trace_metadata: Record; tags: Record; }; trace_data: { spans: MlflowSpan[]; }; }; } /** * Build the MLflow V3 `POST /api/3.0/mlflow/traces` payload for one settled * submission. Pure and deterministic: trace/span ids derive from the * submission id (+ span index) via SHA-256, so replaying the same settled * submission produces byte-identical ids. The root span covers the whole * submission; buffered {@link TelemetrySpan}s become its children. */ export declare function buildMlflowTrace(input: MlflowTraceInput): MlflowTracePayload; export {}; //# sourceMappingURL=mlflow-tracing.d.ts.map