/** * Provider-aware token measurement and persistence. * * Central SSoT for CLI/tooling token estimation with a three-layer chain: * 1) OTel/provider telemetry when available * 2) Exact tokenizer for supported models * 3) Heuristic fallback calibrated for JSON vs text payloads * * @task T5618 * @why CLEO needs a provider-aware in-house token service instead of relying on a single external runtime. * @what Adds central token measurement, persistence, CRUD, and summary helpers for CLI, tests, and telemetry tooling. */ import { type TOKEN_USAGE_TRANSPORTS, type TokenUsageRow } from '../store/tasks-schema.js'; export type TokenMethod = 'otel' | 'provider_api' | 'tokenizer' | 'heuristic'; export type TokenConfidence = 'real' | 'high' | 'estimated' | 'coarse'; /** * Transport origin of a token exchange. Derived from the canonical * {@link TOKEN_USAGE_TRANSPORTS} enum SSoT (`cli | api | agent | mcp | unknown`) * so the type, the schema CHECK, and the exodus normalization stay in lockstep * (T11649 — `'mcp'` is a first-class origin, no longer coerced to `'agent'`). */ export type TokenTransport = (typeof TOKEN_USAGE_TRANSPORTS)[number]; export interface TokenExchangeInput { requestPayload?: unknown; responsePayload?: unknown; provider?: string; model?: string; transport?: TokenTransport; gateway?: string; domain?: string; operation?: string; sessionId?: string; taskId?: string; requestId?: string; cwd?: string; metadata?: Record; } export interface TokenMeasurement { inputChars: number; outputChars: number; inputTokens: number; outputTokens: number; totalTokens: number; method: TokenMethod; confidence: TokenConfidence; provider: string; model?: string; requestHash?: string; responseHash?: string; metadata: Record; } export interface TokenUsageFilters { provider?: string; transport?: TokenTransport; gateway?: string; domain?: string; operation?: string; sessionId?: string; taskId?: string; method?: TokenMethod; confidence?: TokenConfidence; requestId?: string; since?: string; until?: string; limit?: number; offset?: number; } export interface TokenUsageSummary { totalRecords: number; inputTokens: number; outputTokens: number; totalTokens: number; byMethod: Array<{ method: string; count: number; totalTokens: number; }>; byTransport: Array<{ transport: string; count: number; totalTokens: number; }>; byOperation: Array<{ key: string; count: number; totalTokens: number; }>; } /** Named params type for {@link recordTokenExchange} — wraps TokenExchangeInput minus cwd (projectRoot is first positional arg). */ export type RecordTokenExchangeParams = Omit; /** Named params type for {@link showTokenUsage} — look up a single token usage record by id. */ export interface ShowTokenUsageParams { /** Record identifier. */ id: string; } /** Named params type for {@link listTokenUsage} — filter and paginate token usage records. */ export type ListTokenUsageParams = TokenUsageFilters; /** Named params type for {@link summarizeTokenUsage} — filter token usage records for aggregation. */ export type SummarizeTokenUsageParams = TokenUsageFilters; /** Named params type for {@link deleteTokenUsage} — delete a single token usage record by id. */ export interface DeleteTokenUsageParams { /** Record identifier. */ id: string; } /** Named params type for {@link clearTokenUsage} — bulk-delete token usage records matching filters. */ export type ClearTokenUsageParams = TokenUsageFilters; export declare function measureTokenExchange(input: TokenExchangeInput): Promise; export declare function recordTokenExchange(projectRoot: string, params: RecordTokenExchangeParams): Promise; export declare function showTokenUsage(projectRoot: string, params: ShowTokenUsageParams): Promise; export declare function listTokenUsage(projectRoot: string, params?: ListTokenUsageParams): Promise<{ records: TokenUsageRow[]; total: number; filtered: number; }>; export declare function summarizeTokenUsage(projectRoot: string, params?: SummarizeTokenUsageParams): Promise; /** * Delete one token usage record. Records live only in `tasks_token_usage`: * the twin collapse drains the bare `token_usage` table into it at every open * (T13115), so the bare table holds nothing a report shows. * * @param projectRoot - Project root. * @param params - The record id. * @returns The id, and `deleted: true`. */ export declare function deleteTokenUsage(projectRoot: string, params: DeleteTokenUsageParams): Promise<{ deleted: boolean; id: string; }>; /** * Delete the token usage records matching the filters (see * {@link deleteTokenUsage}). * * @param projectRoot - Project root. * @param params - Filters; none clears everything. * @returns How many records were deleted. */ export declare function clearTokenUsage(projectRoot: string, params?: ClearTokenUsageParams): Promise<{ deleted: number; }>; /** * Record the token cost of a successful dispatch, for mutations only. * * `token_usage` is portable-personal (cleo-dev ruling 2026-09-29, journal * spec Q9): its rows are cost history that syncs and is backed up. A row * written by a read would make a read-only command change synced state: after * a `cleo show`, `cleo cloud verify` turned from `match` to `ahead`, and with * change capture on every read would become a sync op (T13106). So a query * (any gateway but `mutate`) records nothing. A mutation changes synced state * anyway, and its cost row travels with that change. Read cost comes back * through a device-local ledger folded into `token_usage` at push (T13114). * * Never throws: token telemetry must not break a command. * * @param input - The exchange; `gateway` decides whether it is recorded, `cwd` names the project. */ export declare function autoRecordDispatchTokenUsage(input: TokenExchangeInput): Promise; export declare function getLatestTokenRecord(projectRoot?: string): Promise; export declare function getTokenUsageAggregateSql(projectRoot?: string): Promise>; //# sourceMappingURL=token-service.d.ts.map