@lakphy/local-router 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1013 -109
- package/dist/entry.js +980 -76
- package/dist/web/assets/index-CQ4HNKVY.css +2 -0
- package/dist/web/assets/index-HmBORmZo.js +190 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-BprGtkte.js +0 -191
- package/dist/web/assets/index-OkpSAlwA.css +0 -2
package/dist/entry.js
CHANGED
|
@@ -9284,8 +9284,8 @@ var require_dist2 = __commonJS((exports, module) => {
|
|
|
9284
9284
|
});
|
|
9285
9285
|
|
|
9286
9286
|
// src/index.ts
|
|
9287
|
-
import { readFileSync as
|
|
9288
|
-
import { dirname as dirname2, resolve as
|
|
9287
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
9288
|
+
import { dirname as dirname2, resolve as resolve7 } from "path";
|
|
9289
9289
|
|
|
9290
9290
|
// node_modules/.bun/@ai-sdk+provider@3.0.8/node_modules/@ai-sdk/provider/dist/index.mjs
|
|
9291
9291
|
var marker = "vercel.ai.error";
|
|
@@ -51789,8 +51789,8 @@ async function getLogMetrics(options) {
|
|
|
51789
51789
|
}
|
|
51790
51790
|
|
|
51791
51791
|
// src/log-query.ts
|
|
51792
|
-
import { createReadStream as createReadStream3, existsSync as
|
|
51793
|
-
import { join as join5, resolve as
|
|
51792
|
+
import { createReadStream as createReadStream3, existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
51793
|
+
import { join as join5, resolve as resolve5 } from "path";
|
|
51794
51794
|
import { createInterface as createInterface2 } from "readline";
|
|
51795
51795
|
|
|
51796
51796
|
// src/log-index.ts
|
|
@@ -51798,11 +51798,11 @@ import { Database } from "bun:sqlite";
|
|
|
51798
51798
|
import {
|
|
51799
51799
|
closeSync,
|
|
51800
51800
|
createReadStream as createReadStream2,
|
|
51801
|
-
existsSync as
|
|
51801
|
+
existsSync as existsSync4,
|
|
51802
51802
|
mkdirSync as mkdirSync2,
|
|
51803
51803
|
openSync,
|
|
51804
51804
|
readSync,
|
|
51805
|
-
statSync
|
|
51805
|
+
statSync as statSync2
|
|
51806
51806
|
} from "fs";
|
|
51807
51807
|
import { join as join4 } from "path";
|
|
51808
51808
|
|
|
@@ -51882,8 +51882,588 @@ function resolveLogSessionIdentity(requestBody) {
|
|
|
51882
51882
|
};
|
|
51883
51883
|
}
|
|
51884
51884
|
|
|
51885
|
+
// src/token-usage.ts
|
|
51886
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, statSync } from "fs";
|
|
51887
|
+
import { resolve as resolve4 } from "path";
|
|
51888
|
+
var MAX_STREAM_USAGE_BYTES = 25 * 1024 * 1024;
|
|
51889
|
+
function asRecord(value) {
|
|
51890
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
51891
|
+
return null;
|
|
51892
|
+
return value;
|
|
51893
|
+
}
|
|
51894
|
+
function numeric(value) {
|
|
51895
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
51896
|
+
return value;
|
|
51897
|
+
if (typeof value === "string" && value.trim()) {
|
|
51898
|
+
const parsed = Number(value);
|
|
51899
|
+
if (Number.isFinite(parsed))
|
|
51900
|
+
return parsed;
|
|
51901
|
+
}
|
|
51902
|
+
return null;
|
|
51903
|
+
}
|
|
51904
|
+
function numberAt(value, path) {
|
|
51905
|
+
let current = value;
|
|
51906
|
+
for (const key2 of path) {
|
|
51907
|
+
const record2 = asRecord(current);
|
|
51908
|
+
if (!record2 || !(key2 in record2))
|
|
51909
|
+
return null;
|
|
51910
|
+
current = record2[key2];
|
|
51911
|
+
}
|
|
51912
|
+
return numeric(current);
|
|
51913
|
+
}
|
|
51914
|
+
function firstNumber(value, paths) {
|
|
51915
|
+
for (const path of paths) {
|
|
51916
|
+
const found = numberAt(value, path);
|
|
51917
|
+
if (found !== null)
|
|
51918
|
+
return found;
|
|
51919
|
+
}
|
|
51920
|
+
return null;
|
|
51921
|
+
}
|
|
51922
|
+
function maxNullable(...values) {
|
|
51923
|
+
const numbers = values.filter((value) => value !== null && value !== undefined);
|
|
51924
|
+
if (numbers.length === 0)
|
|
51925
|
+
return null;
|
|
51926
|
+
return Math.max(...numbers);
|
|
51927
|
+
}
|
|
51928
|
+
function sumNullable(...values) {
|
|
51929
|
+
let total = 0;
|
|
51930
|
+
let hasValue = false;
|
|
51931
|
+
for (const value of values) {
|
|
51932
|
+
if (value === null || value === undefined)
|
|
51933
|
+
continue;
|
|
51934
|
+
total += value;
|
|
51935
|
+
hasValue = true;
|
|
51936
|
+
}
|
|
51937
|
+
return hasValue ? total : null;
|
|
51938
|
+
}
|
|
51939
|
+
function roundPercent(numerator, denominator) {
|
|
51940
|
+
if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0)
|
|
51941
|
+
return null;
|
|
51942
|
+
return Number((numerator / denominator * 100).toFixed(2));
|
|
51943
|
+
}
|
|
51944
|
+
function inferProviderStyle(usage, providerHint) {
|
|
51945
|
+
const hint = providerHint?.toLowerCase() ?? "";
|
|
51946
|
+
if (hint.includes("anthropic") || hint.includes("claude"))
|
|
51947
|
+
return "anthropic";
|
|
51948
|
+
if (hint.includes("gemini") || hint.includes("google"))
|
|
51949
|
+
return "gemini";
|
|
51950
|
+
if (hint.includes("deepseek"))
|
|
51951
|
+
return "deepseek";
|
|
51952
|
+
if (hint.includes("cohere"))
|
|
51953
|
+
return "cohere";
|
|
51954
|
+
if (hint.includes("mistral"))
|
|
51955
|
+
return "mistral";
|
|
51956
|
+
if (hint.includes("openrouter"))
|
|
51957
|
+
return "openrouter";
|
|
51958
|
+
if (hint.includes("openai") || hint.includes("gpt-"))
|
|
51959
|
+
return "openai";
|
|
51960
|
+
if ("cache_read_input_tokens" in usage || "cache_creation_input_tokens" in usage) {
|
|
51961
|
+
return "anthropic";
|
|
51962
|
+
}
|
|
51963
|
+
if ("prompt_cache_hit_tokens" in usage || "prompt_cache_miss_tokens" in usage) {
|
|
51964
|
+
return "deepseek";
|
|
51965
|
+
}
|
|
51966
|
+
if ("promptTokenCount" in usage || "usageMetadata" in usage || "cachedContentTokenCount" in usage) {
|
|
51967
|
+
return "gemini";
|
|
51968
|
+
}
|
|
51969
|
+
if ("billed_units" in usage || "tokens" in usage) {
|
|
51970
|
+
return "cohere";
|
|
51971
|
+
}
|
|
51972
|
+
if ("prompt_tokens" in usage || "completion_tokens" in usage) {
|
|
51973
|
+
return "openai";
|
|
51974
|
+
}
|
|
51975
|
+
if ("input_tokens" in usage || "output_tokens" in usage) {
|
|
51976
|
+
return "openai";
|
|
51977
|
+
}
|
|
51978
|
+
return "unknown";
|
|
51979
|
+
}
|
|
51980
|
+
function createEmptyMetrics2(input) {
|
|
51981
|
+
return {
|
|
51982
|
+
schemaVersion: 1,
|
|
51983
|
+
source: input.source,
|
|
51984
|
+
providerStyle: input.providerStyle,
|
|
51985
|
+
inputTokens: null,
|
|
51986
|
+
outputTokens: null,
|
|
51987
|
+
totalTokens: null,
|
|
51988
|
+
cachedInputTokens: null,
|
|
51989
|
+
cacheHitInputTokens: null,
|
|
51990
|
+
cacheHitRate: null,
|
|
51991
|
+
cacheHitRateDenominatorTokens: null,
|
|
51992
|
+
cacheHitRateFormula: null,
|
|
51993
|
+
cacheReadInputTokens: null,
|
|
51994
|
+
cacheCreationInputTokens: null,
|
|
51995
|
+
cacheCreationInputTokens5m: null,
|
|
51996
|
+
cacheCreationInputTokens1h: null,
|
|
51997
|
+
cacheWriteInputTokens: null,
|
|
51998
|
+
cacheMissInputTokens: null,
|
|
51999
|
+
reasoningTokens: null,
|
|
52000
|
+
audioInputTokens: null,
|
|
52001
|
+
audioOutputTokens: null,
|
|
52002
|
+
textInputTokens: null,
|
|
52003
|
+
textOutputTokens: null,
|
|
52004
|
+
acceptedPredictionTokens: null,
|
|
52005
|
+
rejectedPredictionTokens: null,
|
|
52006
|
+
toolUsePromptTokens: null,
|
|
52007
|
+
billableInputTokens: null,
|
|
52008
|
+
billableOutputTokens: null,
|
|
52009
|
+
creditUsage: null,
|
|
52010
|
+
cost: null,
|
|
52011
|
+
rawUsage: input.rawUsage,
|
|
52012
|
+
rawUsagePath: input.rawUsagePath,
|
|
52013
|
+
warnings: []
|
|
52014
|
+
};
|
|
52015
|
+
}
|
|
52016
|
+
function hasAnyTokenSignal(metrics) {
|
|
52017
|
+
return [
|
|
52018
|
+
metrics.inputTokens,
|
|
52019
|
+
metrics.outputTokens,
|
|
52020
|
+
metrics.totalTokens,
|
|
52021
|
+
metrics.cachedInputTokens,
|
|
52022
|
+
metrics.cacheHitInputTokens,
|
|
52023
|
+
metrics.cacheReadInputTokens,
|
|
52024
|
+
metrics.cacheCreationInputTokens,
|
|
52025
|
+
metrics.cacheMissInputTokens,
|
|
52026
|
+
metrics.reasoningTokens,
|
|
52027
|
+
metrics.billableInputTokens,
|
|
52028
|
+
metrics.billableOutputTokens,
|
|
52029
|
+
metrics.creditUsage,
|
|
52030
|
+
metrics.cost
|
|
52031
|
+
].some((value) => value !== null);
|
|
52032
|
+
}
|
|
52033
|
+
function normalizeUsageObject(input) {
|
|
52034
|
+
const { usage, source: source2, rawUsagePath, providerHint } = input;
|
|
52035
|
+
const providerStyle = inferProviderStyle(usage, providerHint);
|
|
52036
|
+
const metrics = createEmptyMetrics2({
|
|
52037
|
+
source: source2,
|
|
52038
|
+
providerStyle,
|
|
52039
|
+
rawUsage: usage,
|
|
52040
|
+
rawUsagePath
|
|
52041
|
+
});
|
|
52042
|
+
const usageBody = asRecord(usage.usageMetadata) ?? usage;
|
|
52043
|
+
metrics.inputTokens = firstNumber(usageBody, [
|
|
52044
|
+
["input_tokens"],
|
|
52045
|
+
["prompt_tokens"],
|
|
52046
|
+
["promptTokenCount"],
|
|
52047
|
+
["tokens", "input_tokens"],
|
|
52048
|
+
["billed_units", "input_tokens"]
|
|
52049
|
+
]);
|
|
52050
|
+
metrics.outputTokens = firstNumber(usageBody, [
|
|
52051
|
+
["output_tokens"],
|
|
52052
|
+
["completion_tokens"],
|
|
52053
|
+
["candidatesTokenCount"],
|
|
52054
|
+
["tokens", "output_tokens"],
|
|
52055
|
+
["billed_units", "output_tokens"]
|
|
52056
|
+
]);
|
|
52057
|
+
const explicitTotalTokens = firstNumber(usageBody, [
|
|
52058
|
+
["total_tokens"],
|
|
52059
|
+
["totalTokenCount"],
|
|
52060
|
+
["tokens", "total_tokens"]
|
|
52061
|
+
]);
|
|
52062
|
+
metrics.totalTokens = explicitTotalTokens;
|
|
52063
|
+
const cachedTokens = firstNumber(usageBody, [
|
|
52064
|
+
["input_tokens_details", "cached_tokens"],
|
|
52065
|
+
["prompt_tokens_details", "cached_tokens"],
|
|
52066
|
+
["cached_tokens"],
|
|
52067
|
+
["cachedContentTokenCount"]
|
|
52068
|
+
]);
|
|
52069
|
+
const cacheReadTokens = firstNumber(usageBody, [
|
|
52070
|
+
["cache_read_input_tokens"],
|
|
52071
|
+
["cacheReadInputTokens"],
|
|
52072
|
+
["claude_cache_read_input_tokens"]
|
|
52073
|
+
]);
|
|
52074
|
+
const promptCacheHitTokens = firstNumber(usageBody, [["prompt_cache_hit_tokens"]]);
|
|
52075
|
+
const promptCacheMissTokens = firstNumber(usageBody, [["prompt_cache_miss_tokens"]]);
|
|
52076
|
+
const cacheCreationTokens = firstNumber(usageBody, [
|
|
52077
|
+
["cache_creation_input_tokens"],
|
|
52078
|
+
["cacheCreationInputTokens"],
|
|
52079
|
+
["cache_creation", "input_tokens"],
|
|
52080
|
+
["claude_cache_creation_input_tokens"]
|
|
52081
|
+
]);
|
|
52082
|
+
metrics.cacheCreationInputTokens5m = firstNumber(usageBody, [
|
|
52083
|
+
["cache_creation", "ephemeral_5m_input_tokens"],
|
|
52084
|
+
["cache_creation", "ephemeral5mInputTokens"],
|
|
52085
|
+
["cache_creation_ephemeral_5m_input_tokens"],
|
|
52086
|
+
["claude_cache_creation_5_m_tokens"]
|
|
52087
|
+
]);
|
|
52088
|
+
metrics.cacheCreationInputTokens1h = firstNumber(usageBody, [
|
|
52089
|
+
["cache_creation", "ephemeral_1h_input_tokens"],
|
|
52090
|
+
["cache_creation", "ephemeral1hInputTokens"],
|
|
52091
|
+
["cache_creation_ephemeral_1h_input_tokens"],
|
|
52092
|
+
["claude_cache_creation_1_h_tokens"]
|
|
52093
|
+
]);
|
|
52094
|
+
metrics.cacheCreationInputTokens = maxNullable(cacheCreationTokens, sumNullable(metrics.cacheCreationInputTokens5m, metrics.cacheCreationInputTokens1h));
|
|
52095
|
+
metrics.cacheReadInputTokens = cacheReadTokens;
|
|
52096
|
+
metrics.cacheHitInputTokens = maxNullable(cachedTokens, cacheReadTokens, promptCacheHitTokens);
|
|
52097
|
+
metrics.cachedInputTokens = metrics.cacheHitInputTokens;
|
|
52098
|
+
metrics.cacheMissInputTokens = promptCacheMissTokens;
|
|
52099
|
+
metrics.cacheWriteInputTokens = firstNumber(usageBody, [
|
|
52100
|
+
["cache_write_input_tokens"],
|
|
52101
|
+
["cacheWriteInputTokens"]
|
|
52102
|
+
]);
|
|
52103
|
+
if (metrics.cacheWriteInputTokens === null && providerStyle === "anthropic") {
|
|
52104
|
+
metrics.cacheWriteInputTokens = metrics.cacheCreationInputTokens;
|
|
52105
|
+
}
|
|
52106
|
+
metrics.reasoningTokens = firstNumber(usageBody, [
|
|
52107
|
+
["output_tokens_details", "reasoning_tokens"],
|
|
52108
|
+
["completion_tokens_details", "reasoning_tokens"],
|
|
52109
|
+
["reasoning_tokens"],
|
|
52110
|
+
["thoughtsTokenCount"]
|
|
52111
|
+
]);
|
|
52112
|
+
metrics.audioInputTokens = firstNumber(usageBody, [
|
|
52113
|
+
["input_tokens_details", "audio_tokens"],
|
|
52114
|
+
["prompt_tokens_details", "audio_tokens"],
|
|
52115
|
+
["audio_input_tokens"]
|
|
52116
|
+
]);
|
|
52117
|
+
metrics.audioOutputTokens = firstNumber(usageBody, [
|
|
52118
|
+
["output_tokens_details", "audio_tokens"],
|
|
52119
|
+
["completion_tokens_details", "audio_tokens"],
|
|
52120
|
+
["audio_output_tokens"]
|
|
52121
|
+
]);
|
|
52122
|
+
metrics.textInputTokens = firstNumber(usageBody, [
|
|
52123
|
+
["input_tokens_details", "text_tokens"],
|
|
52124
|
+
["prompt_tokens_details", "text_tokens"],
|
|
52125
|
+
["text_input_tokens"]
|
|
52126
|
+
]);
|
|
52127
|
+
metrics.textOutputTokens = firstNumber(usageBody, [
|
|
52128
|
+
["output_tokens_details", "text_tokens"],
|
|
52129
|
+
["completion_tokens_details", "text_tokens"],
|
|
52130
|
+
["text_output_tokens"]
|
|
52131
|
+
]);
|
|
52132
|
+
metrics.acceptedPredictionTokens = firstNumber(usageBody, [
|
|
52133
|
+
["output_tokens_details", "accepted_prediction_tokens"],
|
|
52134
|
+
["completion_tokens_details", "accepted_prediction_tokens"],
|
|
52135
|
+
["accepted_prediction_tokens"]
|
|
52136
|
+
]);
|
|
52137
|
+
metrics.rejectedPredictionTokens = firstNumber(usageBody, [
|
|
52138
|
+
["output_tokens_details", "rejected_prediction_tokens"],
|
|
52139
|
+
["completion_tokens_details", "rejected_prediction_tokens"],
|
|
52140
|
+
["rejected_prediction_tokens"]
|
|
52141
|
+
]);
|
|
52142
|
+
metrics.toolUsePromptTokens = firstNumber(usageBody, [
|
|
52143
|
+
["toolUsePromptTokenCount"],
|
|
52144
|
+
["tool_use_prompt_tokens"]
|
|
52145
|
+
]);
|
|
52146
|
+
metrics.billableInputTokens = firstNumber(usageBody, [
|
|
52147
|
+
["billed_units", "input_tokens"],
|
|
52148
|
+
["billable_input_tokens"]
|
|
52149
|
+
]);
|
|
52150
|
+
metrics.billableOutputTokens = firstNumber(usageBody, [
|
|
52151
|
+
["billed_units", "output_tokens"],
|
|
52152
|
+
["billable_output_tokens"]
|
|
52153
|
+
]);
|
|
52154
|
+
metrics.creditUsage = firstNumber(usageBody, [["credit_usage"], ["creditUsage"]]);
|
|
52155
|
+
metrics.cost = firstNumber(usageBody, [["cost"], ["total_cost"], ["totalCost"]]);
|
|
52156
|
+
let cacheDenominator = null;
|
|
52157
|
+
let cacheFormula = null;
|
|
52158
|
+
if (providerStyle === "anthropic") {
|
|
52159
|
+
cacheDenominator = sumNullable(metrics.inputTokens, metrics.cacheReadInputTokens, metrics.cacheCreationInputTokens);
|
|
52160
|
+
cacheFormula = "cache_read_input_tokens / (input_tokens + cache_read_input_tokens + cache_creation_input_tokens)";
|
|
52161
|
+
} else if (providerStyle === "deepseek") {
|
|
52162
|
+
cacheDenominator = metrics.inputTokens ?? sumNullable(metrics.cacheHitInputTokens, metrics.cacheMissInputTokens);
|
|
52163
|
+
cacheFormula = "prompt_cache_hit_tokens / prompt_tokens";
|
|
52164
|
+
} else if (providerStyle === "gemini") {
|
|
52165
|
+
cacheDenominator = metrics.inputTokens;
|
|
52166
|
+
cacheFormula = "cachedContentTokenCount / promptTokenCount";
|
|
52167
|
+
} else if (providerStyle === "openai" || providerStyle === "mistral" || providerStyle === "openrouter" || providerStyle === "unknown") {
|
|
52168
|
+
cacheDenominator = metrics.inputTokens;
|
|
52169
|
+
cacheFormula = "cached_tokens / input_tokens";
|
|
52170
|
+
}
|
|
52171
|
+
if (metrics.cacheHitInputTokens !== null && cacheDenominator !== null && cacheDenominator > 0) {
|
|
52172
|
+
metrics.cacheHitRateDenominatorTokens = cacheDenominator;
|
|
52173
|
+
metrics.cacheHitRateFormula = cacheFormula;
|
|
52174
|
+
metrics.cacheHitRate = roundPercent(metrics.cacheHitInputTokens, cacheDenominator);
|
|
52175
|
+
if (metrics.cacheMissInputTokens === null) {
|
|
52176
|
+
metrics.cacheMissInputTokens = Math.max(0, cacheDenominator - metrics.cacheHitInputTokens);
|
|
52177
|
+
}
|
|
52178
|
+
}
|
|
52179
|
+
if (metrics.totalTokens === null && metrics.outputTokens !== null) {
|
|
52180
|
+
const effectiveInputTokens = metrics.cacheHitRateDenominatorTokens ?? metrics.inputTokens;
|
|
52181
|
+
if (effectiveInputTokens !== null) {
|
|
52182
|
+
metrics.totalTokens = effectiveInputTokens + metrics.outputTokens;
|
|
52183
|
+
metrics.warnings.push(metrics.cacheHitRateDenominatorTokens !== null ? "totalTokens \u7531 cacheHitRateDenominatorTokens + outputTokens \u63A8\u5BFC" : "totalTokens \u7531 inputTokens + outputTokens \u63A8\u5BFC");
|
|
52184
|
+
}
|
|
52185
|
+
}
|
|
52186
|
+
return hasAnyTokenSignal(metrics) ? metrics : null;
|
|
52187
|
+
}
|
|
52188
|
+
function collectUsageCandidates(value, prefix = "") {
|
|
52189
|
+
const record2 = asRecord(value);
|
|
52190
|
+
if (!record2)
|
|
52191
|
+
return [];
|
|
52192
|
+
const candidates = [];
|
|
52193
|
+
const candidateKeys = [
|
|
52194
|
+
"usage",
|
|
52195
|
+
"usageMetadata",
|
|
52196
|
+
"message.usage",
|
|
52197
|
+
"response.usage",
|
|
52198
|
+
"body.usage",
|
|
52199
|
+
"data.usage",
|
|
52200
|
+
"event.usage"
|
|
52201
|
+
];
|
|
52202
|
+
for (const key2 of candidateKeys) {
|
|
52203
|
+
const path = key2.split(".");
|
|
52204
|
+
let current = record2;
|
|
52205
|
+
for (const part of path) {
|
|
52206
|
+
const currentRecord = asRecord(current);
|
|
52207
|
+
current = currentRecord?.[part];
|
|
52208
|
+
}
|
|
52209
|
+
const usage = asRecord(current);
|
|
52210
|
+
if (usage) {
|
|
52211
|
+
candidates.push({ usage, path: prefix ? `${prefix}.${key2}` : key2 });
|
|
52212
|
+
}
|
|
52213
|
+
}
|
|
52214
|
+
const direct = normalizeUsageObject({
|
|
52215
|
+
usage: record2,
|
|
52216
|
+
source: "response_body",
|
|
52217
|
+
rawUsagePath: prefix || null
|
|
52218
|
+
});
|
|
52219
|
+
if (direct) {
|
|
52220
|
+
candidates.push({ usage: record2, path: prefix || "$" });
|
|
52221
|
+
}
|
|
52222
|
+
return candidates;
|
|
52223
|
+
}
|
|
52224
|
+
function mergeNumber(current, incoming, strategy = "max") {
|
|
52225
|
+
if (incoming === null)
|
|
52226
|
+
return current;
|
|
52227
|
+
if (current === null)
|
|
52228
|
+
return incoming;
|
|
52229
|
+
return strategy === "latest" ? incoming : Math.max(current, incoming);
|
|
52230
|
+
}
|
|
52231
|
+
function mergeTokenUsageMetrics(current, incoming) {
|
|
52232
|
+
if (!current)
|
|
52233
|
+
return incoming;
|
|
52234
|
+
if (!incoming)
|
|
52235
|
+
return current;
|
|
52236
|
+
const merged = {
|
|
52237
|
+
...current,
|
|
52238
|
+
source: incoming.source,
|
|
52239
|
+
providerStyle: current.providerStyle === "unknown" ? incoming.providerStyle : current.providerStyle,
|
|
52240
|
+
rawUsage: incoming.rawUsage ?? current.rawUsage,
|
|
52241
|
+
rawUsagePath: incoming.rawUsagePath ?? current.rawUsagePath,
|
|
52242
|
+
warnings: Array.from(new Set([...current.warnings, ...incoming.warnings]))
|
|
52243
|
+
};
|
|
52244
|
+
const numericKeys = [
|
|
52245
|
+
"inputTokens",
|
|
52246
|
+
"outputTokens",
|
|
52247
|
+
"totalTokens",
|
|
52248
|
+
"cachedInputTokens",
|
|
52249
|
+
"cacheHitInputTokens",
|
|
52250
|
+
"cacheHitRateDenominatorTokens",
|
|
52251
|
+
"cacheReadInputTokens",
|
|
52252
|
+
"cacheCreationInputTokens",
|
|
52253
|
+
"cacheCreationInputTokens5m",
|
|
52254
|
+
"cacheCreationInputTokens1h",
|
|
52255
|
+
"cacheWriteInputTokens",
|
|
52256
|
+
"cacheMissInputTokens",
|
|
52257
|
+
"reasoningTokens",
|
|
52258
|
+
"audioInputTokens",
|
|
52259
|
+
"audioOutputTokens",
|
|
52260
|
+
"textInputTokens",
|
|
52261
|
+
"textOutputTokens",
|
|
52262
|
+
"acceptedPredictionTokens",
|
|
52263
|
+
"rejectedPredictionTokens",
|
|
52264
|
+
"toolUsePromptTokens",
|
|
52265
|
+
"billableInputTokens",
|
|
52266
|
+
"billableOutputTokens",
|
|
52267
|
+
"creditUsage",
|
|
52268
|
+
"cost"
|
|
52269
|
+
];
|
|
52270
|
+
for (const key2 of numericKeys) {
|
|
52271
|
+
const value = mergeNumber(current[key2], incoming[key2], key2 === "cost" || key2 === "creditUsage" ? "latest" : "max");
|
|
52272
|
+
merged[key2] = value;
|
|
52273
|
+
}
|
|
52274
|
+
if (incoming.cacheHitRate !== null && (current.cacheHitRate === null || (incoming.cacheHitRateDenominatorTokens ?? 0) >= (current.cacheHitRateDenominatorTokens ?? 0))) {
|
|
52275
|
+
merged.cacheHitRate = incoming.cacheHitRate;
|
|
52276
|
+
merged.cacheHitRateFormula = incoming.cacheHitRateFormula;
|
|
52277
|
+
}
|
|
52278
|
+
if (merged.cacheHitInputTokens !== null && merged.cacheHitRateDenominatorTokens !== null) {
|
|
52279
|
+
merged.cacheHitRate = roundPercent(merged.cacheHitInputTokens, merged.cacheHitRateDenominatorTokens);
|
|
52280
|
+
}
|
|
52281
|
+
if (merged.totalTokens === null && merged.outputTokens !== null) {
|
|
52282
|
+
const effectiveInputTokens = merged.cacheHitRateDenominatorTokens ?? merged.inputTokens;
|
|
52283
|
+
if (effectiveInputTokens !== null) {
|
|
52284
|
+
merged.totalTokens = effectiveInputTokens + merged.outputTokens;
|
|
52285
|
+
merged.warnings.push(merged.cacheHitRateDenominatorTokens !== null ? "totalTokens \u7531 cacheHitRateDenominatorTokens + outputTokens \u63A8\u5BFC" : "totalTokens \u7531 inputTokens + outputTokens \u63A8\u5BFC");
|
|
52286
|
+
merged.warnings = Array.from(new Set(merged.warnings));
|
|
52287
|
+
}
|
|
52288
|
+
}
|
|
52289
|
+
return merged;
|
|
52290
|
+
}
|
|
52291
|
+
function toTokenUsageSummary(metrics) {
|
|
52292
|
+
const { rawUsage: _rawUsage, ...summary } = metrics;
|
|
52293
|
+
return summary;
|
|
52294
|
+
}
|
|
52295
|
+
function extractTokenUsageFromJson(value, options) {
|
|
52296
|
+
let merged = null;
|
|
52297
|
+
const candidates = collectUsageCandidates(value, options.rawUsagePathPrefix ?? "");
|
|
52298
|
+
for (const candidate of candidates) {
|
|
52299
|
+
const metrics = normalizeUsageObject({
|
|
52300
|
+
usage: candidate.usage,
|
|
52301
|
+
source: options.source,
|
|
52302
|
+
rawUsagePath: candidate.path,
|
|
52303
|
+
providerHint: options.providerHint
|
|
52304
|
+
});
|
|
52305
|
+
merged = mergeTokenUsageMetrics(merged, metrics);
|
|
52306
|
+
}
|
|
52307
|
+
return merged;
|
|
52308
|
+
}
|
|
52309
|
+
function extractTokenUsageFromResponseText(text2, source2 = "response_body", providerHint) {
|
|
52310
|
+
if (!text2?.trim())
|
|
52311
|
+
return null;
|
|
52312
|
+
try {
|
|
52313
|
+
return extractTokenUsageFromJson(JSON.parse(text2), { source: source2, providerHint });
|
|
52314
|
+
} catch {
|
|
52315
|
+
return null;
|
|
52316
|
+
}
|
|
52317
|
+
}
|
|
52318
|
+
function processSseMessage(dataLines, source2, providerHint) {
|
|
52319
|
+
if (dataLines.length === 0)
|
|
52320
|
+
return null;
|
|
52321
|
+
const data = dataLines.join(`
|
|
52322
|
+
`).trim();
|
|
52323
|
+
if (!data || data === "[DONE]")
|
|
52324
|
+
return null;
|
|
52325
|
+
try {
|
|
52326
|
+
return extractTokenUsageFromJson(JSON.parse(data), {
|
|
52327
|
+
source: source2,
|
|
52328
|
+
providerHint,
|
|
52329
|
+
rawUsagePathPrefix: source2 === "stream_file" ? "stream" : "stream"
|
|
52330
|
+
});
|
|
52331
|
+
} catch {
|
|
52332
|
+
return null;
|
|
52333
|
+
}
|
|
52334
|
+
}
|
|
52335
|
+
function extractTokenUsageFromSseText(text2, source2 = "stream_file", providerHint) {
|
|
52336
|
+
if (!text2?.trim())
|
|
52337
|
+
return null;
|
|
52338
|
+
let merged = null;
|
|
52339
|
+
let dataLines = [];
|
|
52340
|
+
const flush = () => {
|
|
52341
|
+
merged = mergeTokenUsageMetrics(merged, processSseMessage(dataLines, source2, providerHint));
|
|
52342
|
+
dataLines = [];
|
|
52343
|
+
};
|
|
52344
|
+
for (const rawLine of text2.split(/\r?\n/)) {
|
|
52345
|
+
if (rawLine === "") {
|
|
52346
|
+
flush();
|
|
52347
|
+
continue;
|
|
52348
|
+
}
|
|
52349
|
+
if (rawLine.startsWith("data:")) {
|
|
52350
|
+
dataLines.push(rawLine.slice(5).trimStart());
|
|
52351
|
+
}
|
|
52352
|
+
}
|
|
52353
|
+
flush();
|
|
52354
|
+
return merged;
|
|
52355
|
+
}
|
|
52356
|
+
function createTokenUsageStreamCollector(providerHint) {
|
|
52357
|
+
const decoder = new TextDecoder;
|
|
52358
|
+
let buffer2 = "";
|
|
52359
|
+
let dataLines = [];
|
|
52360
|
+
let latest = null;
|
|
52361
|
+
const flushMessage = () => {
|
|
52362
|
+
latest = mergeTokenUsageMetrics(latest, processSseMessage(dataLines, "stream_chunk", providerHint));
|
|
52363
|
+
dataLines = [];
|
|
52364
|
+
};
|
|
52365
|
+
const processLine = (rawLine) => {
|
|
52366
|
+
const line2 = rawLine.replace(/\r$/, "");
|
|
52367
|
+
if (line2 === "") {
|
|
52368
|
+
flushMessage();
|
|
52369
|
+
return;
|
|
52370
|
+
}
|
|
52371
|
+
if (line2.startsWith("data:")) {
|
|
52372
|
+
dataLines.push(line2.slice(5).trimStart());
|
|
52373
|
+
}
|
|
52374
|
+
};
|
|
52375
|
+
return {
|
|
52376
|
+
addChunk(chunk) {
|
|
52377
|
+
buffer2 += decoder.decode(chunk, { stream: true });
|
|
52378
|
+
let newlineIndex = buffer2.indexOf(`
|
|
52379
|
+
`);
|
|
52380
|
+
while (newlineIndex >= 0) {
|
|
52381
|
+
processLine(buffer2.slice(0, newlineIndex));
|
|
52382
|
+
buffer2 = buffer2.slice(newlineIndex + 1);
|
|
52383
|
+
newlineIndex = buffer2.indexOf(`
|
|
52384
|
+
`);
|
|
52385
|
+
}
|
|
52386
|
+
},
|
|
52387
|
+
getUsage() {
|
|
52388
|
+
buffer2 += decoder.decode();
|
|
52389
|
+
if (buffer2) {
|
|
52390
|
+
processLine(buffer2);
|
|
52391
|
+
buffer2 = "";
|
|
52392
|
+
}
|
|
52393
|
+
flushMessage();
|
|
52394
|
+
return latest;
|
|
52395
|
+
}
|
|
52396
|
+
};
|
|
52397
|
+
}
|
|
52398
|
+
function safeReadStreamFile(streamFile, baseDir) {
|
|
52399
|
+
if (!streamFile)
|
|
52400
|
+
return { content: null, warning: null };
|
|
52401
|
+
try {
|
|
52402
|
+
const candidates = [streamFile];
|
|
52403
|
+
if (baseDir)
|
|
52404
|
+
candidates.push(resolve4(baseDir, streamFile));
|
|
52405
|
+
for (const candidate of candidates) {
|
|
52406
|
+
const resolved = resolve4(candidate);
|
|
52407
|
+
if (!resolved.endsWith(".sse.raw"))
|
|
52408
|
+
continue;
|
|
52409
|
+
if (!existsSync3(resolved))
|
|
52410
|
+
continue;
|
|
52411
|
+
const stats = statSync(resolved);
|
|
52412
|
+
if (stats.size > MAX_STREAM_USAGE_BYTES) {
|
|
52413
|
+
return {
|
|
52414
|
+
content: null,
|
|
52415
|
+
warning: `stream_file \u8D85\u8FC7 ${MAX_STREAM_USAGE_BYTES} \u5B57\u8282\uFF0C\u5DF2\u8DF3\u8FC7 token usage \u56DE\u586B`
|
|
52416
|
+
};
|
|
52417
|
+
}
|
|
52418
|
+
return { content: readFileSync3(resolved, "utf-8"), warning: null };
|
|
52419
|
+
}
|
|
52420
|
+
} catch (err) {
|
|
52421
|
+
return {
|
|
52422
|
+
content: null,
|
|
52423
|
+
warning: `stream_file token usage \u8BFB\u53D6\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`
|
|
52424
|
+
};
|
|
52425
|
+
}
|
|
52426
|
+
return { content: null, warning: null };
|
|
52427
|
+
}
|
|
52428
|
+
function extractTokenUsageFromLogEvent(event, options = {}) {
|
|
52429
|
+
if (event.token_usage) {
|
|
52430
|
+
return {
|
|
52431
|
+
rawUsage: null,
|
|
52432
|
+
...event.token_usage,
|
|
52433
|
+
source: event.token_usage.source ?? "explicit"
|
|
52434
|
+
};
|
|
52435
|
+
}
|
|
52436
|
+
const providerHint = [event.provider, event.route_type, event.model_in, event.model_out].filter(Boolean).join(" ");
|
|
52437
|
+
const responseBodyUsage = extractTokenUsageFromResponseText(event.response_body, "response_body", providerHint);
|
|
52438
|
+
if (responseBodyUsage)
|
|
52439
|
+
return responseBodyUsage;
|
|
52440
|
+
const responseAfterPluginsUsage = extractTokenUsageFromResponseText(event.response_body_after_plugins, "response_body_after_plugins", providerHint);
|
|
52441
|
+
if (responseAfterPluginsUsage)
|
|
52442
|
+
return responseAfterPluginsUsage;
|
|
52443
|
+
const responseBeforePluginsUsage = extractTokenUsageFromResponseText(event.response_body_before_plugins, "response_body_before_plugins", providerHint);
|
|
52444
|
+
if (responseBeforePluginsUsage)
|
|
52445
|
+
return responseBeforePluginsUsage;
|
|
52446
|
+
const streamContent = options.streamContent ?? safeReadStreamFile(event.stream_file, options.baseDir).content;
|
|
52447
|
+
return extractTokenUsageFromSseText(streamContent ?? undefined, "stream_file", providerHint);
|
|
52448
|
+
}
|
|
52449
|
+
function extractTokenUsageSummaryFromLogEvent(event, options = {}) {
|
|
52450
|
+
const metrics = extractTokenUsageFromLogEvent(event, options);
|
|
52451
|
+
return metrics ? toTokenUsageSummary(metrics) : null;
|
|
52452
|
+
}
|
|
52453
|
+
function enrichLogEventTokenUsage(event, options = {}) {
|
|
52454
|
+
if (event.token_usage)
|
|
52455
|
+
return event;
|
|
52456
|
+
const tokenUsage = extractTokenUsageFromLogEvent(event, options);
|
|
52457
|
+
if (!tokenUsage)
|
|
52458
|
+
return event;
|
|
52459
|
+
return {
|
|
52460
|
+
...event,
|
|
52461
|
+
token_usage: tokenUsage
|
|
52462
|
+
};
|
|
52463
|
+
}
|
|
52464
|
+
|
|
51885
52465
|
// src/log-index.ts
|
|
51886
|
-
var SCHEMA_VERSION =
|
|
52466
|
+
var SCHEMA_VERSION = 3;
|
|
51887
52467
|
var MAX_INDEX_QUEUE = 20000;
|
|
51888
52468
|
var INDEX_BATCH_SIZE = 250;
|
|
51889
52469
|
var INDEX_FLUSH_DELAY_MS = 50;
|
|
@@ -52027,6 +52607,7 @@ function eventToRow(input) {
|
|
|
52027
52607
|
const statusClass = getStatusClass2(event);
|
|
52028
52608
|
const latencyMs = Math.max(0, event.latency_ms ?? 0);
|
|
52029
52609
|
const model = event.model_out || event.model_in;
|
|
52610
|
+
const tokenUsage = extractTokenUsageSummaryFromLogEvent(event, { baseDir: input.baseDir });
|
|
52030
52611
|
return {
|
|
52031
52612
|
id: input.id,
|
|
52032
52613
|
ts_ms: tsMs,
|
|
@@ -52054,8 +52635,46 @@ function eventToRow(input) {
|
|
|
52054
52635
|
line_number: input.lineNumber,
|
|
52055
52636
|
byte_offset: input.offset,
|
|
52056
52637
|
byte_length: input.byteLength,
|
|
52057
|
-
search_text: buildSearchText(event)
|
|
52058
|
-
|
|
52638
|
+
search_text: buildSearchText(event),
|
|
52639
|
+
token_input: tokenUsage?.inputTokens ?? null,
|
|
52640
|
+
token_output: tokenUsage?.outputTokens ?? null,
|
|
52641
|
+
token_total: tokenUsage?.totalTokens ?? null,
|
|
52642
|
+
token_cached_input: tokenUsage?.cachedInputTokens ?? null,
|
|
52643
|
+
token_cache_hit_input: tokenUsage?.cacheHitInputTokens ?? null,
|
|
52644
|
+
token_cache_hit_rate: tokenUsage?.cacheHitRate ?? null,
|
|
52645
|
+
token_cache_hit_rate_denominator: tokenUsage?.cacheHitRateDenominatorTokens ?? null,
|
|
52646
|
+
token_cache_read_input: tokenUsage?.cacheReadInputTokens ?? null,
|
|
52647
|
+
token_cache_creation_input: tokenUsage?.cacheCreationInputTokens ?? null,
|
|
52648
|
+
token_cache_creation_input_5m: tokenUsage?.cacheCreationInputTokens5m ?? null,
|
|
52649
|
+
token_cache_creation_input_1h: tokenUsage?.cacheCreationInputTokens1h ?? null,
|
|
52650
|
+
token_cache_write_input: tokenUsage?.cacheWriteInputTokens ?? null,
|
|
52651
|
+
token_cache_miss_input: tokenUsage?.cacheMissInputTokens ?? null,
|
|
52652
|
+
token_reasoning: tokenUsage?.reasoningTokens ?? null,
|
|
52653
|
+
token_audio_input: tokenUsage?.audioInputTokens ?? null,
|
|
52654
|
+
token_audio_output: tokenUsage?.audioOutputTokens ?? null,
|
|
52655
|
+
token_text_input: tokenUsage?.textInputTokens ?? null,
|
|
52656
|
+
token_text_output: tokenUsage?.textOutputTokens ?? null,
|
|
52657
|
+
token_accepted_prediction: tokenUsage?.acceptedPredictionTokens ?? null,
|
|
52658
|
+
token_rejected_prediction: tokenUsage?.rejectedPredictionTokens ?? null,
|
|
52659
|
+
token_tool_use_prompt: tokenUsage?.toolUsePromptTokens ?? null,
|
|
52660
|
+
token_billable_input: tokenUsage?.billableInputTokens ?? null,
|
|
52661
|
+
token_billable_output: tokenUsage?.billableOutputTokens ?? null,
|
|
52662
|
+
token_credit_usage: tokenUsage?.creditUsage ?? null,
|
|
52663
|
+
token_cost: tokenUsage?.cost ?? null,
|
|
52664
|
+
token_source: tokenUsage?.source ?? null,
|
|
52665
|
+
token_provider_style: tokenUsage?.providerStyle ?? null,
|
|
52666
|
+
token_raw_usage_path: tokenUsage?.rawUsagePath ?? null,
|
|
52667
|
+
token_usage_json: tokenUsage ? JSON.stringify(tokenUsage) : null
|
|
52668
|
+
};
|
|
52669
|
+
}
|
|
52670
|
+
function parseTokenUsageSummary(value) {
|
|
52671
|
+
if (!value)
|
|
52672
|
+
return null;
|
|
52673
|
+
try {
|
|
52674
|
+
return JSON.parse(value);
|
|
52675
|
+
} catch {
|
|
52676
|
+
return null;
|
|
52677
|
+
}
|
|
52059
52678
|
}
|
|
52060
52679
|
function rowToSummary(row) {
|
|
52061
52680
|
return {
|
|
@@ -52078,7 +52697,8 @@ function rowToSummary(row) {
|
|
|
52078
52697
|
hasMetadata: row.has_metadata === 1,
|
|
52079
52698
|
userIdRaw: row.user_id_raw,
|
|
52080
52699
|
userKey: row.user_key,
|
|
52081
|
-
sessionId: row.session_id
|
|
52700
|
+
sessionId: row.session_id,
|
|
52701
|
+
tokenUsage: parseTokenUsageSummary(row.token_usage_json)
|
|
52082
52702
|
};
|
|
52083
52703
|
}
|
|
52084
52704
|
async function* readJsonlLinesWithOffsets(filePath) {
|
|
@@ -52148,7 +52768,22 @@ function createEmptyStats() {
|
|
|
52148
52768
|
errorCount: 0,
|
|
52149
52769
|
errorRate: 0,
|
|
52150
52770
|
avgLatencyMs: 0,
|
|
52151
|
-
p95LatencyMs: 0
|
|
52771
|
+
p95LatencyMs: 0,
|
|
52772
|
+
tokenUsageCount: 0,
|
|
52773
|
+
inputTokens: 0,
|
|
52774
|
+
outputTokens: 0,
|
|
52775
|
+
totalTokens: 0,
|
|
52776
|
+
cachedInputTokens: 0,
|
|
52777
|
+
cacheHitInputTokens: 0,
|
|
52778
|
+
cacheHitRate: 0,
|
|
52779
|
+
cacheHitRateDenominatorTokens: 0,
|
|
52780
|
+
cacheReadInputTokens: 0,
|
|
52781
|
+
cacheCreationInputTokens: 0,
|
|
52782
|
+
cacheWriteInputTokens: 0,
|
|
52783
|
+
cacheMissInputTokens: 0,
|
|
52784
|
+
reasoningTokens: 0,
|
|
52785
|
+
billableInputTokens: 0,
|
|
52786
|
+
billableOutputTokens: 0
|
|
52152
52787
|
};
|
|
52153
52788
|
}
|
|
52154
52789
|
function createEmptyQueryResult(query, meta3 = {}) {
|
|
@@ -52241,12 +52876,28 @@ class LogIndex {
|
|
|
52241
52876
|
id, ts_ms, ts_start, level, provider, route_type, model, model_in, model_out,
|
|
52242
52877
|
path, request_id, latency_ms, upstream_status, status_class, has_error,
|
|
52243
52878
|
message, error_type, has_metadata, user_id_raw, user_key, session_id,
|
|
52244
|
-
source_date, source_file, line_number, byte_offset, byte_length, search_text
|
|
52879
|
+
source_date, source_file, line_number, byte_offset, byte_length, search_text,
|
|
52880
|
+
token_input, token_output, token_total, token_cached_input, token_cache_hit_input,
|
|
52881
|
+
token_cache_hit_rate, token_cache_hit_rate_denominator, token_cache_read_input,
|
|
52882
|
+
token_cache_creation_input, token_cache_creation_input_5m, token_cache_creation_input_1h,
|
|
52883
|
+
token_cache_write_input, token_cache_miss_input, token_reasoning, token_audio_input,
|
|
52884
|
+
token_audio_output, token_text_input, token_text_output, token_accepted_prediction,
|
|
52885
|
+
token_rejected_prediction, token_tool_use_prompt, token_billable_input,
|
|
52886
|
+
token_billable_output, token_credit_usage, token_cost, token_source,
|
|
52887
|
+
token_provider_style, token_raw_usage_path, token_usage_json
|
|
52245
52888
|
) VALUES (
|
|
52246
52889
|
$id, $ts_ms, $ts_start, $level, $provider, $route_type, $model, $model_in, $model_out,
|
|
52247
52890
|
$path, $request_id, $latency_ms, $upstream_status, $status_class, $has_error,
|
|
52248
52891
|
$message, $error_type, $has_metadata, $user_id_raw, $user_key, $session_id,
|
|
52249
|
-
$source_date, $source_file, $line_number, $byte_offset, $byte_length, $search_text
|
|
52892
|
+
$source_date, $source_file, $line_number, $byte_offset, $byte_length, $search_text,
|
|
52893
|
+
$token_input, $token_output, $token_total, $token_cached_input, $token_cache_hit_input,
|
|
52894
|
+
$token_cache_hit_rate, $token_cache_hit_rate_denominator, $token_cache_read_input,
|
|
52895
|
+
$token_cache_creation_input, $token_cache_creation_input_5m, $token_cache_creation_input_1h,
|
|
52896
|
+
$token_cache_write_input, $token_cache_miss_input, $token_reasoning, $token_audio_input,
|
|
52897
|
+
$token_audio_output, $token_text_input, $token_text_output, $token_accepted_prediction,
|
|
52898
|
+
$token_rejected_prediction, $token_tool_use_prompt, $token_billable_input,
|
|
52899
|
+
$token_billable_output, $token_credit_usage, $token_cost, $token_source,
|
|
52900
|
+
$token_provider_style, $token_raw_usage_path, $token_usage_json
|
|
52250
52901
|
)
|
|
52251
52902
|
`);
|
|
52252
52903
|
this.deleteFtsStmt = this.db.prepare("DELETE FROM log_events_fts WHERE event_id = ?");
|
|
@@ -52296,9 +52947,9 @@ class LogIndex {
|
|
|
52296
52947
|
const dates = listDateStrings2(fromMs, toMs);
|
|
52297
52948
|
for (const date5 of dates) {
|
|
52298
52949
|
const filePath = join4(eventsDir, `${date5}.jsonl`);
|
|
52299
|
-
if (!
|
|
52950
|
+
if (!existsSync4(filePath))
|
|
52300
52951
|
continue;
|
|
52301
|
-
const stats =
|
|
52952
|
+
const stats = statSync2(filePath);
|
|
52302
52953
|
const fileRow = this.db.query("SELECT size_bytes, mtime_ms FROM log_index_files WHERE file_path = ?").get(filePath);
|
|
52303
52954
|
const sizeBytes = stats.size;
|
|
52304
52955
|
const mtimeMs = Math.trunc(stats.mtimeMs);
|
|
@@ -52333,7 +52984,7 @@ class LogIndex {
|
|
|
52333
52984
|
e.id, e.ts_start, e.level, e.provider, e.route_type, e.model, e.model_in,
|
|
52334
52985
|
e.model_out, e.path, e.request_id, e.latency_ms, e.upstream_status,
|
|
52335
52986
|
e.status_class, e.has_error, e.message, e.error_type, e.has_metadata,
|
|
52336
|
-
e.user_id_raw, e.user_key, e.session_id, e.ts_ms
|
|
52987
|
+
e.user_id_raw, e.user_key, e.session_id, e.ts_ms, e.token_usage_json
|
|
52337
52988
|
FROM log_events e
|
|
52338
52989
|
${whereSql}
|
|
52339
52990
|
${cursorClause}
|
|
@@ -52388,7 +53039,7 @@ class LogIndex {
|
|
|
52388
53039
|
return null;
|
|
52389
53040
|
const row = this.db.query("SELECT source_date, source_file, line_number, byte_offset FROM log_events WHERE id = ?").get(id);
|
|
52390
53041
|
const filePath = row?.source_file ?? join4(this.baseDir, "events", `${parsedId.date}.jsonl`);
|
|
52391
|
-
if (!
|
|
53042
|
+
if (!existsSync4(filePath))
|
|
52392
53043
|
return null;
|
|
52393
53044
|
const line2 = readLineAtOffset(filePath, row?.byte_offset ?? parsedId.offset);
|
|
52394
53045
|
if (!line2?.trim())
|
|
@@ -52456,7 +53107,36 @@ class LogIndex {
|
|
|
52456
53107
|
line_number INTEGER,
|
|
52457
53108
|
byte_offset INTEGER NOT NULL,
|
|
52458
53109
|
byte_length INTEGER NOT NULL,
|
|
52459
|
-
search_text TEXT NOT NULL
|
|
53110
|
+
search_text TEXT NOT NULL,
|
|
53111
|
+
token_input INTEGER,
|
|
53112
|
+
token_output INTEGER,
|
|
53113
|
+
token_total INTEGER,
|
|
53114
|
+
token_cached_input INTEGER,
|
|
53115
|
+
token_cache_hit_input INTEGER,
|
|
53116
|
+
token_cache_hit_rate REAL,
|
|
53117
|
+
token_cache_hit_rate_denominator INTEGER,
|
|
53118
|
+
token_cache_read_input INTEGER,
|
|
53119
|
+
token_cache_creation_input INTEGER,
|
|
53120
|
+
token_cache_creation_input_5m INTEGER,
|
|
53121
|
+
token_cache_creation_input_1h INTEGER,
|
|
53122
|
+
token_cache_write_input INTEGER,
|
|
53123
|
+
token_cache_miss_input INTEGER,
|
|
53124
|
+
token_reasoning INTEGER,
|
|
53125
|
+
token_audio_input INTEGER,
|
|
53126
|
+
token_audio_output INTEGER,
|
|
53127
|
+
token_text_input INTEGER,
|
|
53128
|
+
token_text_output INTEGER,
|
|
53129
|
+
token_accepted_prediction INTEGER,
|
|
53130
|
+
token_rejected_prediction INTEGER,
|
|
53131
|
+
token_tool_use_prompt INTEGER,
|
|
53132
|
+
token_billable_input INTEGER,
|
|
53133
|
+
token_billable_output INTEGER,
|
|
53134
|
+
token_credit_usage REAL,
|
|
53135
|
+
token_cost REAL,
|
|
53136
|
+
token_source TEXT,
|
|
53137
|
+
token_provider_style TEXT,
|
|
53138
|
+
token_raw_usage_path TEXT,
|
|
53139
|
+
token_usage_json TEXT
|
|
52460
53140
|
);
|
|
52461
53141
|
|
|
52462
53142
|
CREATE VIRTUAL TABLE IF NOT EXISTS log_events_fts
|
|
@@ -52474,12 +53154,67 @@ class LogIndex {
|
|
|
52474
53154
|
CREATE INDEX IF NOT EXISTS idx_log_events_session_time ON log_events(session_id, ts_ms DESC);
|
|
52475
53155
|
CREATE INDEX IF NOT EXISTS idx_log_events_file ON log_events(source_file);
|
|
52476
53156
|
`);
|
|
53157
|
+
this.ensureTokenColumns();
|
|
53158
|
+
this.db.exec(`
|
|
53159
|
+
CREATE INDEX IF NOT EXISTS idx_log_events_token_total_time ON log_events(token_total, ts_ms DESC);
|
|
53160
|
+
CREATE INDEX IF NOT EXISTS idx_log_events_token_input_time ON log_events(token_input, ts_ms DESC);
|
|
53161
|
+
CREATE INDEX IF NOT EXISTS idx_log_events_token_cache_hit_rate_time ON log_events(token_cache_hit_rate, ts_ms DESC);
|
|
53162
|
+
`);
|
|
53163
|
+
const versionRow = this.db.query("SELECT value FROM log_index_meta WHERE key = 'schema_version'").get();
|
|
53164
|
+
const previousVersion = Number.parseInt(versionRow?.value ?? "0", 10) || 0;
|
|
53165
|
+
if (previousVersion > 0 && previousVersion < SCHEMA_VERSION) {
|
|
53166
|
+
this.db.exec(`
|
|
53167
|
+
DELETE FROM log_events_fts;
|
|
53168
|
+
DELETE FROM log_events;
|
|
53169
|
+
DELETE FROM log_index_files;
|
|
53170
|
+
`);
|
|
53171
|
+
}
|
|
52477
53172
|
this.db.prepare(`
|
|
52478
53173
|
INSERT INTO log_index_meta(key, value)
|
|
52479
53174
|
VALUES ('schema_version', ?)
|
|
52480
53175
|
ON CONFLICT(key) DO UPDATE SET value = excluded.value
|
|
52481
53176
|
`).run(String(SCHEMA_VERSION));
|
|
52482
53177
|
}
|
|
53178
|
+
ensureTokenColumns() {
|
|
53179
|
+
const rows = this.db.query("PRAGMA table_info(log_events)").all();
|
|
53180
|
+
const existing = new Set(rows.map((row) => row.name));
|
|
53181
|
+
const columns = [
|
|
53182
|
+
{ name: "token_input", type: "INTEGER" },
|
|
53183
|
+
{ name: "token_output", type: "INTEGER" },
|
|
53184
|
+
{ name: "token_total", type: "INTEGER" },
|
|
53185
|
+
{ name: "token_cached_input", type: "INTEGER" },
|
|
53186
|
+
{ name: "token_cache_hit_input", type: "INTEGER" },
|
|
53187
|
+
{ name: "token_cache_hit_rate", type: "REAL" },
|
|
53188
|
+
{ name: "token_cache_hit_rate_denominator", type: "INTEGER" },
|
|
53189
|
+
{ name: "token_cache_read_input", type: "INTEGER" },
|
|
53190
|
+
{ name: "token_cache_creation_input", type: "INTEGER" },
|
|
53191
|
+
{ name: "token_cache_creation_input_5m", type: "INTEGER" },
|
|
53192
|
+
{ name: "token_cache_creation_input_1h", type: "INTEGER" },
|
|
53193
|
+
{ name: "token_cache_write_input", type: "INTEGER" },
|
|
53194
|
+
{ name: "token_cache_miss_input", type: "INTEGER" },
|
|
53195
|
+
{ name: "token_reasoning", type: "INTEGER" },
|
|
53196
|
+
{ name: "token_audio_input", type: "INTEGER" },
|
|
53197
|
+
{ name: "token_audio_output", type: "INTEGER" },
|
|
53198
|
+
{ name: "token_text_input", type: "INTEGER" },
|
|
53199
|
+
{ name: "token_text_output", type: "INTEGER" },
|
|
53200
|
+
{ name: "token_accepted_prediction", type: "INTEGER" },
|
|
53201
|
+
{ name: "token_rejected_prediction", type: "INTEGER" },
|
|
53202
|
+
{ name: "token_tool_use_prompt", type: "INTEGER" },
|
|
53203
|
+
{ name: "token_billable_input", type: "INTEGER" },
|
|
53204
|
+
{ name: "token_billable_output", type: "INTEGER" },
|
|
53205
|
+
{ name: "token_credit_usage", type: "REAL" },
|
|
53206
|
+
{ name: "token_cost", type: "REAL" },
|
|
53207
|
+
{ name: "token_source", type: "TEXT" },
|
|
53208
|
+
{ name: "token_provider_style", type: "TEXT" },
|
|
53209
|
+
{ name: "token_raw_usage_path", type: "TEXT" },
|
|
53210
|
+
{ name: "token_usage_json", type: "TEXT" }
|
|
53211
|
+
];
|
|
53212
|
+
for (const column2 of columns) {
|
|
53213
|
+
if (existing.has(column2.name))
|
|
53214
|
+
continue;
|
|
53215
|
+
this.db.exec(`ALTER TABLE log_events ADD COLUMN ${column2.name} ${column2.type}`);
|
|
53216
|
+
}
|
|
53217
|
+
}
|
|
52483
53218
|
flushQueue() {
|
|
52484
53219
|
if (this.queue.length === 0 || this.disposed)
|
|
52485
53220
|
return;
|
|
@@ -52507,6 +53242,7 @@ class LogIndex {
|
|
|
52507
53242
|
return;
|
|
52508
53243
|
const id = encodeOffsetLogEventId(item.date, item.offset);
|
|
52509
53244
|
const row = eventToRow({
|
|
53245
|
+
baseDir: this.baseDir,
|
|
52510
53246
|
id,
|
|
52511
53247
|
date: item.date,
|
|
52512
53248
|
filePath: item.filePath,
|
|
@@ -52522,7 +53258,7 @@ class LogIndex {
|
|
|
52522
53258
|
this.insertFtsStmt.run(id, row.search_text);
|
|
52523
53259
|
if (!this.dirtyFiles.has(item.filePath)) {
|
|
52524
53260
|
try {
|
|
52525
|
-
const stats =
|
|
53261
|
+
const stats = statSync2(item.filePath);
|
|
52526
53262
|
const indexedThrough = item.offset + item.byteLength;
|
|
52527
53263
|
this.upsertFileStmt.run(item.filePath, item.date, Math.min(indexedThrough, stats.size), Math.trunc(stats.mtimeMs), Date.now());
|
|
52528
53264
|
} catch {}
|
|
@@ -52549,6 +53285,7 @@ class LogIndex {
|
|
|
52549
53285
|
continue;
|
|
52550
53286
|
}
|
|
52551
53287
|
const row = eventToRow({
|
|
53288
|
+
baseDir: this.baseDir,
|
|
52552
53289
|
id: encodeOffsetLogEventId(date5, item.offset),
|
|
52553
53290
|
date: date5,
|
|
52554
53291
|
filePath,
|
|
@@ -52581,7 +53318,21 @@ class LogIndex {
|
|
|
52581
53318
|
SELECT
|
|
52582
53319
|
COUNT(*) AS total,
|
|
52583
53320
|
COALESCE(SUM(has_error), 0) AS errorCount,
|
|
52584
|
-
COALESCE(AVG(latency_ms), 0) AS avgLatencyMs
|
|
53321
|
+
COALESCE(AVG(latency_ms), 0) AS avgLatencyMs,
|
|
53322
|
+
COALESCE(SUM(CASE WHEN token_usage_json IS NOT NULL THEN 1 ELSE 0 END), 0) AS tokenUsageCount,
|
|
53323
|
+
COALESCE(SUM(token_input), 0) AS inputTokens,
|
|
53324
|
+
COALESCE(SUM(token_output), 0) AS outputTokens,
|
|
53325
|
+
COALESCE(SUM(token_total), 0) AS totalTokens,
|
|
53326
|
+
COALESCE(SUM(token_cached_input), 0) AS cachedInputTokens,
|
|
53327
|
+
COALESCE(SUM(token_cache_hit_input), 0) AS cacheHitInputTokens,
|
|
53328
|
+
COALESCE(SUM(token_cache_hit_rate_denominator), 0) AS cacheHitRateDenominatorTokens,
|
|
53329
|
+
COALESCE(SUM(token_cache_read_input), 0) AS cacheReadInputTokens,
|
|
53330
|
+
COALESCE(SUM(token_cache_creation_input), 0) AS cacheCreationInputTokens,
|
|
53331
|
+
COALESCE(SUM(token_cache_write_input), 0) AS cacheWriteInputTokens,
|
|
53332
|
+
COALESCE(SUM(token_cache_miss_input), 0) AS cacheMissInputTokens,
|
|
53333
|
+
COALESCE(SUM(token_reasoning), 0) AS reasoningTokens,
|
|
53334
|
+
COALESCE(SUM(token_billable_input), 0) AS billableInputTokens,
|
|
53335
|
+
COALESCE(SUM(token_billable_output), 0) AS billableOutputTokens
|
|
52585
53336
|
FROM log_events e
|
|
52586
53337
|
${whereSql}
|
|
52587
53338
|
`).get(...params);
|
|
@@ -52602,7 +53353,22 @@ class LogIndex {
|
|
|
52602
53353
|
errorCount,
|
|
52603
53354
|
errorRate: toPercent2(errorCount, total),
|
|
52604
53355
|
avgLatencyMs: Math.round(Number(aggregate.avgLatencyMs) || 0),
|
|
52605
|
-
p95LatencyMs: Math.round(p95Row?.latency_ms ?? 0)
|
|
53356
|
+
p95LatencyMs: Math.round(p95Row?.latency_ms ?? 0),
|
|
53357
|
+
tokenUsageCount: Number(aggregate.tokenUsageCount) || 0,
|
|
53358
|
+
inputTokens: Number(aggregate.inputTokens) || 0,
|
|
53359
|
+
outputTokens: Number(aggregate.outputTokens) || 0,
|
|
53360
|
+
totalTokens: Number(aggregate.totalTokens) || 0,
|
|
53361
|
+
cachedInputTokens: Number(aggregate.cachedInputTokens) || 0,
|
|
53362
|
+
cacheHitInputTokens: Number(aggregate.cacheHitInputTokens) || 0,
|
|
53363
|
+
cacheHitRate: toPercent2(Number(aggregate.cacheHitInputTokens) || 0, Number(aggregate.cacheHitRateDenominatorTokens) || 0),
|
|
53364
|
+
cacheHitRateDenominatorTokens: Number(aggregate.cacheHitRateDenominatorTokens) || 0,
|
|
53365
|
+
cacheReadInputTokens: Number(aggregate.cacheReadInputTokens) || 0,
|
|
53366
|
+
cacheCreationInputTokens: Number(aggregate.cacheCreationInputTokens) || 0,
|
|
53367
|
+
cacheWriteInputTokens: Number(aggregate.cacheWriteInputTokens) || 0,
|
|
53368
|
+
cacheMissInputTokens: Number(aggregate.cacheMissInputTokens) || 0,
|
|
53369
|
+
reasoningTokens: Number(aggregate.reasoningTokens) || 0,
|
|
53370
|
+
billableInputTokens: Number(aggregate.billableInputTokens) || 0,
|
|
53371
|
+
billableOutputTokens: Number(aggregate.billableOutputTokens) || 0
|
|
52606
53372
|
};
|
|
52607
53373
|
}
|
|
52608
53374
|
}
|
|
@@ -52683,7 +53449,7 @@ function getIndexedLogEventDetail(logConfig, id) {
|
|
|
52683
53449
|
if (!parsedId)
|
|
52684
53450
|
return null;
|
|
52685
53451
|
const filePath = join4(baseDir, "events", `${parsedId.date}.jsonl`);
|
|
52686
|
-
if (!
|
|
53452
|
+
if (!existsSync4(filePath))
|
|
52687
53453
|
return null;
|
|
52688
53454
|
const line2 = readLineAtOffset(filePath, parsedId.offset);
|
|
52689
53455
|
if (!line2?.trim())
|
|
@@ -52816,8 +53582,25 @@ function createRunningStats() {
|
|
|
52816
53582
|
total: 0,
|
|
52817
53583
|
errorCount: 0,
|
|
52818
53584
|
latencySum: 0,
|
|
52819
|
-
latencyCounts: new Map
|
|
52820
|
-
|
|
53585
|
+
latencyCounts: new Map,
|
|
53586
|
+
tokenUsageCount: 0,
|
|
53587
|
+
inputTokens: 0,
|
|
53588
|
+
outputTokens: 0,
|
|
53589
|
+
totalTokens: 0,
|
|
53590
|
+
cachedInputTokens: 0,
|
|
53591
|
+
cacheHitInputTokens: 0,
|
|
53592
|
+
cacheHitRateDenominatorTokens: 0,
|
|
53593
|
+
cacheReadInputTokens: 0,
|
|
53594
|
+
cacheCreationInputTokens: 0,
|
|
53595
|
+
cacheWriteInputTokens: 0,
|
|
53596
|
+
cacheMissInputTokens: 0,
|
|
53597
|
+
reasoningTokens: 0,
|
|
53598
|
+
billableInputTokens: 0,
|
|
53599
|
+
billableOutputTokens: 0
|
|
53600
|
+
};
|
|
53601
|
+
}
|
|
53602
|
+
function addNullable(total, value) {
|
|
53603
|
+
return total + (value ?? 0);
|
|
52821
53604
|
}
|
|
52822
53605
|
function updateRunningStats(stats, item) {
|
|
52823
53606
|
stats.total += 1;
|
|
@@ -52828,6 +53611,23 @@ function updateRunningStats(stats, item) {
|
|
|
52828
53611
|
stats.latencySum += latency;
|
|
52829
53612
|
const roundedLatency = Math.round(latency);
|
|
52830
53613
|
stats.latencyCounts.set(roundedLatency, (stats.latencyCounts.get(roundedLatency) ?? 0) + 1);
|
|
53614
|
+
const usage = item.tokenUsage;
|
|
53615
|
+
if (!usage)
|
|
53616
|
+
return;
|
|
53617
|
+
stats.tokenUsageCount += 1;
|
|
53618
|
+
stats.inputTokens = addNullable(stats.inputTokens, usage.inputTokens);
|
|
53619
|
+
stats.outputTokens = addNullable(stats.outputTokens, usage.outputTokens);
|
|
53620
|
+
stats.totalTokens = addNullable(stats.totalTokens, usage.totalTokens);
|
|
53621
|
+
stats.cachedInputTokens = addNullable(stats.cachedInputTokens, usage.cachedInputTokens);
|
|
53622
|
+
stats.cacheHitInputTokens = addNullable(stats.cacheHitInputTokens, usage.cacheHitInputTokens);
|
|
53623
|
+
stats.cacheHitRateDenominatorTokens = addNullable(stats.cacheHitRateDenominatorTokens, usage.cacheHitRateDenominatorTokens);
|
|
53624
|
+
stats.cacheReadInputTokens = addNullable(stats.cacheReadInputTokens, usage.cacheReadInputTokens);
|
|
53625
|
+
stats.cacheCreationInputTokens = addNullable(stats.cacheCreationInputTokens, usage.cacheCreationInputTokens);
|
|
53626
|
+
stats.cacheWriteInputTokens = addNullable(stats.cacheWriteInputTokens, usage.cacheWriteInputTokens);
|
|
53627
|
+
stats.cacheMissInputTokens = addNullable(stats.cacheMissInputTokens, usage.cacheMissInputTokens);
|
|
53628
|
+
stats.reasoningTokens = addNullable(stats.reasoningTokens, usage.reasoningTokens);
|
|
53629
|
+
stats.billableInputTokens = addNullable(stats.billableInputTokens, usage.billableInputTokens);
|
|
53630
|
+
stats.billableOutputTokens = addNullable(stats.billableOutputTokens, usage.billableOutputTokens);
|
|
52831
53631
|
}
|
|
52832
53632
|
function percentileFromCounts(latencyCounts, total, ratio) {
|
|
52833
53633
|
if (total <= 0 || latencyCounts.size === 0)
|
|
@@ -52850,7 +53650,22 @@ function finalizeStats(stats) {
|
|
|
52850
53650
|
errorCount: 0,
|
|
52851
53651
|
errorRate: 0,
|
|
52852
53652
|
avgLatencyMs: 0,
|
|
52853
|
-
p95LatencyMs: 0
|
|
53653
|
+
p95LatencyMs: 0,
|
|
53654
|
+
tokenUsageCount: 0,
|
|
53655
|
+
inputTokens: 0,
|
|
53656
|
+
outputTokens: 0,
|
|
53657
|
+
totalTokens: 0,
|
|
53658
|
+
cachedInputTokens: 0,
|
|
53659
|
+
cacheHitInputTokens: 0,
|
|
53660
|
+
cacheHitRate: 0,
|
|
53661
|
+
cacheHitRateDenominatorTokens: 0,
|
|
53662
|
+
cacheReadInputTokens: 0,
|
|
53663
|
+
cacheCreationInputTokens: 0,
|
|
53664
|
+
cacheWriteInputTokens: 0,
|
|
53665
|
+
cacheMissInputTokens: 0,
|
|
53666
|
+
reasoningTokens: 0,
|
|
53667
|
+
billableInputTokens: 0,
|
|
53668
|
+
billableOutputTokens: 0
|
|
52854
53669
|
};
|
|
52855
53670
|
}
|
|
52856
53671
|
return {
|
|
@@ -52858,8 +53673,26 @@ function finalizeStats(stats) {
|
|
|
52858
53673
|
errorCount: stats.errorCount,
|
|
52859
53674
|
errorRate: toPercent3(stats.errorCount, stats.total),
|
|
52860
53675
|
avgLatencyMs: Math.round(stats.latencySum / stats.total),
|
|
52861
|
-
p95LatencyMs: percentileFromCounts(stats.latencyCounts, stats.total, 0.95)
|
|
52862
|
-
|
|
53676
|
+
p95LatencyMs: percentileFromCounts(stats.latencyCounts, stats.total, 0.95),
|
|
53677
|
+
tokenUsageCount: stats.tokenUsageCount,
|
|
53678
|
+
inputTokens: stats.inputTokens,
|
|
53679
|
+
outputTokens: stats.outputTokens,
|
|
53680
|
+
totalTokens: stats.totalTokens,
|
|
53681
|
+
cachedInputTokens: stats.cachedInputTokens,
|
|
53682
|
+
cacheHitInputTokens: stats.cacheHitInputTokens,
|
|
53683
|
+
cacheHitRate: toPercent3(stats.cacheHitInputTokens, stats.cacheHitRateDenominatorTokens),
|
|
53684
|
+
cacheHitRateDenominatorTokens: stats.cacheHitRateDenominatorTokens,
|
|
53685
|
+
cacheReadInputTokens: stats.cacheReadInputTokens,
|
|
53686
|
+
cacheCreationInputTokens: stats.cacheCreationInputTokens,
|
|
53687
|
+
cacheWriteInputTokens: stats.cacheWriteInputTokens,
|
|
53688
|
+
cacheMissInputTokens: stats.cacheMissInputTokens,
|
|
53689
|
+
reasoningTokens: stats.reasoningTokens,
|
|
53690
|
+
billableInputTokens: stats.billableInputTokens,
|
|
53691
|
+
billableOutputTokens: stats.billableOutputTokens
|
|
53692
|
+
};
|
|
53693
|
+
}
|
|
53694
|
+
function createEmptyLogQueryStats() {
|
|
53695
|
+
return finalizeStats(createRunningStats());
|
|
52863
53696
|
}
|
|
52864
53697
|
function compareLocatedEvents(a, b, sort) {
|
|
52865
53698
|
if (a.ts !== b.ts) {
|
|
@@ -52931,7 +53764,8 @@ function eventToSummary(item) {
|
|
|
52931
53764
|
hasMetadata: identity.hasMetadata,
|
|
52932
53765
|
userIdRaw: identity.userIdRaw,
|
|
52933
53766
|
userKey: identity.userKey,
|
|
52934
|
-
sessionId: identity.sessionId
|
|
53767
|
+
sessionId: identity.sessionId,
|
|
53768
|
+
tokenUsage: item.tokenUsage
|
|
52935
53769
|
};
|
|
52936
53770
|
}
|
|
52937
53771
|
function createLogEventSummaryFromEvent(event, location) {
|
|
@@ -52943,7 +53777,8 @@ function createLogEventSummaryFromEvent(event, location) {
|
|
|
52943
53777
|
ts: Number.isFinite(ts) ? ts : 0,
|
|
52944
53778
|
level: getLevel2(event),
|
|
52945
53779
|
statusClass: getStatusClass3(event),
|
|
52946
|
-
event
|
|
53780
|
+
event,
|
|
53781
|
+
tokenUsage: extractTokenUsageSummaryFromLogEvent(event)
|
|
52947
53782
|
});
|
|
52948
53783
|
}
|
|
52949
53784
|
function logEventMatchesQuery(event, query) {
|
|
@@ -53032,23 +53867,23 @@ function readStreamContent(baseDir, streamFile) {
|
|
|
53032
53867
|
if (!streamFile)
|
|
53033
53868
|
return { content: null, warning: null };
|
|
53034
53869
|
try {
|
|
53035
|
-
const resolvedBase =
|
|
53036
|
-
const resolvedFromFile =
|
|
53870
|
+
const resolvedBase = resolve5(baseDir);
|
|
53871
|
+
const resolvedFromFile = resolve5(streamFile);
|
|
53037
53872
|
const looksLikeStreamFile = resolvedFromFile.endsWith(".sse.raw");
|
|
53038
53873
|
if (!looksLikeStreamFile) {
|
|
53039
53874
|
return { content: null, warning: "stream_file \u4E0D\u662F .sse.raw \u6587\u4EF6\uFF0C\u5DF2\u8DF3\u8FC7\u8BFB\u53D6\u3002" };
|
|
53040
53875
|
}
|
|
53041
|
-
if (
|
|
53042
|
-
return { content:
|
|
53876
|
+
if (existsSync5(resolvedFromFile)) {
|
|
53877
|
+
return { content: readFileSync4(resolvedFromFile, "utf-8"), warning: null };
|
|
53043
53878
|
}
|
|
53044
|
-
const fallbackPath =
|
|
53879
|
+
const fallbackPath = resolve5(resolvedBase, streamFile);
|
|
53045
53880
|
if (!fallbackPath.startsWith(`${resolvedBase}/`) && fallbackPath !== resolvedBase) {
|
|
53046
53881
|
return { content: null, warning: "stream_file \u8DEF\u5F84\u975E\u6CD5\uFF0C\u5DF2\u62D2\u7EDD\u8BFB\u53D6\u3002" };
|
|
53047
53882
|
}
|
|
53048
|
-
if (!
|
|
53883
|
+
if (!existsSync5(fallbackPath)) {
|
|
53049
53884
|
return { content: null, warning: "stream_file \u4E0D\u5B58\u5728\uFF0C\u53EF\u80FD\u5DF2\u88AB\u6E05\u7406\u3002" };
|
|
53050
53885
|
}
|
|
53051
|
-
return { content:
|
|
53886
|
+
return { content: readFileSync4(fallbackPath, "utf-8"), warning: null };
|
|
53052
53887
|
} catch (err) {
|
|
53053
53888
|
return {
|
|
53054
53889
|
content: null,
|
|
@@ -53065,6 +53900,10 @@ async function buildLogEventDetail(id, parsed, location, context2) {
|
|
|
53065
53900
|
const responseBodyAvailable = event.response_body !== undefined;
|
|
53066
53901
|
const streamCaptured = Boolean(event.stream_file);
|
|
53067
53902
|
const { content: streamContent, warning: streamWarning } = readStreamContent(resolveLogBaseDir(context2.logConfig), event.stream_file);
|
|
53903
|
+
const tokenUsage = extractTokenUsageSummaryFromLogEvent(event, {
|
|
53904
|
+
baseDir: resolveLogBaseDir(context2.logConfig),
|
|
53905
|
+
streamContent: streamContent ?? undefined
|
|
53906
|
+
}) ?? null;
|
|
53068
53907
|
const hasPluginData = event.plugins_request || event.plugins_response || event.request_body_after_plugins !== undefined || event.request_url_after_plugins !== undefined || event.response_body_before_plugins !== undefined || event.response_body_after_plugins !== undefined;
|
|
53069
53908
|
const pluginsSection = hasPluginData ? {
|
|
53070
53909
|
request: event.plugins_request,
|
|
@@ -53090,7 +53929,16 @@ async function buildLogEventDetail(id, parsed, location, context2) {
|
|
|
53090
53929
|
hasError: level === "error",
|
|
53091
53930
|
model: event.model_out || event.model_in,
|
|
53092
53931
|
modelIn: event.model_in,
|
|
53093
|
-
modelOut: event.model_out
|
|
53932
|
+
modelOut: event.model_out,
|
|
53933
|
+
tokenUsage
|
|
53934
|
+
},
|
|
53935
|
+
usage: {
|
|
53936
|
+
tokenUsage,
|
|
53937
|
+
requestBytes: event.request_bytes ?? 0,
|
|
53938
|
+
responseBytes: event.response_bytes ?? null,
|
|
53939
|
+
streamBytes: event.stream_bytes ?? null,
|
|
53940
|
+
streamFileBytes: event.stream_file_bytes ?? null,
|
|
53941
|
+
streamFileTruncated: event.stream_file_truncated === true
|
|
53094
53942
|
},
|
|
53095
53943
|
request: {
|
|
53096
53944
|
method: event.method,
|
|
@@ -53132,16 +53980,10 @@ async function buildLogEventDetail(id, parsed, location, context2) {
|
|
|
53132
53980
|
}
|
|
53133
53981
|
async function scanEvents(baseDir, query) {
|
|
53134
53982
|
const eventsDir = join5(baseDir, "events");
|
|
53135
|
-
if (!
|
|
53983
|
+
if (!existsSync5(eventsDir)) {
|
|
53136
53984
|
return {
|
|
53137
53985
|
items: [],
|
|
53138
|
-
stats:
|
|
53139
|
-
total: 0,
|
|
53140
|
-
errorCount: 0,
|
|
53141
|
-
errorRate: 0,
|
|
53142
|
-
avgLatencyMs: 0,
|
|
53143
|
-
p95LatencyMs: 0
|
|
53144
|
-
},
|
|
53986
|
+
stats: createEmptyLogQueryStats(),
|
|
53145
53987
|
meta: {
|
|
53146
53988
|
scannedFiles: 0,
|
|
53147
53989
|
scannedLines: 0,
|
|
@@ -53165,7 +54007,7 @@ async function scanEvents(baseDir, query) {
|
|
|
53165
54007
|
break;
|
|
53166
54008
|
}
|
|
53167
54009
|
const filePath = join5(eventsDir, `${date5}.jsonl`);
|
|
53168
|
-
if (!
|
|
54010
|
+
if (!existsSync5(filePath))
|
|
53169
54011
|
continue;
|
|
53170
54012
|
scannedFiles += 1;
|
|
53171
54013
|
const stream = createReadStream3(filePath, { encoding: "utf-8" });
|
|
@@ -53227,6 +54069,7 @@ async function scanEvents(baseDir, query) {
|
|
|
53227
54069
|
continue;
|
|
53228
54070
|
if (!containsKeyword(event, query.q))
|
|
53229
54071
|
continue;
|
|
54072
|
+
const tokenUsage = extractTokenUsageSummaryFromLogEvent(event, { baseDir });
|
|
53230
54073
|
const located = {
|
|
53231
54074
|
id: encodeEventId(date5, lineNumber),
|
|
53232
54075
|
date: date5,
|
|
@@ -53234,7 +54077,8 @@ async function scanEvents(baseDir, query) {
|
|
|
53234
54077
|
ts,
|
|
53235
54078
|
level,
|
|
53236
54079
|
statusClass,
|
|
53237
|
-
event
|
|
54080
|
+
event,
|
|
54081
|
+
tokenUsage
|
|
53238
54082
|
};
|
|
53239
54083
|
updateRunningStats(runningStats, located);
|
|
53240
54084
|
insertBoundedEvent(items, located, query.sort, maxKeep);
|
|
@@ -53294,13 +54138,7 @@ async function queryLogEventsInternal(context2, input, maxLimit) {
|
|
|
53294
54138
|
items: [],
|
|
53295
54139
|
nextCursor: null,
|
|
53296
54140
|
hasMore: false,
|
|
53297
|
-
stats:
|
|
53298
|
-
total: 0,
|
|
53299
|
-
errorCount: 0,
|
|
53300
|
-
errorRate: 0,
|
|
53301
|
-
avgLatencyMs: 0,
|
|
53302
|
-
p95LatencyMs: 0
|
|
53303
|
-
},
|
|
54141
|
+
stats: createEmptyLogQueryStats(),
|
|
53304
54142
|
meta: {
|
|
53305
54143
|
scannedFiles: 0,
|
|
53306
54144
|
scannedLines: 0,
|
|
@@ -53352,7 +54190,7 @@ async function getLogEventDetailById(context2, id) {
|
|
|
53352
54190
|
const { date: date5, line: line2 } = decodeEventId(id);
|
|
53353
54191
|
const baseDir = resolveLogBaseDir(context2.logConfig);
|
|
53354
54192
|
const filePath = join5(baseDir, "events", `${date5}.jsonl`);
|
|
53355
|
-
if (!
|
|
54193
|
+
if (!existsSync5(filePath))
|
|
53356
54194
|
return null;
|
|
53357
54195
|
const stream = createReadStream3(filePath, { encoding: "utf-8" });
|
|
53358
54196
|
const rl = createInterface2({ input: stream, crlfDelay: Number.POSITIVE_INFINITY });
|
|
@@ -53383,6 +54221,7 @@ function escapeCsvValue(value) {
|
|
|
53383
54221
|
return text2;
|
|
53384
54222
|
}
|
|
53385
54223
|
function toCsvRow(item) {
|
|
54224
|
+
const usage = item.tokenUsage;
|
|
53386
54225
|
return [
|
|
53387
54226
|
item.id,
|
|
53388
54227
|
item.ts,
|
|
@@ -53403,7 +54242,36 @@ function toCsvRow(item) {
|
|
|
53403
54242
|
item.userKey ?? "",
|
|
53404
54243
|
item.sessionId ?? "",
|
|
53405
54244
|
item.message,
|
|
53406
|
-
item.errorType ?? ""
|
|
54245
|
+
item.errorType ?? "",
|
|
54246
|
+
usage?.inputTokens ?? "",
|
|
54247
|
+
usage?.outputTokens ?? "",
|
|
54248
|
+
usage?.totalTokens ?? "",
|
|
54249
|
+
usage?.cachedInputTokens ?? "",
|
|
54250
|
+
usage?.cacheHitInputTokens ?? "",
|
|
54251
|
+
usage?.cacheHitRate ?? "",
|
|
54252
|
+
usage?.cacheHitRateDenominatorTokens ?? "",
|
|
54253
|
+
usage?.cacheReadInputTokens ?? "",
|
|
54254
|
+
usage?.cacheCreationInputTokens ?? "",
|
|
54255
|
+
usage?.cacheCreationInputTokens5m ?? "",
|
|
54256
|
+
usage?.cacheCreationInputTokens1h ?? "",
|
|
54257
|
+
usage?.cacheWriteInputTokens ?? "",
|
|
54258
|
+
usage?.cacheMissInputTokens ?? "",
|
|
54259
|
+
usage?.reasoningTokens ?? "",
|
|
54260
|
+
usage?.audioInputTokens ?? "",
|
|
54261
|
+
usage?.audioOutputTokens ?? "",
|
|
54262
|
+
usage?.textInputTokens ?? "",
|
|
54263
|
+
usage?.textOutputTokens ?? "",
|
|
54264
|
+
usage?.acceptedPredictionTokens ?? "",
|
|
54265
|
+
usage?.rejectedPredictionTokens ?? "",
|
|
54266
|
+
usage?.toolUsePromptTokens ?? "",
|
|
54267
|
+
usage?.billableInputTokens ?? "",
|
|
54268
|
+
usage?.billableOutputTokens ?? "",
|
|
54269
|
+
usage?.creditUsage ?? "",
|
|
54270
|
+
usage?.cost ?? "",
|
|
54271
|
+
usage?.providerStyle ?? "",
|
|
54272
|
+
usage?.source ?? "",
|
|
54273
|
+
usage?.rawUsagePath ?? "",
|
|
54274
|
+
usage?.cacheHitRateFormula ?? ""
|
|
53407
54275
|
].map(escapeCsvValue).join(",");
|
|
53408
54276
|
}
|
|
53409
54277
|
function createCsvExportStream(items) {
|
|
@@ -53428,7 +54296,36 @@ function createCsvExportStream(items) {
|
|
|
53428
54296
|
"userKey",
|
|
53429
54297
|
"sessionId",
|
|
53430
54298
|
"message",
|
|
53431
|
-
"errorType"
|
|
54299
|
+
"errorType",
|
|
54300
|
+
"usage.inputTokens",
|
|
54301
|
+
"usage.outputTokens",
|
|
54302
|
+
"usage.totalTokens",
|
|
54303
|
+
"usage.cachedInputTokens",
|
|
54304
|
+
"usage.cacheHitInputTokens",
|
|
54305
|
+
"usage.cacheHitRate",
|
|
54306
|
+
"usage.cacheHitRateDenominatorTokens",
|
|
54307
|
+
"usage.cacheReadInputTokens",
|
|
54308
|
+
"usage.cacheCreationInputTokens",
|
|
54309
|
+
"usage.cacheCreationInputTokens5m",
|
|
54310
|
+
"usage.cacheCreationInputTokens1h",
|
|
54311
|
+
"usage.cacheWriteInputTokens",
|
|
54312
|
+
"usage.cacheMissInputTokens",
|
|
54313
|
+
"usage.reasoningTokens",
|
|
54314
|
+
"usage.audioInputTokens",
|
|
54315
|
+
"usage.audioOutputTokens",
|
|
54316
|
+
"usage.textInputTokens",
|
|
54317
|
+
"usage.textOutputTokens",
|
|
54318
|
+
"usage.acceptedPredictionTokens",
|
|
54319
|
+
"usage.rejectedPredictionTokens",
|
|
54320
|
+
"usage.toolUsePromptTokens",
|
|
54321
|
+
"usage.billableInputTokens",
|
|
54322
|
+
"usage.billableOutputTokens",
|
|
54323
|
+
"usage.creditUsage",
|
|
54324
|
+
"usage.cost",
|
|
54325
|
+
"usage.providerStyle",
|
|
54326
|
+
"usage.source",
|
|
54327
|
+
"usage.rawUsagePath",
|
|
54328
|
+
"usage.cacheHitRateFormula"
|
|
53432
54329
|
];
|
|
53433
54330
|
return new ReadableStream({
|
|
53434
54331
|
start(controller) {
|
|
@@ -53507,7 +54404,7 @@ function parseBooleanFlag(value) {
|
|
|
53507
54404
|
}
|
|
53508
54405
|
|
|
53509
54406
|
// src/log-sessions.ts
|
|
53510
|
-
import { createReadStream as createReadStream4, existsSync as
|
|
54407
|
+
import { createReadStream as createReadStream4, existsSync as existsSync6 } from "fs";
|
|
53511
54408
|
import { join as join6 } from "path";
|
|
53512
54409
|
import { createInterface as createInterface3 } from "readline";
|
|
53513
54410
|
var MAX_LINES_SCANNED3 = 250000;
|
|
@@ -53630,7 +54527,7 @@ async function queryLogSessions(context2, input) {
|
|
|
53630
54527
|
}
|
|
53631
54528
|
const baseDir = resolveLogBaseDir(context2.logConfig);
|
|
53632
54529
|
const eventsDir = join6(baseDir, "events");
|
|
53633
|
-
if (!
|
|
54530
|
+
if (!existsSync6(eventsDir)) {
|
|
53634
54531
|
return createEmptyResult(normalized.fromMs, normalized.toMs);
|
|
53635
54532
|
}
|
|
53636
54533
|
const usersMap = new Map;
|
|
@@ -53649,7 +54546,7 @@ async function queryLogSessions(context2, input) {
|
|
|
53649
54546
|
break;
|
|
53650
54547
|
}
|
|
53651
54548
|
const filePath = join6(eventsDir, `${date5}.jsonl`);
|
|
53652
|
-
if (!
|
|
54549
|
+
if (!existsSync6(filePath))
|
|
53653
54550
|
continue;
|
|
53654
54551
|
scannedFiles += 1;
|
|
53655
54552
|
const stream = createReadStream4(filePath, { encoding: "utf-8" });
|
|
@@ -53757,7 +54654,7 @@ async function queryLogSessions(context2, input) {
|
|
|
53757
54654
|
}
|
|
53758
54655
|
|
|
53759
54656
|
// src/log-storage.ts
|
|
53760
|
-
import { existsSync as
|
|
54657
|
+
import { existsSync as existsSync7, promises as fsPromises } from "fs";
|
|
53761
54658
|
import { join as join7 } from "path";
|
|
53762
54659
|
var cachedStorage = null;
|
|
53763
54660
|
var calculationPromise = null;
|
|
@@ -53766,7 +54663,7 @@ var CACHE_TTL_MS2 = 60 * 60 * 1000;
|
|
|
53766
54663
|
var CALCULATION_INTERVAL_MS = 60 * 60 * 1000;
|
|
53767
54664
|
var MIN_CALCULATION_INTERVAL_MS = 5 * 60 * 1000;
|
|
53768
54665
|
async function calculateDirSize(dirPath) {
|
|
53769
|
-
if (!
|
|
54666
|
+
if (!existsSync7(dirPath)) {
|
|
53770
54667
|
return { bytes: 0, fileCount: 0 };
|
|
53771
54668
|
}
|
|
53772
54669
|
let bytes = 0;
|
|
@@ -53821,7 +54718,7 @@ async function doCalculateStorage(logConfig) {
|
|
|
53821
54718
|
};
|
|
53822
54719
|
}
|
|
53823
54720
|
async function calculateIndexSize(baseDir) {
|
|
53824
|
-
if (!
|
|
54721
|
+
if (!existsSync7(baseDir)) {
|
|
53825
54722
|
return { bytes: 0, fileCount: 0 };
|
|
53826
54723
|
}
|
|
53827
54724
|
let bytes = 0;
|
|
@@ -53902,10 +54799,10 @@ function subscribeLogEvents(subscriber) {
|
|
|
53902
54799
|
import {
|
|
53903
54800
|
appendFileSync,
|
|
53904
54801
|
closeSync as closeSync2,
|
|
53905
|
-
existsSync as
|
|
54802
|
+
existsSync as existsSync8,
|
|
53906
54803
|
mkdirSync as mkdirSync3,
|
|
53907
54804
|
openSync as openSync2,
|
|
53908
|
-
statSync as
|
|
54805
|
+
statSync as statSync3,
|
|
53909
54806
|
writeSync
|
|
53910
54807
|
} from "fs";
|
|
53911
54808
|
import { join as join8 } from "path";
|
|
@@ -53936,13 +54833,13 @@ class Logger {
|
|
|
53936
54833
|
}
|
|
53937
54834
|
ensureDirs() {
|
|
53938
54835
|
for (const dir of [this.baseDir, this.eventsDir, this.streamsDir]) {
|
|
53939
|
-
if (!
|
|
54836
|
+
if (!existsSync8(dir))
|
|
53940
54837
|
mkdirSync3(dir, { recursive: true });
|
|
53941
54838
|
}
|
|
53942
54839
|
}
|
|
53943
54840
|
ensureStreamDateDir(dateStr) {
|
|
53944
54841
|
const dir = join8(this.streamsDir, dateStr);
|
|
53945
|
-
if (!
|
|
54842
|
+
if (!existsSync8(dir))
|
|
53946
54843
|
mkdirSync3(dir, { recursive: true });
|
|
53947
54844
|
return dir;
|
|
53948
54845
|
}
|
|
@@ -53950,11 +54847,12 @@ class Logger {
|
|
|
53950
54847
|
if (!this._enabled)
|
|
53951
54848
|
return;
|
|
53952
54849
|
try {
|
|
54850
|
+
const enrichedEvent = enrichLogEventTokenUsage(event, { baseDir: this.baseDir });
|
|
53953
54851
|
this.ensureDirs();
|
|
53954
|
-
const dateStr =
|
|
54852
|
+
const dateStr = enrichedEvent.ts_start.slice(0, 10);
|
|
53955
54853
|
const filePath = join8(this.eventsDir, `${dateStr}.jsonl`);
|
|
53956
|
-
const offset =
|
|
53957
|
-
const line2 = `${JSON.stringify(
|
|
54854
|
+
const offset = existsSync8(filePath) ? statSync3(filePath).size : 0;
|
|
54855
|
+
const line2 = `${JSON.stringify(enrichedEvent)}
|
|
53958
54856
|
`;
|
|
53959
54857
|
appendFileSync(filePath, line2);
|
|
53960
54858
|
const id = encodeOffsetLogEventId(dateStr, offset);
|
|
@@ -53964,9 +54862,9 @@ class Logger {
|
|
|
53964
54862
|
date: dateStr,
|
|
53965
54863
|
offset,
|
|
53966
54864
|
byteLength: Buffer.byteLength(line2),
|
|
53967
|
-
event
|
|
54865
|
+
event: enrichedEvent
|
|
53968
54866
|
});
|
|
53969
|
-
publishLogEvent({ id, date: dateStr, filePath, offset, event });
|
|
54867
|
+
publishLogEvent({ id, date: dateStr, filePath, offset, event: enrichedEvent });
|
|
53970
54868
|
} catch (err) {
|
|
53971
54869
|
console.error("[logger] \u4E8B\u4EF6\u65E5\u5FD7\u5199\u5165\u5931\u8D25:", err);
|
|
53972
54870
|
}
|
|
@@ -55257,7 +56155,7 @@ var openAPISpec = {
|
|
|
55257
56155
|
// src/plugin-loader.ts
|
|
55258
56156
|
import { mkdtemp, rm, writeFile } from "fs/promises";
|
|
55259
56157
|
import { tmpdir } from "os";
|
|
55260
|
-
import { join as join9, resolve as
|
|
56158
|
+
import { join as join9, resolve as resolve6 } from "path";
|
|
55261
56159
|
function isLocalPath(pkg) {
|
|
55262
56160
|
return pkg.startsWith("./") || pkg.startsWith("../") || pkg.startsWith("/") || /^[A-Za-z]:[\\/]/.test(pkg);
|
|
55263
56161
|
}
|
|
@@ -55313,7 +56211,7 @@ async function importPlugin(pkg, configDir) {
|
|
|
55313
56211
|
const localPath = await fetchRemotePlugin(pkg);
|
|
55314
56212
|
modulePath = `${localPath}?t=${Date.now()}`;
|
|
55315
56213
|
} else if (isLocalPath(pkg)) {
|
|
55316
|
-
const absolutePath =
|
|
56214
|
+
const absolutePath = resolve6(configDir, pkg);
|
|
55317
56215
|
modulePath = `${absolutePath}?t=${Date.now()}`;
|
|
55318
56216
|
} else {
|
|
55319
56217
|
modulePath = pkg;
|
|
@@ -55706,6 +56604,7 @@ async function proxyRequest(c2, options) {
|
|
|
55706
56604
|
});
|
|
55707
56605
|
}
|
|
55708
56606
|
const capture = logger?.openStreamCapture(logMeta.requestId, dateStr) ?? null;
|
|
56607
|
+
const tokenUsageCollector = createTokenUsageStreamCollector(`${logMeta.provider} ${logMeta.routeType} ${logMeta.modelIn} ${logMeta.modelOut}`);
|
|
55709
56608
|
let upstreamBytes = 0;
|
|
55710
56609
|
let writeEventCalled = false;
|
|
55711
56610
|
const finalizeAndWriteEvent = () => {
|
|
@@ -55717,6 +56616,7 @@ async function proxyRequest(c2, options) {
|
|
|
55717
56616
|
truncated: false,
|
|
55718
56617
|
filePath: null
|
|
55719
56618
|
};
|
|
56619
|
+
const tokenUsage2 = tokenUsageCollector.getUsage();
|
|
55720
56620
|
logger?.writeEvent(buildLogEvent(logMeta, targetUrl, proxy, Date.now(), {
|
|
55721
56621
|
upstream_status: sseStatus,
|
|
55722
56622
|
content_type_res: contentTypeRes,
|
|
@@ -55728,6 +56628,7 @@ async function proxyRequest(c2, options) {
|
|
|
55728
56628
|
stream_file_bytes: captureResult.bytesWritten
|
|
55729
56629
|
},
|
|
55730
56630
|
...captureResult.truncated && { stream_file_truncated: true },
|
|
56631
|
+
...tokenUsage2 && { token_usage: tokenUsage2 },
|
|
55731
56632
|
...requestBody !== undefined && { request_body: requestBody },
|
|
55732
56633
|
...pluginLogOverrides
|
|
55733
56634
|
}));
|
|
@@ -55743,6 +56644,7 @@ async function proxyRequest(c2, options) {
|
|
|
55743
56644
|
return;
|
|
55744
56645
|
}
|
|
55745
56646
|
upstreamBytes += value.byteLength;
|
|
56647
|
+
tokenUsageCollector.addChunk(value);
|
|
55746
56648
|
capture?.write(value);
|
|
55747
56649
|
controller.enqueue(value);
|
|
55748
56650
|
} catch (err) {
|
|
@@ -55793,12 +56695,14 @@ async function proxyRequest(c2, options) {
|
|
|
55793
56695
|
});
|
|
55794
56696
|
}
|
|
55795
56697
|
const responseBytes = Buffer.byteLength(responseText, "utf-8");
|
|
56698
|
+
const tokenUsage = extractTokenUsageFromResponseText(responseText, "response_body", `${logMeta.provider} ${logMeta.routeType} ${logMeta.modelIn} ${logMeta.modelOut}`);
|
|
55796
56699
|
const eventOverrides = {
|
|
55797
56700
|
upstream_status: upstreamRes.status,
|
|
55798
56701
|
content_type_res: contentTypeRes,
|
|
55799
56702
|
response_headers: finalResponseHeaders,
|
|
55800
56703
|
response_bytes: responseBytes,
|
|
55801
56704
|
provider_request_id: providerRequestId,
|
|
56705
|
+
...tokenUsage && { token_usage: tokenUsage },
|
|
55802
56706
|
...pluginLogOverrides
|
|
55803
56707
|
};
|
|
55804
56708
|
if (requestBody !== undefined) {
|
|
@@ -56081,7 +56985,7 @@ function createAdminApiRoutes(store, pluginManager, registerCleanup) {
|
|
|
56081
56985
|
const CRYPTO_SESSION_TTL_MS = 2 * 60 * 1000;
|
|
56082
56986
|
const CRYPTO_SESSION_MAX = 512;
|
|
56083
56987
|
const schemaPath = getBundledSchemaPath();
|
|
56084
|
-
const schemaJson = JSON.parse(
|
|
56988
|
+
const schemaJson = JSON.parse(readFileSync5(schemaPath, "utf-8"));
|
|
56085
56989
|
const pruneExpiredCryptoSessions = (now2 = Date.now()) => {
|
|
56086
56990
|
for (const [id, record2] of Array.from(cryptoSessions.entries())) {
|
|
56087
56991
|
if (now2 - record2.createdAt > CRYPTO_SESSION_TTL_MS) {
|
|
@@ -56686,7 +57590,7 @@ async function createApp(store, options) {
|
|
|
56686
57590
|
}
|
|
56687
57591
|
const stopLogStorageTask = startLogStorageBackgroundTask(config2.log);
|
|
56688
57592
|
options?.registerCleanup?.(stopLogStorageTask);
|
|
56689
|
-
const configDir = dirname2(
|
|
57593
|
+
const configDir = dirname2(resolve7(store.getPath()));
|
|
56690
57594
|
const pluginManager = new PluginManager(configDir);
|
|
56691
57595
|
const reloadResult = await pluginManager.reloadAll(config2.providers);
|
|
56692
57596
|
if (!reloadResult.ok) {
|