mirror of
https://github.com/Routstr/routstrd.git
synced 2026-08-10 04:07:00 +00:00
logging usage
This commit is contained in:
@@ -242,6 +242,78 @@ type UsageData = {
|
||||
satsCost: number;
|
||||
};
|
||||
|
||||
type UsageTrackingEntry = UsageData & {
|
||||
id: string;
|
||||
timestamp: number;
|
||||
modelId: string;
|
||||
baseUrl: string;
|
||||
requestId: string;
|
||||
client?: string;
|
||||
sessionId?: string;
|
||||
tags?: string[];
|
||||
};
|
||||
|
||||
function extractUsageFromResponseBody(body: unknown): UsageData | null {
|
||||
if (!body || typeof body !== "object") return null;
|
||||
const usage = (body as { usage?: Record<string, unknown> }).usage;
|
||||
if (!usage || typeof usage !== "object") return null;
|
||||
|
||||
const promptTokens = Number(usage.prompt_tokens ?? 0);
|
||||
const completionTokens = Number(usage.completion_tokens ?? 0);
|
||||
const totalTokens = Number(usage.total_tokens ?? 0);
|
||||
const costValue = usage.cost;
|
||||
|
||||
let cost = 0;
|
||||
let satsCost = 0;
|
||||
|
||||
if (typeof costValue === "number") {
|
||||
cost = costValue;
|
||||
} else if (costValue && typeof costValue === "object") {
|
||||
const costObj = costValue as Record<string, unknown>;
|
||||
const totalUsd = costObj.total_usd;
|
||||
const totalMsats = costObj.total_msats;
|
||||
|
||||
cost = typeof totalUsd === "number" ? totalUsd : 0;
|
||||
satsCost = typeof totalMsats === "number" ? totalMsats / 1000 : 0;
|
||||
}
|
||||
|
||||
if (
|
||||
promptTokens === 0 &&
|
||||
completionTokens === 0 &&
|
||||
totalTokens === 0 &&
|
||||
cost === 0 &&
|
||||
satsCost === 0
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
promptTokens,
|
||||
completionTokens,
|
||||
totalTokens,
|
||||
cost,
|
||||
satsCost,
|
||||
};
|
||||
}
|
||||
|
||||
function resolveUsageBaseUrl(response: Response, fallback?: string): string {
|
||||
const responseWithBaseUrl = response as Response & { baseUrl?: unknown };
|
||||
if (typeof responseWithBaseUrl.baseUrl === "string") {
|
||||
return responseWithBaseUrl.baseUrl;
|
||||
}
|
||||
|
||||
try {
|
||||
if (response.url) {
|
||||
const parsed = new URL(response.url);
|
||||
return `${parsed.protocol}//${parsed.host}`;
|
||||
}
|
||||
} catch {
|
||||
// Ignore URL parsing failures.
|
||||
}
|
||||
|
||||
return fallback || "unknown";
|
||||
}
|
||||
|
||||
function createSSEParserTransform(
|
||||
onUsage: (usage: UsageData) => void,
|
||||
): Transform {
|
||||
@@ -342,6 +414,13 @@ async function main(): Promise<void> {
|
||||
const sqliteDriver = createBunSqliteDriver(DB_PATH);
|
||||
const store = await createSdkStore({ driver: sqliteDriver });
|
||||
|
||||
const appendUsageTracking = (entry: UsageTrackingEntry): void => {
|
||||
const state = store.getState();
|
||||
const nextUsage = [...(state.usageTracking || []), entry];
|
||||
state.setUsageTracking(nextUsage);
|
||||
logger.log("Usage tracking saved:", JSON.stringify(entry));
|
||||
};
|
||||
|
||||
// Create adapters from our SQLite-backed store
|
||||
const discoveryAdapter = createDiscoveryAdapterFromStore(store);
|
||||
const providerRegistry = createProviderRegistryFromStore(store);
|
||||
@@ -792,6 +871,7 @@ async function main(): Promise<void> {
|
||||
const requestId =
|
||||
response.headers.get("x-routstr-request-id") || undefined;
|
||||
logger.log("Request ID, ", requestId, " with path: ", url.pathname);
|
||||
const usageBaseUrl = resolveUsageBaseUrl(response, forcedProvider);
|
||||
|
||||
if (isStream) {
|
||||
res.statusCode = response.status;
|
||||
@@ -812,6 +892,14 @@ async function main(): Promise<void> {
|
||||
|
||||
res.on("finish", () => {
|
||||
if (capturedUsage) {
|
||||
appendUsageTracking({
|
||||
id: `${requestId || `req-${Date.now()}`}-${modelId}`,
|
||||
timestamp: Date.now(),
|
||||
modelId,
|
||||
baseUrl: usageBaseUrl,
|
||||
requestId: requestId || "unknown",
|
||||
...capturedUsage,
|
||||
});
|
||||
logger.log(
|
||||
`Streaming request usage:`,
|
||||
JSON.stringify(capturedUsage),
|
||||
@@ -825,6 +913,17 @@ async function main(): Promise<void> {
|
||||
}
|
||||
|
||||
const responseBody = await response.json();
|
||||
const nonStreamUsage = extractUsageFromResponseBody(responseBody);
|
||||
if (nonStreamUsage) {
|
||||
appendUsageTracking({
|
||||
id: `${requestId || `req-${Date.now()}`}-${modelId}`,
|
||||
timestamp: Date.now(),
|
||||
modelId,
|
||||
baseUrl: usageBaseUrl,
|
||||
requestId: requestId || "unknown",
|
||||
...nonStreamUsage,
|
||||
});
|
||||
}
|
||||
res.writeHead(response.status, {
|
||||
"Content-Type": "application/json",
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user