@kaitranntt/ccs 7.77.1-dev.3 → 7.77.1-dev.5
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/ccs.js +1 -1
- package/dist/ccs.js.map +1 -1
- package/dist/cliproxy/services/oauth-usage-log-transformer.d.ts +4 -0
- package/dist/cliproxy/services/oauth-usage-log-transformer.d.ts.map +1 -0
- package/dist/cliproxy/services/oauth-usage-log-transformer.js +162 -0
- package/dist/cliproxy/services/oauth-usage-log-transformer.js.map +1 -0
- package/dist/cliproxy/services/stats-fetcher.d.ts +4 -0
- package/dist/cliproxy/services/stats-fetcher.d.ts.map +1 -1
- package/dist/cliproxy/services/stats-fetcher.js +133 -25
- package/dist/cliproxy/services/stats-fetcher.js.map +1 -1
- package/dist/cliproxy/services/stats-transformer.d.ts.map +1 -1
- package/dist/cliproxy/services/stats-transformer.js +85 -13
- package/dist/cliproxy/services/stats-transformer.js.map +1 -1
- package/dist/cliproxy/services/usage-compatibility-transformer.d.ts +12 -0
- package/dist/cliproxy/services/usage-compatibility-transformer.d.ts.map +1 -0
- package/dist/cliproxy/services/usage-compatibility-transformer.js +458 -0
- package/dist/cliproxy/services/usage-compatibility-transformer.js.map +1 -0
- package/dist/delegation/delegation-handler.d.ts.map +1 -1
- package/dist/delegation/delegation-handler.js +107 -33
- package/dist/delegation/delegation-handler.js.map +1 -1
- package/package.json +1 -1
|
@@ -11,6 +11,38 @@ function normalizeProvider(provider) {
|
|
|
11
11
|
}
|
|
12
12
|
return (0, provider_capabilities_1.mapExternalProviderName)(normalized) ?? normalized;
|
|
13
13
|
}
|
|
14
|
+
function extractAuthFilenameFromSource(source) {
|
|
15
|
+
const authFileMatch = source.match(/(?:^|\s)auth_file=("[^"]+"|'[^']+'|[^\s]+)/i);
|
|
16
|
+
const rawValue = authFileMatch?.[1] ?? source;
|
|
17
|
+
const value = rawValue.trim().replace(/^['"]|['"]$/g, '');
|
|
18
|
+
const filenameCandidate = value.split('|').pop() ?? value;
|
|
19
|
+
return filenameCandidate.split(/[\\/]/).pop() ?? filenameCandidate.trim();
|
|
20
|
+
}
|
|
21
|
+
function stripKnownAuthPlanSuffix(value) {
|
|
22
|
+
return value.replace(/-(?:free|plus|pro|team|business|enterprise)$/i, '');
|
|
23
|
+
}
|
|
24
|
+
function normalizeAuthFilenameSource(provider, source) {
|
|
25
|
+
const filename = extractAuthFilenameFromSource(source);
|
|
26
|
+
const normalizedProvider = normalizeProvider(provider);
|
|
27
|
+
const hadJsonExtension = /\.json$/i.test(filename);
|
|
28
|
+
let candidate = filename.replace(/\.json$/i, '');
|
|
29
|
+
const providerPrefix = `${normalizedProvider}-`;
|
|
30
|
+
if (candidate.toLowerCase().startsWith(providerPrefix)) {
|
|
31
|
+
candidate = candidate.slice(providerPrefix.length);
|
|
32
|
+
}
|
|
33
|
+
candidate = candidate.replace(/^[a-f0-9]{8}[-_]/i, '');
|
|
34
|
+
if (hadJsonExtension) {
|
|
35
|
+
candidate = stripKnownAuthPlanSuffix(candidate);
|
|
36
|
+
}
|
|
37
|
+
const parts = candidate.split('@');
|
|
38
|
+
if (parts.length < 2) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const localPart = parts[0]?.trim();
|
|
42
|
+
const domainPart = parts.slice(1).join('@').trim();
|
|
43
|
+
const email = `${localPart}@${domainPart}`;
|
|
44
|
+
return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email) ? email.toLowerCase() : null;
|
|
45
|
+
}
|
|
14
46
|
function buildAuthIndexLookup(authFiles) {
|
|
15
47
|
const lookup = new Map();
|
|
16
48
|
const duplicateEmailCounts = new Map();
|
|
@@ -61,10 +93,30 @@ function resolveSourceForDetail(resolvedProvider, detail, authIndexLookup) {
|
|
|
61
93
|
}
|
|
62
94
|
const source = detail.source?.trim();
|
|
63
95
|
if (source) {
|
|
64
|
-
return source;
|
|
96
|
+
return normalizeAuthFilenameSource(resolvedProvider, source) ?? source;
|
|
65
97
|
}
|
|
66
98
|
return resolvedAuthFile?.source ?? 'unknown';
|
|
67
99
|
}
|
|
100
|
+
function resolveCountWithDetails(aggregateCount, detailCount) {
|
|
101
|
+
if (aggregateCount === undefined) {
|
|
102
|
+
return detailCount;
|
|
103
|
+
}
|
|
104
|
+
return aggregateCount < detailCount ? detailCount : aggregateCount;
|
|
105
|
+
}
|
|
106
|
+
function shouldReplaceLastUsedAt(current, next) {
|
|
107
|
+
if (!next) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
const nextTime = Date.parse(next);
|
|
111
|
+
if (!Number.isFinite(nextTime)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
if (!current) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
const currentTime = Date.parse(current);
|
|
118
|
+
return !Number.isFinite(currentTime) || nextTime > currentTime;
|
|
119
|
+
}
|
|
68
120
|
function buildCliproxyStatsFromUsageResponse(data, options = {}) {
|
|
69
121
|
const usage = data.usage;
|
|
70
122
|
const requestsByModel = {};
|
|
@@ -78,7 +130,7 @@ function buildCliproxyStatsFromUsageResponse(data, options = {}) {
|
|
|
78
130
|
let sawAnyDetail = false;
|
|
79
131
|
if (usage?.apis) {
|
|
80
132
|
for (const [provider, providerData] of Object.entries(usage.apis)) {
|
|
81
|
-
let
|
|
133
|
+
let providerDetailCount = 0;
|
|
82
134
|
if (!providerData.models) {
|
|
83
135
|
const normalizedProvider = normalizeProvider(provider);
|
|
84
136
|
requestsByProvider[normalizedProvider] =
|
|
@@ -86,13 +138,15 @@ function buildCliproxyStatsFromUsageResponse(data, options = {}) {
|
|
|
86
138
|
continue;
|
|
87
139
|
}
|
|
88
140
|
for (const [model, modelData] of Object.entries(providerData.models)) {
|
|
89
|
-
|
|
141
|
+
let modelDetailCount = 0;
|
|
90
142
|
if (!modelData.details) {
|
|
143
|
+
requestsByModel[model] = (requestsByModel[model] ?? 0) + (modelData.total_requests ?? 0);
|
|
91
144
|
continue;
|
|
92
145
|
}
|
|
93
146
|
for (const detail of modelData.details) {
|
|
94
147
|
sawAnyDetail = true;
|
|
95
|
-
|
|
148
|
+
providerDetailCount++;
|
|
149
|
+
modelDetailCount++;
|
|
96
150
|
const resolvedProvider = resolveProviderForDetail(provider, detail, authIndexLookup);
|
|
97
151
|
const source = resolveSourceForDetail(resolvedProvider, detail, authIndexLookup);
|
|
98
152
|
const accountKey = (0, account_stats_key_1.buildQualifiedAccountStatsKey)(resolvedProvider, source);
|
|
@@ -117,24 +171,42 @@ function buildCliproxyStatsFromUsageResponse(data, options = {}) {
|
|
|
117
171
|
}
|
|
118
172
|
const tokens = detail.tokens?.total_tokens ?? 0;
|
|
119
173
|
accountStats[accountKey].totalTokens += tokens;
|
|
120
|
-
accountStats[accountKey].lastUsedAt
|
|
174
|
+
if (shouldReplaceLastUsedAt(accountStats[accountKey].lastUsedAt, detail.timestamp)) {
|
|
175
|
+
accountStats[accountKey].lastUsedAt = detail.timestamp;
|
|
176
|
+
}
|
|
121
177
|
totalInputTokens += detail.tokens?.input_tokens ?? 0;
|
|
122
178
|
totalOutputTokens += detail.tokens?.output_tokens ?? 0;
|
|
123
179
|
}
|
|
180
|
+
requestsByModel[model] =
|
|
181
|
+
(requestsByModel[model] ?? 0) +
|
|
182
|
+
resolveCountWithDetails(modelData.total_requests, modelDetailCount);
|
|
124
183
|
}
|
|
125
|
-
|
|
184
|
+
const providerTotal = providerData.total_requests ?? 0;
|
|
185
|
+
if (providerDetailCount === 0) {
|
|
126
186
|
const normalizedProvider = normalizeProvider(provider);
|
|
127
187
|
requestsByProvider[normalizedProvider] =
|
|
128
|
-
(requestsByProvider[normalizedProvider] ?? 0) +
|
|
188
|
+
(requestsByProvider[normalizedProvider] ?? 0) + providerTotal;
|
|
189
|
+
}
|
|
190
|
+
else if (providerTotal > providerDetailCount) {
|
|
191
|
+
const normalizedProvider = normalizeProvider(provider);
|
|
192
|
+
requestsByProvider[normalizedProvider] =
|
|
193
|
+
(requestsByProvider[normalizedProvider] ?? 0) + (providerTotal - providerDetailCount);
|
|
129
194
|
}
|
|
130
195
|
}
|
|
131
196
|
}
|
|
197
|
+
const aggregateFailureCount = usage?.failure_count ?? data.failed_requests;
|
|
198
|
+
const successCount = sawAnyDetail
|
|
199
|
+
? resolveCountWithDetails(usage?.success_count, totalSuccessCount)
|
|
200
|
+
: (usage?.success_count ?? 0);
|
|
201
|
+
const failureCount = sawAnyDetail
|
|
202
|
+
? resolveCountWithDetails(aggregateFailureCount, totalFailureCount)
|
|
203
|
+
: (aggregateFailureCount ?? 0);
|
|
204
|
+
const providerTotalRequests = Object.values(requestsByProvider).reduce((total, count) => total + count, 0);
|
|
205
|
+
const totalRequests = Math.max(usage?.total_requests ?? 0, successCount + failureCount, providerTotalRequests);
|
|
132
206
|
return {
|
|
133
|
-
totalRequests
|
|
134
|
-
successCount
|
|
135
|
-
failureCount
|
|
136
|
-
? totalFailureCount
|
|
137
|
-
: (usage?.failure_count ?? data.failed_requests ?? 0),
|
|
207
|
+
totalRequests,
|
|
208
|
+
successCount,
|
|
209
|
+
failureCount,
|
|
138
210
|
tokens: {
|
|
139
211
|
input: totalInputTokens,
|
|
140
212
|
output: totalOutputTokens,
|
|
@@ -143,7 +215,7 @@ function buildCliproxyStatsFromUsageResponse(data, options = {}) {
|
|
|
143
215
|
requestsByModel,
|
|
144
216
|
requestsByProvider,
|
|
145
217
|
accountStats,
|
|
146
|
-
quotaExceededCount:
|
|
218
|
+
quotaExceededCount: failureCount,
|
|
147
219
|
retryCount: 0,
|
|
148
220
|
collectedAt: new Date().toISOString(),
|
|
149
221
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stats-transformer.js","sourceRoot":"","sources":["../../../src/cliproxy/services/stats-transformer.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"stats-transformer.js","sourceRoot":"","sources":["../../../src/cliproxy/services/stats-transformer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CliproxyUsageApiResponse } from './stats-fetcher';
|
|
2
|
+
interface MergeMissingDetailsOptions {
|
|
3
|
+
appendExtraDetails?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare function buildUsageResponseFromQueueRecords(records: unknown[]): CliproxyUsageApiResponse;
|
|
6
|
+
export declare function mergeUsageResponses(base: CliproxyUsageApiResponse, incoming: CliproxyUsageApiResponse): CliproxyUsageApiResponse;
|
|
7
|
+
export declare function mergeUsageResponseWithMissingDetails(base: CliproxyUsageApiResponse, incoming: CliproxyUsageApiResponse | null | undefined, options?: MergeMissingDetailsOptions): CliproxyUsageApiResponse;
|
|
8
|
+
export declare function buildUsageResponseFromApiKeyUsage(rawResponse: unknown): CliproxyUsageApiResponse;
|
|
9
|
+
export declare function hasUsageDetails(response: CliproxyUsageApiResponse): boolean;
|
|
10
|
+
export declare function hasUsageTotals(response: CliproxyUsageApiResponse): boolean;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=usage-compatibility-transformer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-compatibility-transformer.d.ts","sourceRoot":"","sources":["../../../src/cliproxy/services/usage-compatibility-transformer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAyB,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAqBvF,UAAU,0BAA0B;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAyJD,wBAAgB,kCAAkC,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,wBAAwB,CA6B/F;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,wBAAwB,EAC9B,QAAQ,EAAE,wBAAwB,GACjC,wBAAwB,CAc1B;AAkTD,wBAAgB,oCAAoC,CAClD,IAAI,EAAE,wBAAwB,EAC9B,QAAQ,EAAE,wBAAwB,GAAG,IAAI,GAAG,SAAS,EACrD,OAAO,GAAE,0BAA+B,GACvC,wBAAwB,CA2C1B;AAED,wBAAgB,iCAAiC,CAAC,WAAW,EAAE,OAAO,GAAG,wBAAwB,CA4ChG;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,wBAAwB,GAAG,OAAO,CAE3E;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,wBAAwB,GAAG,OAAO,CAE1E"}
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hasUsageTotals = exports.hasUsageDetails = exports.buildUsageResponseFromApiKeyUsage = exports.mergeUsageResponseWithMissingDetails = exports.mergeUsageResponses = exports.buildUsageResponseFromQueueRecords = void 0;
|
|
4
|
+
function asRecord(value) {
|
|
5
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
6
|
+
? value
|
|
7
|
+
: null;
|
|
8
|
+
}
|
|
9
|
+
function asString(value, fallback) {
|
|
10
|
+
return typeof value === 'string' && value.trim() ? value.trim() : fallback;
|
|
11
|
+
}
|
|
12
|
+
function asNumber(value) {
|
|
13
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
if (typeof value === 'string' && value.trim()) {
|
|
17
|
+
const parsed = Number(value);
|
|
18
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
19
|
+
}
|
|
20
|
+
return 0;
|
|
21
|
+
}
|
|
22
|
+
function asBoolean(value) {
|
|
23
|
+
return value === true;
|
|
24
|
+
}
|
|
25
|
+
function normalizeTokens(rawTokens) {
|
|
26
|
+
const tokens = asRecord(rawTokens) ?? {};
|
|
27
|
+
const input = asNumber(tokens.input_tokens);
|
|
28
|
+
const output = asNumber(tokens.output_tokens);
|
|
29
|
+
const reasoning = asNumber(tokens.reasoning_tokens);
|
|
30
|
+
const cached = asNumber(tokens.cached_tokens);
|
|
31
|
+
const explicitTotal = asNumber(tokens.total_tokens);
|
|
32
|
+
const total = explicitTotal || input + output + reasoning + cached;
|
|
33
|
+
return {
|
|
34
|
+
input_tokens: input,
|
|
35
|
+
output_tokens: output,
|
|
36
|
+
reasoning_tokens: reasoning,
|
|
37
|
+
cached_tokens: cached,
|
|
38
|
+
total_tokens: total,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function normalizeQueueRecord(record) {
|
|
42
|
+
const raw = asRecord(record);
|
|
43
|
+
if (!raw) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const provider = asString(raw.provider, 'unknown');
|
|
47
|
+
const model = asString(raw.model, asString(raw.alias, 'unknown'));
|
|
48
|
+
const source = asString(raw.source, 'unknown');
|
|
49
|
+
const authIndex = typeof raw.auth_index === 'string' || typeof raw.auth_index === 'number'
|
|
50
|
+
? raw.auth_index
|
|
51
|
+
: source;
|
|
52
|
+
return {
|
|
53
|
+
timestamp: asString(raw.timestamp, new Date().toISOString()),
|
|
54
|
+
provider,
|
|
55
|
+
model,
|
|
56
|
+
alias: asString(raw.alias, model),
|
|
57
|
+
source,
|
|
58
|
+
auth_index: authIndex,
|
|
59
|
+
request_id: asString(raw.request_id, ''),
|
|
60
|
+
tokens: normalizeTokens(raw.tokens),
|
|
61
|
+
failed: asBoolean(raw.failed),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function ensureProviderBucket(response, provider) {
|
|
65
|
+
const usage = (response.usage ?? (response.usage = { apis: {} }));
|
|
66
|
+
const apis = (usage.apis ?? (usage.apis = {}));
|
|
67
|
+
return (apis[provider] ?? (apis[provider] = { total_requests: 0, total_tokens: 0, models: {} }));
|
|
68
|
+
}
|
|
69
|
+
function ensureModelBucket(providerBucket, model) {
|
|
70
|
+
const models = (providerBucket.models ?? (providerBucket.models = {}));
|
|
71
|
+
return (models[model] ?? (models[model] = { total_requests: 0, total_tokens: 0, details: [] }));
|
|
72
|
+
}
|
|
73
|
+
function addDetail(response, provider, model, detail) {
|
|
74
|
+
const usage = (response.usage ?? (response.usage = { apis: {} }));
|
|
75
|
+
const providerBucket = ensureProviderBucket(response, provider);
|
|
76
|
+
const modelBucket = ensureModelBucket(providerBucket, model);
|
|
77
|
+
const totalTokens = detail.tokens?.total_tokens ?? 0;
|
|
78
|
+
usage.total_requests = (usage.total_requests ?? 0) + 1;
|
|
79
|
+
usage.total_tokens = (usage.total_tokens ?? 0) + totalTokens;
|
|
80
|
+
if (detail.failed) {
|
|
81
|
+
usage.failure_count = (usage.failure_count ?? 0) + 1;
|
|
82
|
+
response.failed_requests = (response.failed_requests ?? 0) + 1;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
usage.success_count = (usage.success_count ?? 0) + 1;
|
|
86
|
+
}
|
|
87
|
+
providerBucket.total_requests = (providerBucket.total_requests ?? 0) + 1;
|
|
88
|
+
providerBucket.total_tokens = (providerBucket.total_tokens ?? 0) + totalTokens;
|
|
89
|
+
modelBucket.total_requests = (modelBucket.total_requests ?? 0) + 1;
|
|
90
|
+
modelBucket.total_tokens = (modelBucket.total_tokens ?? 0) + totalTokens;
|
|
91
|
+
(modelBucket.details ?? (modelBucket.details = [])).push(detail);
|
|
92
|
+
}
|
|
93
|
+
function createDetailSignature(provider, model, detail) {
|
|
94
|
+
return [
|
|
95
|
+
provider,
|
|
96
|
+
model,
|
|
97
|
+
detail.request_id?.trim() ?? '',
|
|
98
|
+
detail.timestamp,
|
|
99
|
+
detail.source,
|
|
100
|
+
String(detail.auth_index),
|
|
101
|
+
detail.tokens?.input_tokens ?? 0,
|
|
102
|
+
detail.tokens?.output_tokens ?? 0,
|
|
103
|
+
detail.tokens?.reasoning_tokens ?? 0,
|
|
104
|
+
detail.tokens?.cached_tokens ?? 0,
|
|
105
|
+
detail.tokens?.total_tokens ?? 0,
|
|
106
|
+
detail.failed ? '1' : '0',
|
|
107
|
+
].join('|');
|
|
108
|
+
}
|
|
109
|
+
function collectResponseDetails(response) {
|
|
110
|
+
const entries = [];
|
|
111
|
+
for (const [provider, providerData] of Object.entries(response.usage?.apis ?? {})) {
|
|
112
|
+
for (const [model, modelData] of Object.entries(providerData.models ?? {})) {
|
|
113
|
+
for (const detail of modelData.details ?? []) {
|
|
114
|
+
entries.push({ provider, model, detail });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return entries;
|
|
119
|
+
}
|
|
120
|
+
function buildUsageResponseFromQueueRecords(records) {
|
|
121
|
+
const response = {
|
|
122
|
+
failed_requests: 0,
|
|
123
|
+
usage: {
|
|
124
|
+
total_requests: 0,
|
|
125
|
+
success_count: 0,
|
|
126
|
+
failure_count: 0,
|
|
127
|
+
total_tokens: 0,
|
|
128
|
+
apis: {},
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
for (const rawRecord of records) {
|
|
132
|
+
const record = normalizeQueueRecord(rawRecord);
|
|
133
|
+
if (!record) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
addDetail(response, record.provider ?? 'unknown', record.model ?? 'unknown', {
|
|
137
|
+
timestamp: record.timestamp ?? new Date().toISOString(),
|
|
138
|
+
source: record.source ?? 'unknown',
|
|
139
|
+
auth_index: record.auth_index ?? record.source ?? 'unknown',
|
|
140
|
+
request_id: record.request_id || undefined,
|
|
141
|
+
tokens: normalizeTokens(record.tokens),
|
|
142
|
+
failed: record.failed === true,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return response;
|
|
146
|
+
}
|
|
147
|
+
exports.buildUsageResponseFromQueueRecords = buildUsageResponseFromQueueRecords;
|
|
148
|
+
function mergeUsageResponses(base, incoming) {
|
|
149
|
+
const merged = buildUsageResponseFromQueueRecords([]);
|
|
150
|
+
const seen = new Set();
|
|
151
|
+
for (const entry of [...collectResponseDetails(base), ...collectResponseDetails(incoming)]) {
|
|
152
|
+
const signature = createDetailSignature(entry.provider, entry.model, entry.detail);
|
|
153
|
+
if (seen.has(signature)) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
seen.add(signature);
|
|
157
|
+
addDetail(merged, entry.provider, entry.model, entry.detail);
|
|
158
|
+
}
|
|
159
|
+
return merged;
|
|
160
|
+
}
|
|
161
|
+
exports.mergeUsageResponses = mergeUsageResponses;
|
|
162
|
+
function cloneUsageResponse(response) {
|
|
163
|
+
return {
|
|
164
|
+
failed_requests: response.failed_requests ?? 0,
|
|
165
|
+
usage: {
|
|
166
|
+
total_requests: response.usage?.total_requests ?? 0,
|
|
167
|
+
success_count: response.usage?.success_count ?? 0,
|
|
168
|
+
failure_count: response.usage?.failure_count ?? 0,
|
|
169
|
+
total_tokens: response.usage?.total_tokens ?? 0,
|
|
170
|
+
apis: Object.fromEntries(Object.entries(response.usage?.apis ?? {}).map(([provider, providerData]) => [
|
|
171
|
+
provider,
|
|
172
|
+
{
|
|
173
|
+
total_requests: providerData.total_requests ?? 0,
|
|
174
|
+
total_tokens: providerData.total_tokens ?? 0,
|
|
175
|
+
models: Object.fromEntries(Object.entries(providerData.models ?? {}).map(([model, modelData]) => [
|
|
176
|
+
model,
|
|
177
|
+
{
|
|
178
|
+
total_requests: modelData.total_requests ?? 0,
|
|
179
|
+
total_tokens: modelData.total_tokens ?? 0,
|
|
180
|
+
details: (modelData.details ?? []).map((detail) => ({
|
|
181
|
+
...detail,
|
|
182
|
+
tokens: { ...detail.tokens },
|
|
183
|
+
})),
|
|
184
|
+
},
|
|
185
|
+
])),
|
|
186
|
+
},
|
|
187
|
+
])),
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function cloneDetail(detail) {
|
|
192
|
+
return {
|
|
193
|
+
...detail,
|
|
194
|
+
tokens: { ...detail.tokens },
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function createMissingDetailMergeKey(provider, model, detail) {
|
|
198
|
+
return [
|
|
199
|
+
provider,
|
|
200
|
+
model,
|
|
201
|
+
detail.request_id?.trim() ?? '',
|
|
202
|
+
detail.timestamp,
|
|
203
|
+
detail.source?.trim() ?? '',
|
|
204
|
+
String(detail.auth_index ?? '').trim(),
|
|
205
|
+
detail.tokens?.input_tokens ?? 0,
|
|
206
|
+
detail.tokens?.output_tokens ?? 0,
|
|
207
|
+
detail.tokens?.reasoning_tokens ?? 0,
|
|
208
|
+
detail.tokens?.cached_tokens ?? 0,
|
|
209
|
+
detail.tokens?.total_tokens ?? 0,
|
|
210
|
+
detail.failed ? '1' : '0',
|
|
211
|
+
].join('|');
|
|
212
|
+
}
|
|
213
|
+
function extractDuplicateIdentityValue(value) {
|
|
214
|
+
const authFileMatch = value.match(/(?:^|\s)auth_file=("[^"]+"|'[^']+'|[^\s]+)/i);
|
|
215
|
+
const rawValue = authFileMatch?.[1] ?? value;
|
|
216
|
+
const unquotedValue = rawValue.trim().replace(/^['"]|['"]$/g, '');
|
|
217
|
+
const pipeCandidate = unquotedValue.split('|').pop() ?? unquotedValue;
|
|
218
|
+
return pipeCandidate.split(/[\\/]/).pop() ?? pipeCandidate.trim();
|
|
219
|
+
}
|
|
220
|
+
function stripKnownAuthPlanSuffix(value) {
|
|
221
|
+
return value.replace(/-(?:free|plus|pro|team|business|enterprise)$/i, '');
|
|
222
|
+
}
|
|
223
|
+
function normalizeDuplicateIdentity(provider, value) {
|
|
224
|
+
const rawValue = String(value ?? '').trim();
|
|
225
|
+
if (!rawValue) {
|
|
226
|
+
return '';
|
|
227
|
+
}
|
|
228
|
+
const normalizedProvider = provider.trim().toLowerCase();
|
|
229
|
+
const identityValue = extractDuplicateIdentityValue(rawValue);
|
|
230
|
+
const hadJsonExtension = /\.json$/i.test(identityValue);
|
|
231
|
+
let candidate = identityValue.replace(/\.json$/i, '');
|
|
232
|
+
const providerPrefix = `${normalizedProvider}-`;
|
|
233
|
+
if (candidate.toLowerCase().startsWith(providerPrefix)) {
|
|
234
|
+
candidate = candidate.slice(providerPrefix.length);
|
|
235
|
+
}
|
|
236
|
+
candidate = candidate.replace(/^[a-f0-9]{8}[-_]/i, '').trim();
|
|
237
|
+
if (hadJsonExtension) {
|
|
238
|
+
candidate = stripKnownAuthPlanSuffix(candidate);
|
|
239
|
+
}
|
|
240
|
+
return candidate ? candidate.toLowerCase() : rawValue.toLowerCase();
|
|
241
|
+
}
|
|
242
|
+
function resolveCompleteDetailDuplicateIdentity(provider, detail) {
|
|
243
|
+
return (normalizeDuplicateIdentity(provider, detail.source) ||
|
|
244
|
+
normalizeDuplicateIdentity(provider, detail.auth_index) ||
|
|
245
|
+
'unknown');
|
|
246
|
+
}
|
|
247
|
+
function createLikelyLogDuplicateKey(provider, model, detail) {
|
|
248
|
+
return [
|
|
249
|
+
provider,
|
|
250
|
+
model,
|
|
251
|
+
resolveCompleteDetailDuplicateIdentity(provider, detail),
|
|
252
|
+
detail.failed ? '1' : '0',
|
|
253
|
+
].join('|');
|
|
254
|
+
}
|
|
255
|
+
function createRequestIdDuplicateKey(provider, model, detail) {
|
|
256
|
+
const requestId = detail.request_id?.trim();
|
|
257
|
+
return requestId ? [provider, model, requestId, detail.failed ? '1' : '0'].join('|') : '';
|
|
258
|
+
}
|
|
259
|
+
function parseDetailTimestamp(detail) {
|
|
260
|
+
const timestampMs = Date.parse(detail.timestamp);
|
|
261
|
+
return Number.isFinite(timestampMs) ? timestampMs : null;
|
|
262
|
+
}
|
|
263
|
+
const TOKENLESS_LOG_DUPLICATE_WINDOW_MS = 5000;
|
|
264
|
+
function detailHasTokenUsage(detail) {
|
|
265
|
+
return ((detail.tokens?.input_tokens ?? 0) > 0 ||
|
|
266
|
+
(detail.tokens?.output_tokens ?? 0) > 0 ||
|
|
267
|
+
(detail.tokens?.reasoning_tokens ?? 0) > 0 ||
|
|
268
|
+
(detail.tokens?.cached_tokens ?? 0) > 0 ||
|
|
269
|
+
(detail.tokens?.total_tokens ?? 0) > 0);
|
|
270
|
+
}
|
|
271
|
+
function collectDetailMergeKeyCounts(response) {
|
|
272
|
+
const counts = new Map();
|
|
273
|
+
for (const entry of collectResponseDetails(response)) {
|
|
274
|
+
const key = createMissingDetailMergeKey(entry.provider, entry.model, entry.detail);
|
|
275
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
276
|
+
}
|
|
277
|
+
return counts;
|
|
278
|
+
}
|
|
279
|
+
function collectLikelyLogDuplicateCandidates(response) {
|
|
280
|
+
const candidates = {
|
|
281
|
+
byRequestId: new Map(),
|
|
282
|
+
byIdentity: new Map(),
|
|
283
|
+
};
|
|
284
|
+
for (const [provider, providerData] of Object.entries(response.usage?.apis ?? {})) {
|
|
285
|
+
for (const [model, modelData] of Object.entries(providerData.models ?? {})) {
|
|
286
|
+
const details = modelData.details ?? [];
|
|
287
|
+
const canUseIdentityWindow = (modelData.total_requests ?? 0) <= details.length;
|
|
288
|
+
for (const detail of details) {
|
|
289
|
+
const requestIdKey = createRequestIdDuplicateKey(provider, model, detail);
|
|
290
|
+
if (requestIdKey) {
|
|
291
|
+
candidates.byRequestId.set(requestIdKey, (candidates.byRequestId.get(requestIdKey) ?? 0) + 1);
|
|
292
|
+
}
|
|
293
|
+
if (!canUseIdentityWindow) {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const timestampMs = parseDetailTimestamp(detail);
|
|
297
|
+
if (timestampMs === null) {
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
const key = createLikelyLogDuplicateKey(provider, model, detail);
|
|
301
|
+
const timestamps = candidates.byIdentity.get(key) ?? [];
|
|
302
|
+
timestamps.push(timestampMs);
|
|
303
|
+
candidates.byIdentity.set(key, timestamps);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return candidates;
|
|
308
|
+
}
|
|
309
|
+
function consumeDetailKey(counts, key) {
|
|
310
|
+
const count = counts.get(key) ?? 0;
|
|
311
|
+
if (count <= 0) {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
if (count === 1) {
|
|
315
|
+
counts.delete(key);
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
counts.set(key, count - 1);
|
|
319
|
+
}
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
function consumeCount(counts, key) {
|
|
323
|
+
const count = counts.get(key) ?? 0;
|
|
324
|
+
if (count <= 0) {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
if (count === 1) {
|
|
328
|
+
counts.delete(key);
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
counts.set(key, count - 1);
|
|
332
|
+
}
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
function consumeLikelyLogDuplicateCandidate(candidates, provider, model, detail) {
|
|
336
|
+
if (detailHasTokenUsage(detail)) {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
const requestIdKey = createRequestIdDuplicateKey(provider, model, detail);
|
|
340
|
+
if (requestIdKey && consumeCount(candidates.byRequestId, requestIdKey)) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
const timestampMs = parseDetailTimestamp(detail);
|
|
344
|
+
if (timestampMs === null) {
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
const key = createLikelyLogDuplicateKey(provider, model, detail);
|
|
348
|
+
const timestamps = candidates.byIdentity.get(key) ?? [];
|
|
349
|
+
const index = timestamps.findIndex((candidateTimestampMs) => Math.abs(candidateTimestampMs - timestampMs) <= TOKENLESS_LOG_DUPLICATE_WINDOW_MS);
|
|
350
|
+
if (index === -1) {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
timestamps.splice(index, 1);
|
|
354
|
+
if (timestamps.length === 0) {
|
|
355
|
+
candidates.byIdentity.delete(key);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
candidates.byIdentity.set(key, timestamps);
|
|
359
|
+
}
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
362
|
+
function countProviderDetails(providerBucket) {
|
|
363
|
+
return Object.values(providerBucket.models ?? {}).reduce((total, modelData) => total + (modelData.details ?? []).length, 0);
|
|
364
|
+
}
|
|
365
|
+
function appendDetailToExistingProvider(merged, provider, model, detail, options) {
|
|
366
|
+
const providerBucket = ensureProviderBucket(merged, provider);
|
|
367
|
+
const shouldFillAggregateOnly = (providerBucket.total_requests ?? 0) > countProviderDetails(providerBucket);
|
|
368
|
+
if (!shouldFillAggregateOnly) {
|
|
369
|
+
if (!options.appendExtraDetails) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
addDetail(merged, provider, model, cloneDetail(detail));
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
const modelBucket = ensureModelBucket(providerBucket, model);
|
|
376
|
+
const shouldFillModelAggregateOnly = (modelBucket.total_requests ?? 0) > (modelBucket.details ?? []).length;
|
|
377
|
+
if (!shouldFillModelAggregateOnly) {
|
|
378
|
+
modelBucket.total_requests = (modelBucket.total_requests ?? 0) + 1;
|
|
379
|
+
}
|
|
380
|
+
(modelBucket.details ?? (modelBucket.details = [])).push(cloneDetail(detail));
|
|
381
|
+
}
|
|
382
|
+
function mergeUsageResponseWithMissingDetails(base, incoming, options = {}) {
|
|
383
|
+
if (!incoming || !hasUsageDetails(incoming)) {
|
|
384
|
+
return base;
|
|
385
|
+
}
|
|
386
|
+
const normalizedOptions = {
|
|
387
|
+
appendExtraDetails: options.appendExtraDetails ?? true,
|
|
388
|
+
};
|
|
389
|
+
const merged = cloneUsageResponse(base);
|
|
390
|
+
const existingDetailCounts = collectDetailMergeKeyCounts(base);
|
|
391
|
+
const likelyLogDuplicateCandidates = collectLikelyLogDuplicateCandidates(base);
|
|
392
|
+
for (const entry of collectResponseDetails(incoming)) {
|
|
393
|
+
const mergeKey = createMissingDetailMergeKey(entry.provider, entry.model, entry.detail);
|
|
394
|
+
if (consumeDetailKey(existingDetailCounts, mergeKey)) {
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
if (consumeLikelyLogDuplicateCandidate(likelyLogDuplicateCandidates, entry.provider, entry.model, entry.detail)) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
if (base.usage?.apis?.[entry.provider]) {
|
|
401
|
+
appendDetailToExistingProvider(merged, entry.provider, entry.model, entry.detail, normalizedOptions);
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
addDetail(merged, entry.provider, entry.model, cloneDetail(entry.detail));
|
|
405
|
+
}
|
|
406
|
+
return merged;
|
|
407
|
+
}
|
|
408
|
+
exports.mergeUsageResponseWithMissingDetails = mergeUsageResponseWithMissingDetails;
|
|
409
|
+
function buildUsageResponseFromApiKeyUsage(rawResponse) {
|
|
410
|
+
const response = buildUsageResponseFromQueueRecords([]);
|
|
411
|
+
const usage = response.usage ?? {
|
|
412
|
+
total_requests: 0,
|
|
413
|
+
success_count: 0,
|
|
414
|
+
failure_count: 0,
|
|
415
|
+
total_tokens: 0,
|
|
416
|
+
apis: {},
|
|
417
|
+
};
|
|
418
|
+
response.usage = usage;
|
|
419
|
+
const byProvider = asRecord(rawResponse);
|
|
420
|
+
if (!byProvider) {
|
|
421
|
+
return response;
|
|
422
|
+
}
|
|
423
|
+
for (const [provider, sources] of Object.entries(byProvider)) {
|
|
424
|
+
const sourceRecords = asRecord(sources);
|
|
425
|
+
if (!sourceRecords) {
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
let providerRequests = 0;
|
|
429
|
+
for (const entry of Object.values(sourceRecords)) {
|
|
430
|
+
const usageEntry = asRecord(entry);
|
|
431
|
+
if (!usageEntry) {
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
const success = asNumber(usageEntry.success);
|
|
435
|
+
const failed = asNumber(usageEntry.failed);
|
|
436
|
+
providerRequests += success + failed;
|
|
437
|
+
usage.success_count = (usage.success_count ?? 0) + success;
|
|
438
|
+
usage.failure_count = (usage.failure_count ?? 0) + failed;
|
|
439
|
+
response.failed_requests = (response.failed_requests ?? 0) + failed;
|
|
440
|
+
}
|
|
441
|
+
if (providerRequests > 0) {
|
|
442
|
+
const providerBucket = ensureProviderBucket(response, provider);
|
|
443
|
+
providerBucket.total_requests = (providerBucket.total_requests ?? 0) + providerRequests;
|
|
444
|
+
usage.total_requests = (usage.total_requests ?? 0) + providerRequests;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return response;
|
|
448
|
+
}
|
|
449
|
+
exports.buildUsageResponseFromApiKeyUsage = buildUsageResponseFromApiKeyUsage;
|
|
450
|
+
function hasUsageDetails(response) {
|
|
451
|
+
return collectResponseDetails(response).length > 0;
|
|
452
|
+
}
|
|
453
|
+
exports.hasUsageDetails = hasUsageDetails;
|
|
454
|
+
function hasUsageTotals(response) {
|
|
455
|
+
return (response.usage?.total_requests ?? 0) > 0;
|
|
456
|
+
}
|
|
457
|
+
exports.hasUsageTotals = hasUsageTotals;
|
|
458
|
+
//# sourceMappingURL=usage-compatibility-transformer.js.map
|