mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-28 17:01:53 +03:00
refactor(infra): extract session cost usage types
This commit is contained in:
+38
-165
@@ -4,6 +4,26 @@ import readline from "node:readline";
|
|||||||
import type { NormalizedUsage, UsageLike } from "../agents/usage.js";
|
import type { NormalizedUsage, UsageLike } from "../agents/usage.js";
|
||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
import type { SessionEntry } from "../config/sessions/types.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 { normalizeUsage } from "../agents/usage.js";
|
||||||
import {
|
import {
|
||||||
resolveSessionFilePath,
|
resolveSessionFilePath,
|
||||||
@@ -12,139 +32,24 @@ import {
|
|||||||
import { countToolResults, extractToolCallNames } from "../utils/transcript-tools.js";
|
import { countToolResults, extractToolCallNames } from "../utils/transcript-tools.js";
|
||||||
import { estimateUsageCost, resolveModelCostConfig } from "../utils/usage-format.js";
|
import { estimateUsageCost, resolveModelCostConfig } from "../utils/usage-format.js";
|
||||||
|
|
||||||
type CostBreakdown = {
|
export type {
|
||||||
total?: number;
|
CostUsageDailyEntry,
|
||||||
input?: number;
|
CostUsageSummary,
|
||||||
output?: number;
|
CostUsageTotals,
|
||||||
cacheRead?: number;
|
DiscoveredSession,
|
||||||
cacheWrite?: number;
|
SessionCostSummary,
|
||||||
};
|
SessionDailyLatency,
|
||||||
|
SessionDailyMessageCounts,
|
||||||
type ParsedUsageEntry = {
|
SessionDailyModelUsage,
|
||||||
usage: NormalizedUsage;
|
SessionDailyUsage,
|
||||||
costTotal?: number;
|
SessionLatencyStats,
|
||||||
costBreakdown?: CostBreakdown;
|
SessionLogEntry,
|
||||||
provider?: string;
|
SessionMessageCounts,
|
||||||
model?: string;
|
SessionModelUsage,
|
||||||
timestamp?: Date;
|
SessionToolUsage,
|
||||||
};
|
SessionUsageTimePoint,
|
||||||
|
SessionUsageTimeSeries,
|
||||||
type ParsedTranscriptEntry = {
|
} from "./session-cost-usage.types.js";
|
||||||
message: Record<string, unknown>;
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
const emptyTotals = (): CostUsageTotals => ({
|
const emptyTotals = (): CostUsageTotals => ({
|
||||||
input: 0,
|
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.
|
* Scan all transcript files to discover sessions not in the session store.
|
||||||
* Returns basic metadata for each discovered session.
|
* 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: {
|
export async function loadSessionUsageTimeSeries(params: {
|
||||||
sessionId?: string;
|
sessionId?: string;
|
||||||
sessionEntry?: SessionEntry;
|
sessionEntry?: SessionEntry;
|
||||||
@@ -928,14 +809,6 @@ export async function loadSessionUsageTimeSeries(params: {
|
|||||||
return { sessionId: params.sessionId, points: sortedPoints };
|
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: {
|
export async function loadSessionLogs(params: {
|
||||||
sessionId?: string;
|
sessionId?: string;
|
||||||
sessionEntry?: SessionEntry;
|
sessionEntry?: SessionEntry;
|
||||||
|
|||||||
@@ -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<string, unknown>;
|
||||||
|
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;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user