import type { UsageProfileReport } from './usage.js'; /** * The profile as a spreadsheet. * * ## Why a file format is a feature * * The terminal report is read once and closed. The people who decide what a * workload is allowed to cost live in spreadsheets, and handing them a * screenshot of a terminal is how a finding stops at the person who ran the * command. `--json` is for machines; this is for the pivot table that gets * shown to whoever signs off the bill. * * ## One row per label and model, and no total row * * `byLabelAndModel` is the grouping a decision is actually made at — routing * `classify` to a cheaper model is a question about one label's calls to one * model — so it is the grain of the file. * * **There is deliberately no TOTAL row.** A total inside a data file is the * oldest spreadsheet trap there is: somebody sums the column, the total row is * included, and every figure downstream is exactly twice what it should be. * The sum of this file is the bill, and a spreadsheet can compute it. * * ## Unpriced models get empty cells, never zeros * * A model the catalogue does not know has real tokens and unknown dollars. * Writing `0` there would be a claim — that those calls were free — and it * would survive into every chart built on the file. An empty cell is the * absence it actually is, and spreadsheets already know how to skip one. */ /** Columns, in order. Exported so a test can pin the header rather than a string. */ export declare const PROFILE_CSV_COLUMNS: readonly ['label', 'model', 'calls', 'input_tokens', 'cache_read_tokens', 'cache_write_tokens', 'output_tokens', 'input_usd', 'cache_read_usd', 'cache_write_usd', 'output_usd', 'total_usd']; export interface ProfileCsvOptions { /** What to call the bucket for calls carrying no label. */ unlabelled: string; /** * Which table to write. * * `slice` is one row per label and model — the grain a routing or budget * decision is made at. `day` and `hour` are the time series, which is what * a spreadsheet gets asked to chart; keeping them behind a choice rather * than in extra columns means every file has one row shape, and a * spreadsheet that has to filter before it can sum is a spreadsheet * somebody sums wrong. */ shape?: ProfileCsvShape; } export type ProfileCsvShape = 'slice' | 'day' | 'hour' | 'model-day'; /** Columns for the per-day series. */ export declare const PROFILE_CSV_DAY_COLUMNS: readonly ['day', 'usd', 'calls', 'top_label', 'top_label_usd']; /** * One row per UTC day *and model* — the long format a pivot table or a chart * wants for drawing the mix moving day by day. The same refusals as every * shape here: no total row, and model ids pass through `field` because a log * can carry any string as a model id. */ export declare const PROFILE_CSV_MODEL_DAY_COLUMNS: readonly ['day', 'model', 'usd', 'calls']; /** Columns for the per-hour-of-UTC-day series. */ export declare const PROFILE_CSV_HOUR_COLUMNS: readonly ['hour_utc', 'usd', 'calls']; /** * The report as CSV text, one row per label and model. * * Rows arrive in the report's own order — largest bill first — because a * spreadsheet can re-sort and a reader opening the file should see the * expensive workload at the top either way. */ export declare function profileToCsv(report: UsageProfileReport, options: ProfileCsvOptions): string; //# sourceMappingURL=csv.d.ts.map