diff --git a/src/infra/session-cost-usage.ts b/src/infra/session-cost-usage.ts index 6b09a518d46..4dd1203f91e 100644 --- a/src/infra/session-cost-usage.ts +++ b/src/infra/session-cost-usage.ts @@ -4,6 +4,26 @@ import readline from "node:readline"; import type { NormalizedUsage, UsageLike } from "../agents/usage.js"; import type { OpenClawConfig } from "../config/config.js"; import type { SessionEntry } from "../config/sessions/types.js"; +import type { + CostBreakdown, + CostUsageTotals, + CostUsageSummary, + DiscoveredSession, + ParsedTranscriptEntry, + ParsedUsageEntry, + SessionCostSummary, + SessionDailyLatency, + SessionDailyMessageCounts, + SessionDailyModelUsage, + SessionDailyUsage, + SessionLatencyStats, + SessionLogEntry, + SessionMessageCounts, + SessionModelUsage, + SessionToolUsage, + SessionUsageTimePoint, + SessionUsageTimeSeries, +} from "./session-cost-usage.types.js"; import { normalizeUsage } from "../agents/usage.js"; import { resolveSessionFilePath, @@ -12,139 +32,24 @@ import { import { countToolResults, extractToolCallNames } from "../utils/transcript-tools.js"; import { estimateUsageCost, resolveModelCostConfig } from "../utils/usage-format.js"; -type CostBreakdown = { - total?: number; - input?: number; - output?: number; - cacheRead?: number; - cacheWrite?: number; -}; - -type ParsedUsageEntry = { - usage: NormalizedUsage; - costTotal?: number; - costBreakdown?: CostBreakdown; - provider?: string; - model?: string; - timestamp?: Date; -}; - -type ParsedTranscriptEntry = { - message: Record; - role?: "user" | "assistant"; - timestamp?: Date; - durationMs?: number; - usage?: NormalizedUsage; - costTotal?: number; - costBreakdown?: CostBreakdown; - provider?: string; - model?: string; - stopReason?: string; - toolNames: string[]; - toolResultCounts: { total: number; errors: number }; -}; - -export type CostUsageTotals = { - input: number; - output: number; - cacheRead: number; - cacheWrite: number; - totalTokens: number; - totalCost: number; - // Cost breakdown by token type (from actual API data when available) - inputCost: number; - outputCost: number; - cacheReadCost: number; - cacheWriteCost: number; - missingCostEntries: number; -}; - -export type CostUsageDailyEntry = CostUsageTotals & { - date: string; -}; - -export type CostUsageSummary = { - updatedAt: number; - days: number; - daily: CostUsageDailyEntry[]; - totals: CostUsageTotals; -}; - -export type SessionDailyUsage = { - date: string; // YYYY-MM-DD - tokens: number; - cost: number; -}; - -export type SessionDailyMessageCounts = { - date: string; // YYYY-MM-DD - total: number; - user: number; - assistant: number; - toolCalls: number; - toolResults: number; - errors: number; -}; - -export type SessionLatencyStats = { - count: number; - avgMs: number; - p95Ms: number; - minMs: number; - maxMs: number; -}; - -export type SessionDailyLatency = SessionLatencyStats & { - date: string; // YYYY-MM-DD -}; - -export type SessionDailyModelUsage = { - date: string; // YYYY-MM-DD - provider?: string; - model?: string; - tokens: number; - cost: number; - count: number; -}; - -export type SessionMessageCounts = { - total: number; - user: number; - assistant: number; - toolCalls: number; - toolResults: number; - errors: number; -}; - -export type SessionToolUsage = { - totalCalls: number; - uniqueTools: number; - tools: Array<{ name: string; count: number }>; -}; - -export type SessionModelUsage = { - provider?: string; - model?: string; - count: number; - totals: CostUsageTotals; -}; - -export type SessionCostSummary = CostUsageTotals & { - sessionId?: string; - sessionFile?: string; - firstActivity?: number; - lastActivity?: number; - durationMs?: number; - activityDates?: string[]; // YYYY-MM-DD dates when session had activity - dailyBreakdown?: SessionDailyUsage[]; // Per-day token/cost breakdown - dailyMessageCounts?: SessionDailyMessageCounts[]; - dailyLatency?: SessionDailyLatency[]; - dailyModelUsage?: SessionDailyModelUsage[]; - messageCounts?: SessionMessageCounts; - toolUsage?: SessionToolUsage; - modelUsage?: SessionModelUsage[]; - latency?: SessionLatencyStats; -}; +export type { + CostUsageDailyEntry, + CostUsageSummary, + CostUsageTotals, + DiscoveredSession, + SessionCostSummary, + SessionDailyLatency, + SessionDailyMessageCounts, + SessionDailyModelUsage, + SessionDailyUsage, + SessionLatencyStats, + SessionLogEntry, + SessionMessageCounts, + SessionModelUsage, + SessionToolUsage, + SessionUsageTimePoint, + SessionUsageTimeSeries, +} from "./session-cost-usage.types.js"; const emptyTotals = (): CostUsageTotals => ({ input: 0, @@ -458,13 +363,6 @@ export async function loadCostUsageSummary(params?: { }; } -export type DiscoveredSession = { - sessionId: string; - sessionFile: string; - mtime: number; - firstUserMessage?: string; -}; - /** * Scan all transcript files to discover sessions not in the session store. * Returns basic metadata for each discovered session. @@ -834,23 +732,6 @@ export async function loadSessionCostSummary(params: { }; } -export type SessionUsageTimePoint = { - timestamp: number; - input: number; - output: number; - cacheRead: number; - cacheWrite: number; - totalTokens: number; - cost: number; - cumulativeTokens: number; - cumulativeCost: number; -}; - -export type SessionUsageTimeSeries = { - sessionId?: string; - points: SessionUsageTimePoint[]; -}; - export async function loadSessionUsageTimeSeries(params: { sessionId?: string; sessionEntry?: SessionEntry; @@ -928,14 +809,6 @@ export async function loadSessionUsageTimeSeries(params: { return { sessionId: params.sessionId, points: sortedPoints }; } -export type SessionLogEntry = { - timestamp: number; - role: "user" | "assistant" | "tool" | "toolResult"; - content: string; - tokens?: number; - cost?: number; -}; - export async function loadSessionLogs(params: { sessionId?: string; sessionEntry?: SessionEntry; diff --git a/src/infra/session-cost-usage.types.ts b/src/infra/session-cost-usage.types.ts new file mode 100644 index 00000000000..56c33721192 --- /dev/null +++ b/src/infra/session-cost-usage.types.ts @@ -0,0 +1,167 @@ +import type { NormalizedUsage } from "../agents/usage.js"; + +export type CostBreakdown = { + total?: number; + input?: number; + output?: number; + cacheRead?: number; + cacheWrite?: number; +}; + +export type ParsedUsageEntry = { + usage: NormalizedUsage; + costTotal?: number; + costBreakdown?: CostBreakdown; + provider?: string; + model?: string; + timestamp?: Date; +}; + +export type ParsedTranscriptEntry = { + message: Record; + role?: "user" | "assistant"; + timestamp?: Date; + durationMs?: number; + usage?: NormalizedUsage; + costTotal?: number; + costBreakdown?: CostBreakdown; + provider?: string; + model?: string; + stopReason?: string; + toolNames: string[]; + toolResultCounts: { total: number; errors: number }; +}; + +export type CostUsageTotals = { + input: number; + output: number; + cacheRead: number; + cacheWrite: number; + totalTokens: number; + totalCost: number; + // Cost breakdown by token type (from actual API data when available) + inputCost: number; + outputCost: number; + cacheReadCost: number; + cacheWriteCost: number; + missingCostEntries: number; +}; + +export type CostUsageDailyEntry = CostUsageTotals & { + date: string; +}; + +export type CostUsageSummary = { + updatedAt: number; + days: number; + daily: CostUsageDailyEntry[]; + totals: CostUsageTotals; +}; + +export type SessionDailyUsage = { + date: string; // YYYY-MM-DD + tokens: number; + cost: number; +}; + +export type SessionDailyMessageCounts = { + date: string; // YYYY-MM-DD + total: number; + user: number; + assistant: number; + toolCalls: number; + toolResults: number; + errors: number; +}; + +export type SessionLatencyStats = { + count: number; + avgMs: number; + p95Ms: number; + minMs: number; + maxMs: number; +}; + +export type SessionDailyLatency = SessionLatencyStats & { + date: string; // YYYY-MM-DD +}; + +export type SessionDailyModelUsage = { + date: string; // YYYY-MM-DD + provider?: string; + model?: string; + tokens: number; + cost: number; + count: number; +}; + +export type SessionMessageCounts = { + total: number; + user: number; + assistant: number; + toolCalls: number; + toolResults: number; + errors: number; +}; + +export type SessionToolUsage = { + totalCalls: number; + uniqueTools: number; + tools: Array<{ name: string; count: number }>; +}; + +export type SessionModelUsage = { + provider?: string; + model?: string; + count: number; + totals: CostUsageTotals; +}; + +export type SessionCostSummary = CostUsageTotals & { + sessionId?: string; + sessionFile?: string; + firstActivity?: number; + lastActivity?: number; + durationMs?: number; + activityDates?: string[]; // YYYY-MM-DD dates when session had activity + dailyBreakdown?: SessionDailyUsage[]; // Per-day token/cost breakdown + dailyMessageCounts?: SessionDailyMessageCounts[]; + dailyLatency?: SessionDailyLatency[]; + dailyModelUsage?: SessionDailyModelUsage[]; + messageCounts?: SessionMessageCounts; + toolUsage?: SessionToolUsage; + modelUsage?: SessionModelUsage[]; + latency?: SessionLatencyStats; +}; + +export type DiscoveredSession = { + sessionId: string; + sessionFile: string; + mtime: number; + firstUserMessage?: string; +}; + +export type SessionUsageTimePoint = { + timestamp: number; + input: number; + output: number; + cacheRead: number; + cacheWrite: number; + totalTokens: number; + cost: number; + cumulativeTokens: number; + cumulativeCost: number; +}; + +export type SessionUsageTimeSeries = { + sessionId?: string; + points: SessionUsageTimePoint[]; +}; + +export type SessionLogEntry = { + timestamp: number; + role: "user" | "assistant" | "tool" | "toolResult"; + content: string; + tokens?: number; + cost?: number; +};