/** * Prompt cost as OpenTelemetry metrics, in the OTLP/HTTP JSON encoding. * * **Trazum writes the payload; it does not send it.** That is a decision, not a * missing feature. Pushing to a collector would mean holding an endpoint and a * credential, and this repository has twice shipped an SSRF where a URL reached * `fetch` without being the URL that was checked. A command that writes a file * has no such failure mode, and `curl --data-binary @metrics.json $OTLP_ENDPOINT` * is one line in the pipeline that already has the credential. * * No dependency on `@opentelemetry/*` either — the JSON encoding is a stable, * documented wire format, and this package has no runtime dependencies by design. * * The two encoding rules that are easy to get wrong and silently produce a * payload a collector drops: * * - **64-bit integers are strings.** `timeUnixNano` and `asInt` are `int64` in * the protobuf, and JSON numbers cannot hold one exactly, so the JSON mapping * specifies strings. A collector reading `1786000000000000000` as a double * loses the last digits of every timestamp. * - **A gauge is `asDouble` or `asInt`, never both**, and a money figure is a * double. Sending `asInt` for `$41.20` silently reports `41`. */ /** Attributes as OTLP encodes them: a list of key/value, not an object. */ export interface OtlpAttribute { key: string; value: { stringValue: string; } | { intValue: string; } | { doubleValue: number; }; } export interface OtlpDataPoint { attributes: OtlpAttribute[]; timeUnixNano: string; asInt?: string; asDouble?: number; } export interface OtlpMetric { name: string; description: string; unit: string; gauge: { dataPoints: OtlpDataPoint[]; }; } export interface OtlpPayload { resourceMetrics: [ { resource: { attributes: OtlpAttribute[]; }; scopeMetrics: [{ scope: { name: string; version: string; }; metrics: OtlpMetric[]; }]; } ]; } /** What `doctor` knows, in the shape this module needs. */ export interface OtlpInput { /** Every prompt surveyed, with the count a budget would be compared against. */ prompts: readonly { path: string; tokens: number; overBudget: boolean; budgeted: boolean; }[]; /** Advisories rolled up by id, as the survey reports them. */ findings: readonly { id: string; prompts: number; monthlyUsd: number | null; }[]; model: string; callsPerMonth: number; } /** * `atMillis` is a parameter rather than a call to `Date.now()`. * * The same reason `computeSavings` takes a `Date`: a function that reads the * clock cannot be asserted against a fixed expectation, and every test of it * ends up asserting only its shape. Here the timestamp *is* half the payload. */ export declare function toOtlpMetrics(input: OtlpInput, atMillis: number): OtlpPayload; //# sourceMappingURL=otlp.d.ts.map