@jsonstudio/rcc 0.89.683 → 0.89.912
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/README.md +44 -0
- package/dist/build-info.js +2 -2
- package/dist/cli.js +164 -116
- package/dist/cli.js.map +1 -1
- package/dist/client/anthropic/anthropic-protocol-client.js +42 -1
- package/dist/client/anthropic/anthropic-protocol-client.js.map +1 -1
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js +4 -1
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -1
- package/dist/commands/camoufox-backfill.d.ts +2 -0
- package/dist/commands/camoufox-backfill.js +33 -0
- package/dist/commands/camoufox-backfill.js.map +1 -0
- package/dist/commands/camoufox-fp.d.ts +2 -0
- package/dist/commands/camoufox-fp.js +86 -0
- package/dist/commands/camoufox-fp.js.map +1 -0
- package/dist/commands/oauth.d.ts +2 -0
- package/dist/commands/oauth.js +170 -0
- package/dist/commands/oauth.js.map +1 -0
- package/dist/commands/provider-update.js +439 -2
- package/dist/commands/provider-update.js.map +1 -1
- package/dist/commands/quota-status.d.ts +2 -0
- package/dist/commands/quota-status.js +80 -0
- package/dist/commands/quota-status.js.map +1 -0
- package/dist/commands/token-daemon.js +12 -1
- package/dist/commands/token-daemon.js.map +1 -1
- package/dist/config/provider-v2-loader.d.ts +16 -0
- package/dist/config/provider-v2-loader.js +84 -0
- package/dist/config/provider-v2-loader.js.map +1 -0
- package/dist/config/routecodex-config-loader.js +27 -4
- package/dist/config/routecodex-config-loader.js.map +1 -1
- package/dist/config/system-prompts/codex-cli.txt +1 -0
- package/dist/config/virtual-router-builder.d.ts +9 -0
- package/dist/config/virtual-router-builder.js +34 -0
- package/dist/config/virtual-router-builder.js.map +1 -0
- package/dist/config/virtual-router-types.d.ts +25 -0
- package/dist/config/virtual-router-types.js +30 -0
- package/dist/config/virtual-router-types.js.map +1 -0
- package/dist/manager/index.d.ts +10 -0
- package/dist/manager/index.js +27 -0
- package/dist/manager/index.js.map +1 -0
- package/dist/manager/modules/health/index.d.ts +22 -0
- package/dist/manager/modules/health/index.js +82 -0
- package/dist/manager/modules/health/index.js.map +1 -0
- package/dist/manager/modules/quota/index.d.ts +57 -0
- package/dist/manager/modules/quota/index.js +426 -0
- package/dist/manager/modules/quota/index.js.map +1 -0
- package/dist/manager/modules/routing/index.d.ts +17 -0
- package/dist/manager/modules/routing/index.js +61 -0
- package/dist/manager/modules/routing/index.js.map +1 -0
- package/dist/manager/modules/token/index.d.ts +10 -0
- package/dist/manager/modules/token/index.js +58 -0
- package/dist/manager/modules/token/index.js.map +1 -0
- package/dist/manager/storage/base-store.d.ts +6 -0
- package/dist/manager/storage/base-store.js +2 -0
- package/dist/manager/storage/base-store.js.map +1 -0
- package/dist/manager/storage/file-store.d.ts +25 -0
- package/dist/manager/storage/file-store.js +117 -0
- package/dist/manager/storage/file-store.js.map +1 -0
- package/dist/manager/types.d.ts +9 -0
- package/dist/manager/types.js +2 -0
- package/dist/manager/types.js.map +1 -0
- package/dist/message-center/index.d.ts +5 -0
- package/dist/message-center/index.js +6 -0
- package/dist/message-center/index.js.map +1 -0
- package/dist/message-center/message-center.d.ts +93 -0
- package/dist/message-center/message-center.js +189 -0
- package/dist/message-center/message-center.js.map +1 -0
- package/dist/providers/auth/antigravity-userinfo-helper.d.ts +2 -0
- package/dist/providers/auth/antigravity-userinfo-helper.js +102 -0
- package/dist/providers/auth/antigravity-userinfo-helper.js.map +1 -1
- package/dist/providers/auth/iflow-cookie-auth.d.ts +27 -0
- package/dist/providers/auth/iflow-cookie-auth.js +209 -0
- package/dist/providers/auth/iflow-cookie-auth.js.map +1 -0
- package/dist/providers/auth/oauth-lifecycle.js +29 -22
- package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
- package/dist/providers/auth/token-scanner/index.js +16 -1
- package/dist/providers/auth/token-scanner/index.js.map +1 -1
- package/dist/providers/core/config/camoufox-launcher.d.ts +16 -0
- package/dist/providers/core/config/camoufox-launcher.js +314 -0
- package/dist/providers/core/config/camoufox-launcher.js.map +1 -0
- package/dist/providers/core/config/oauth-flows.d.ts +9 -0
- package/dist/providers/core/config/oauth-flows.js +50 -19
- package/dist/providers/core/config/oauth-flows.js.map +1 -1
- package/dist/providers/core/config/provider-oauth-configs.d.ts +6 -0
- package/dist/providers/core/config/provider-oauth-configs.js +12 -0
- package/dist/providers/core/config/provider-oauth-configs.js.map +1 -1
- package/dist/providers/core/config/service-profiles.js +26 -3
- package/dist/providers/core/config/service-profiles.js.map +1 -1
- package/dist/providers/core/runtime/antigravity-quota-client.d.ts +10 -0
- package/dist/providers/core/runtime/antigravity-quota-client.js +88 -0
- package/dist/providers/core/runtime/antigravity-quota-client.js.map +1 -0
- package/dist/providers/core/runtime/base-provider.d.ts +2 -1
- package/dist/providers/core/runtime/base-provider.js +93 -34
- package/dist/providers/core/runtime/base-provider.js.map +1 -1
- package/dist/providers/core/runtime/gemini-cli-http-provider.js +42 -10
- package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
- package/dist/providers/core/runtime/http-request-executor.js +24 -0
- package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
- package/dist/providers/core/runtime/http-transport-provider.d.ts +0 -3
- package/dist/providers/core/runtime/http-transport-provider.js +32 -136
- package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
- package/dist/providers/core/runtime/provider-error-classifier.js +18 -10
- package/dist/providers/core/runtime/provider-error-classifier.js.map +1 -1
- package/dist/providers/core/runtime/rate-limit-manager.d.ts +6 -0
- package/dist/providers/core/runtime/rate-limit-manager.js +23 -0
- package/dist/providers/core/runtime/rate-limit-manager.js.map +1 -1
- package/dist/providers/core/runtime/responses-provider.js +17 -19
- package/dist/providers/core/runtime/responses-provider.js.map +1 -1
- package/dist/providers/core/strategies/oauth-auth-code-flow.d.ts +1 -0
- package/dist/providers/core/strategies/oauth-auth-code-flow.js +3 -2
- package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
- package/dist/providers/core/strategies/oauth-device-flow.d.ts +1 -0
- package/dist/providers/core/strategies/oauth-device-flow.js +3 -2
- package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
- package/dist/providers/core/strategies/oauth-hybrid-flow.d.ts +1 -0
- package/dist/providers/core/strategies/oauth-hybrid-flow.js +3 -2
- package/dist/providers/core/strategies/oauth-hybrid-flow.js.map +1 -1
- package/dist/providers/core/utils/http-client.js +43 -1
- package/dist/providers/core/utils/http-client.js.map +1 -1
- package/dist/providers/mock/mock-provider-runtime.js +4 -4
- package/dist/providers/mock/mock-provider-runtime.js.map +1 -1
- package/dist/providers/profile/provider-profile-loader.js +13 -1
- package/dist/providers/profile/provider-profile-loader.js.map +1 -1
- package/dist/providers/profile/provider-profile.d.ts +5 -0
- package/dist/scripts/camoufox/gen-fingerprint-env.py +171 -0
- package/dist/scripts/camoufox/launch-auth.mjs +617 -0
- package/dist/server/runtime/http-server/daemon-admin/credentials-handler.d.ts +3 -0
- package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js +138 -0
- package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js.map +1 -0
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.d.ts +3 -0
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.js +166 -0
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.js.map +1 -0
- package/dist/server/runtime/http-server/daemon-admin/quota-handler.d.ts +3 -0
- package/dist/server/runtime/http-server/daemon-admin/quota-handler.js +109 -0
- package/dist/server/runtime/http-server/daemon-admin/quota-handler.js.map +1 -0
- package/dist/server/runtime/http-server/daemon-admin/status-handler.d.ts +3 -0
- package/dist/server/runtime/http-server/daemon-admin/status-handler.js +43 -0
- package/dist/server/runtime/http-server/daemon-admin/status-handler.js.map +1 -0
- package/dist/server/runtime/http-server/daemon-admin-routes.d.ts +19 -0
- package/dist/server/runtime/http-server/daemon-admin-routes.js +27 -0
- package/dist/server/runtime/http-server/daemon-admin-routes.js.map +1 -0
- package/dist/server/runtime/http-server/executor-provider.d.ts +1 -0
- package/dist/server/runtime/http-server/executor-provider.js +26 -0
- package/dist/server/runtime/http-server/executor-provider.js.map +1 -1
- package/dist/server/runtime/http-server/executor-response.d.ts +16 -0
- package/dist/server/runtime/http-server/executor-response.js +164 -0
- package/dist/server/runtime/http-server/executor-response.js.map +1 -0
- package/dist/server/runtime/http-server/index.d.ts +6 -0
- package/dist/server/runtime/http-server/index.js +121 -53
- package/dist/server/runtime/http-server/index.js.map +1 -1
- package/dist/server/runtime/http-server/request-executor.d.ts +3 -0
- package/dist/server/runtime/http-server/request-executor.js +73 -21
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/server/runtime/http-server/routes.d.ts +5 -0
- package/dist/server/runtime/http-server/routes.js +45 -1
- package/dist/server/runtime/http-server/routes.js.map +1 -1
- package/dist/server/runtime/http-server/types.d.ts +1 -0
- package/dist/server/utils/client-connection-state.d.ts +8 -0
- package/dist/server/utils/client-connection-state.js +52 -0
- package/dist/server/utils/client-connection-state.js.map +1 -0
- package/dist/server/utils/request-id-manager.js +21 -3
- package/dist/server/utils/request-id-manager.js.map +1 -1
- package/dist/token-daemon/history-store.d.ts +2 -0
- package/dist/token-daemon/history-store.js +6 -2
- package/dist/token-daemon/history-store.js.map +1 -1
- package/dist/token-daemon/index.js +36 -5
- package/dist/token-daemon/index.js.map +1 -1
- package/dist/token-daemon/leader-lock.d.ts +11 -0
- package/dist/token-daemon/leader-lock.js +79 -0
- package/dist/token-daemon/leader-lock.js.map +1 -0
- package/dist/token-daemon/message-bus-integrator.d.ts +98 -0
- package/dist/token-daemon/message-bus-integrator.js +144 -0
- package/dist/token-daemon/message-bus-integrator.js.map +1 -0
- package/dist/token-daemon/provider-registry.d.ts +22 -0
- package/dist/token-daemon/provider-registry.js +201 -0
- package/dist/token-daemon/provider-registry.js.map +1 -0
- package/dist/token-daemon/token-daemon.d.ts +8 -0
- package/dist/token-daemon/token-daemon.js +196 -11
- package/dist/token-daemon/token-daemon.js.map +1 -1
- package/dist/token-portal/local-token-portal.d.ts +1 -0
- package/dist/token-portal/local-token-portal.js +18 -0
- package/dist/token-portal/local-token-portal.js.map +1 -1
- package/dist/token-portal/render.js +1 -0
- package/dist/token-portal/render.js.map +1 -1
- package/dist/tools/error-log.d.ts +31 -0
- package/dist/tools/error-log.js +117 -0
- package/dist/tools/error-log.js.map +1 -0
- package/dist/tools/stats-request-events.d.ts +2 -0
- package/dist/tools/stats-request-events.js +16 -0
- package/dist/tools/stats-request-events.js.map +1 -0
- package/dist/tools/stats-usage.d.ts +31 -0
- package/dist/tools/stats-usage.js +206 -0
- package/dist/tools/stats-usage.js.map +1 -0
- package/package.json +9 -4
- package/scripts/analyze-codex-error-failures.mjs +111 -0
- package/scripts/analyze-usage-estimate.mjs +240 -0
- package/scripts/camoufox/gen-fingerprint-env.py +171 -0
- package/scripts/camoufox/launch-auth.mjs +617 -0
- package/scripts/classify-codex-samples.mjs +251 -0
- package/scripts/cleanup-codex-error-samples.mjs +88 -0
- package/scripts/compare-codex-rccx.mjs +268 -0
- package/scripts/copy-compat-assets.mjs +18 -0
- package/scripts/install-release.sh +1 -1
- package/scripts/local-replay-openai-response.mjs +1 -2
- package/scripts/pack-mode.mjs +16 -6
- package/scripts/replay-codex-sample.mjs +24 -2
- package/scripts/responses-compare-server.mjs +119 -0
- package/scripts/tests/apply-patch-loop.mjs +266 -7
- package/scripts/tests/exec-command-loop.mjs +165 -0
- package/scripts/tool-classification-report.ts +281 -0
- package/scripts/verification/samples/openai-chat-list-local-files.json +1 -1
- package/scripts/verify-apply-patch.mjs +28 -17
- package/scripts/verify-codex-error-samples.mjs +102 -0
- package/scripts/verify-e2e-toolcall.mjs +71 -4
- package/scripts/virtual-router-shadow-v2-real.mjs +143 -0
- package/scripts/virtual-router-shadow-v2.mjs +122 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
const STATS_DIR = path.join(os.homedir(), '.routecodex', 'stats');
|
|
5
|
+
const REQUEST_EVENTS_FILE = path.join(STATS_DIR, 'request-events.log');
|
|
6
|
+
function createEmptyBucket() {
|
|
7
|
+
return {
|
|
8
|
+
requestCount: 0,
|
|
9
|
+
successCount: 0,
|
|
10
|
+
errorCount: 0,
|
|
11
|
+
latencyMs: { sum: 0, min: Number.POSITIVE_INFINITY, max: 0 },
|
|
12
|
+
tokens: { prompt: 0, completion: 0, total: 0 }
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function createEmptyDailyUsage() {
|
|
16
|
+
return {
|
|
17
|
+
byProviderKey: {},
|
|
18
|
+
byRoute: {},
|
|
19
|
+
byPool: {},
|
|
20
|
+
byEndpoint: {}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function applyEventToBucket(bucket, ev) {
|
|
24
|
+
bucket.requestCount += 1;
|
|
25
|
+
if (ev.success) {
|
|
26
|
+
bucket.successCount += 1;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
bucket.errorCount += 1;
|
|
30
|
+
}
|
|
31
|
+
if (typeof ev.latencyMs === 'number' && Number.isFinite(ev.latencyMs) && ev.latencyMs >= 0) {
|
|
32
|
+
bucket.latencyMs.sum += ev.latencyMs;
|
|
33
|
+
if (ev.latencyMs < bucket.latencyMs.min) {
|
|
34
|
+
bucket.latencyMs.min = ev.latencyMs;
|
|
35
|
+
}
|
|
36
|
+
if (ev.latencyMs > bucket.latencyMs.max) {
|
|
37
|
+
bucket.latencyMs.max = ev.latencyMs;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (typeof ev.promptTokens === 'number' && Number.isFinite(ev.promptTokens) && ev.promptTokens > 0) {
|
|
41
|
+
bucket.tokens.prompt += ev.promptTokens;
|
|
42
|
+
}
|
|
43
|
+
if (typeof ev.completionTokens === 'number' &&
|
|
44
|
+
Number.isFinite(ev.completionTokens) &&
|
|
45
|
+
ev.completionTokens > 0) {
|
|
46
|
+
bucket.tokens.completion += ev.completionTokens;
|
|
47
|
+
}
|
|
48
|
+
if (typeof ev.totalTokens === 'number' && Number.isFinite(ev.totalTokens) && ev.totalTokens > 0) {
|
|
49
|
+
bucket.tokens.total += ev.totalTokens;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const derived = (typeof ev.promptTokens === 'number' && Number.isFinite(ev.promptTokens) && ev.promptTokens > 0
|
|
53
|
+
? ev.promptTokens
|
|
54
|
+
: 0) +
|
|
55
|
+
(typeof ev.completionTokens === 'number' &&
|
|
56
|
+
Number.isFinite(ev.completionTokens) &&
|
|
57
|
+
ev.completionTokens > 0
|
|
58
|
+
? ev.completionTokens
|
|
59
|
+
: 0);
|
|
60
|
+
bucket.tokens.total += derived;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function ensureDailyBucket(map, key) {
|
|
64
|
+
if (!map[key]) {
|
|
65
|
+
map[key] = createEmptyDailyUsage();
|
|
66
|
+
}
|
|
67
|
+
return map[key];
|
|
68
|
+
}
|
|
69
|
+
function formatDayKey(timestamp) {
|
|
70
|
+
const d = new Date(timestamp);
|
|
71
|
+
const year = d.getFullYear();
|
|
72
|
+
const month = `${d.getMonth() + 1}`.padStart(2, '0');
|
|
73
|
+
const day = `${d.getDate()}`.padStart(2, '0');
|
|
74
|
+
return `${year}-${month}-${day}`;
|
|
75
|
+
}
|
|
76
|
+
function formatWeekKey(timestamp) {
|
|
77
|
+
const d = new Date(timestamp);
|
|
78
|
+
const onejan = new Date(d.getFullYear(), 0, 1);
|
|
79
|
+
const dayMs = 24 * 60 * 60 * 1000;
|
|
80
|
+
const dayOfYear = Math.floor((d.getTime() - onejan.getTime()) / dayMs) + 1;
|
|
81
|
+
const week = Math.ceil(dayOfYear / 7);
|
|
82
|
+
const year = d.getFullYear();
|
|
83
|
+
const weekStr = `${week}`.padStart(2, '0');
|
|
84
|
+
return `${year}-W${weekStr}`;
|
|
85
|
+
}
|
|
86
|
+
export async function loadUsageTimeSeries(query) {
|
|
87
|
+
const result = { days: {}, weeks: {} };
|
|
88
|
+
let content;
|
|
89
|
+
try {
|
|
90
|
+
content = await fs.readFile(REQUEST_EVENTS_FILE, 'utf8');
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
if (!content) {
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
const lines = content.split('\n');
|
|
99
|
+
for (const line of lines) {
|
|
100
|
+
const trimmed = line.trim();
|
|
101
|
+
if (!trimmed) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
let ev = null;
|
|
105
|
+
try {
|
|
106
|
+
const parsed = JSON.parse(trimmed);
|
|
107
|
+
if (parsed && typeof parsed === 'object' && typeof parsed.timestamp === 'number') {
|
|
108
|
+
ev = parsed;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (!ev) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const ts = ev.timestamp;
|
|
118
|
+
if (typeof ts !== 'number' || !Number.isFinite(ts)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (query.fromMs && ts < query.fromMs) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (query.toMs && ts > query.toMs) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const dayKey = formatDayKey(ts);
|
|
128
|
+
const weekKey = formatWeekKey(ts);
|
|
129
|
+
const dayBucket = ensureDailyBucket(result.days, dayKey);
|
|
130
|
+
const providerKey = ev.providerKey || 'unknown';
|
|
131
|
+
const routeKey = ev.routeName || 'unknown';
|
|
132
|
+
const poolKey = ev.poolId || 'default';
|
|
133
|
+
const endpointKey = ev.entryEndpoint || 'unknown';
|
|
134
|
+
if (!dayBucket.byProviderKey[providerKey]) {
|
|
135
|
+
dayBucket.byProviderKey[providerKey] = createEmptyBucket();
|
|
136
|
+
}
|
|
137
|
+
applyEventToBucket(dayBucket.byProviderKey[providerKey], ev);
|
|
138
|
+
if (!dayBucket.byRoute[routeKey]) {
|
|
139
|
+
dayBucket.byRoute[routeKey] = createEmptyBucket();
|
|
140
|
+
}
|
|
141
|
+
applyEventToBucket(dayBucket.byRoute[routeKey], ev);
|
|
142
|
+
if (!dayBucket.byPool[poolKey]) {
|
|
143
|
+
dayBucket.byPool[poolKey] = createEmptyBucket();
|
|
144
|
+
}
|
|
145
|
+
applyEventToBucket(dayBucket.byPool[poolKey], ev);
|
|
146
|
+
if (!dayBucket.byEndpoint[endpointKey]) {
|
|
147
|
+
dayBucket.byEndpoint[endpointKey] = createEmptyBucket();
|
|
148
|
+
}
|
|
149
|
+
applyEventToBucket(dayBucket.byEndpoint[endpointKey], ev);
|
|
150
|
+
const weekBucket = ensureDailyBucket(result.weeks, weekKey);
|
|
151
|
+
if (!weekBucket.byProviderKey[providerKey]) {
|
|
152
|
+
weekBucket.byProviderKey[providerKey] = createEmptyBucket();
|
|
153
|
+
}
|
|
154
|
+
applyEventToBucket(weekBucket.byProviderKey[providerKey], ev);
|
|
155
|
+
if (!weekBucket.byRoute[routeKey]) {
|
|
156
|
+
weekBucket.byRoute[routeKey] = createEmptyBucket();
|
|
157
|
+
}
|
|
158
|
+
applyEventToBucket(weekBucket.byRoute[routeKey], ev);
|
|
159
|
+
if (!weekBucket.byPool[poolKey]) {
|
|
160
|
+
weekBucket.byPool[poolKey] = createEmptyBucket();
|
|
161
|
+
}
|
|
162
|
+
applyEventToBucket(weekBucket.byPool[poolKey], ev);
|
|
163
|
+
if (!weekBucket.byEndpoint[endpointKey]) {
|
|
164
|
+
weekBucket.byEndpoint[endpointKey] = createEmptyBucket();
|
|
165
|
+
}
|
|
166
|
+
applyEventToBucket(weekBucket.byEndpoint[endpointKey], ev);
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
export function summarizeUsage(timeSeries, period, group) {
|
|
171
|
+
const summary = {};
|
|
172
|
+
const source = period === 'day' ? timeSeries.days : period === 'week' ? timeSeries.weeks : timeSeries.days;
|
|
173
|
+
const pickGroup = (daily) => {
|
|
174
|
+
if (group === 'provider')
|
|
175
|
+
return daily.byProviderKey;
|
|
176
|
+
if (group === 'route')
|
|
177
|
+
return daily.byRoute;
|
|
178
|
+
if (group === 'pool')
|
|
179
|
+
return daily.byPool;
|
|
180
|
+
return daily.byEndpoint;
|
|
181
|
+
};
|
|
182
|
+
for (const daily of Object.values(source)) {
|
|
183
|
+
const map = pickGroup(daily);
|
|
184
|
+
for (const [key, bucket] of Object.entries(map)) {
|
|
185
|
+
if (!summary[key]) {
|
|
186
|
+
summary[key] = createEmptyBucket();
|
|
187
|
+
}
|
|
188
|
+
const target = summary[key];
|
|
189
|
+
target.requestCount += bucket.requestCount;
|
|
190
|
+
target.successCount += bucket.successCount;
|
|
191
|
+
target.errorCount += bucket.errorCount;
|
|
192
|
+
target.latencyMs.sum += bucket.latencyMs.sum;
|
|
193
|
+
if (bucket.latencyMs.min < target.latencyMs.min) {
|
|
194
|
+
target.latencyMs.min = bucket.latencyMs.min;
|
|
195
|
+
}
|
|
196
|
+
if (bucket.latencyMs.max > target.latencyMs.max) {
|
|
197
|
+
target.latencyMs.max = bucket.latencyMs.max;
|
|
198
|
+
}
|
|
199
|
+
target.tokens.prompt += bucket.tokens.prompt;
|
|
200
|
+
target.tokens.completion += bucket.tokens.completion;
|
|
201
|
+
target.tokens.total += bucket.tokens.total;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return summary;
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=stats-usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats-usage.js","sourceRoot":"","sources":["../../src/tools/stats-usage.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsonstudio/rcc",
|
|
3
|
-
"version": "0.89.
|
|
3
|
+
"version": "0.89.912",
|
|
4
4
|
"description": "Multi-provider OpenAI proxy server with anthropic/responses/chat support (release)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "npm run llmswitch:ensure && node scripts/build-core.mjs && node scripts/vendor-core.mjs && npm run clean && node scripts/gen-build-info.mjs && tsc && node scripts/copy-compat-assets.mjs && node scripts/copy-modules-config.mjs",
|
|
31
|
-
"build:dev": "BUILD_MODE=dev npm run build && npm run verify:e2e-toolcall && npm run verify:apply-patch && npm run test:routing-instructions && npm run install:global",
|
|
31
|
+
"build:dev": "BUILD_MODE=dev npm run build && npm run verify:e2e-toolcall && npm run verify:apply-patch && npm run verify:exec-command && npm run test:routing-instructions && npm run install:global && npm run mock:regressions && npm run verify:errorsamples",
|
|
32
32
|
"build:min": "npm run llmswitch:ensure && node scripts/build-core.mjs && node scripts/vendor-core.mjs && npm run clean && node scripts/gen-build-info.mjs && tsc && node scripts/copy-compat-assets.mjs && node scripts/copy-modules-config.mjs",
|
|
33
33
|
"prepack": "echo skip-prepack",
|
|
34
34
|
"postbuild": "chmod +x dist/cli.js || true",
|
|
@@ -54,6 +54,8 @@
|
|
|
54
54
|
"prepare": "",
|
|
55
55
|
"postinstall": "chmod +x dist/cli.js || true",
|
|
56
56
|
"verify:apply-patch": "node scripts/verify-apply-patch.mjs",
|
|
57
|
+
"verify:exec-command": "node scripts/tests/exec-command-loop.mjs",
|
|
58
|
+
"verify:errorsamples": "node scripts/verify-codex-error-samples.mjs",
|
|
57
59
|
"install:global": "./scripts/install-global.sh",
|
|
58
60
|
"install:release": "./scripts/install-release.sh",
|
|
59
61
|
"audit:tool-text": "node scripts/audit-tool-text.mjs",
|
|
@@ -116,17 +118,19 @@
|
|
|
116
118
|
"test:v2:protocol": "node tests/v2/dist/protocol-conversion-test.js",
|
|
117
119
|
"test:comprehensive": "node scripts/v2-consistency/comprehensive-consistency-test.mjs",
|
|
118
120
|
"test:golden": "node scripts/tests/golden-provider-cycle.mjs",
|
|
121
|
+
"test:sharedmodule": "npm run jest:run -- tests/sharedmodule/*.spec.ts",
|
|
119
122
|
"sync:ci-goldens": "node scripts/tools/sync-ci-goldens.mjs",
|
|
120
123
|
"mock:extract": "node scripts/mock-provider/extract.mjs",
|
|
121
124
|
"mock:validate": "node scripts/mock-provider/validate.mjs",
|
|
122
125
|
"mock:regressions": "node scripts/mock-provider/run-regressions.mjs",
|
|
123
126
|
"mock:clean": "node scripts/mock-provider/clean.mjs",
|
|
124
127
|
"publish:rcc": "node scripts/publish-rcc.mjs",
|
|
125
|
-
"build:rccx": "npm run build:min && node scripts/pack-mode.mjs --name @jsonstudio/rccx --bin rccx"
|
|
128
|
+
"build:rccx": "npm run build:min && node scripts/pack-mode.mjs --name @jsonstudio/rccx --bin rccx",
|
|
129
|
+
"compare:codex:rccx": "node scripts/compare-codex-rccx.mjs"
|
|
126
130
|
},
|
|
127
131
|
"dependencies": {
|
|
128
132
|
"@anthropic-ai/sdk": "^0.65.0",
|
|
129
|
-
"@jsonstudio/llms": "^0.6.
|
|
133
|
+
"@jsonstudio/llms": "^0.6.586",
|
|
130
134
|
"@jsonstudio/rcc": "^0.89.555",
|
|
131
135
|
"@lmstudio/sdk": "^1.5.0",
|
|
132
136
|
"@radix-ui/react-switch": "^1.2.6",
|
|
@@ -145,6 +149,7 @@
|
|
|
145
149
|
"open": "^9.1.0",
|
|
146
150
|
"openai": "^5.23.0",
|
|
147
151
|
"ora": "^9.0.0",
|
|
152
|
+
"playwright-core": "^1.49.0",
|
|
148
153
|
"rcc-basemodule": "^0.2.7",
|
|
149
154
|
"rcc-debugcenter": "^0.1.6",
|
|
150
155
|
"rcc-errorhandling": "^1.0.10",
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Analyze failures in ~/.routecodex/codex-samples to understand
|
|
5
|
+
* which error patterns出现频率最高,以及哪些适合作为“可修复”样本。
|
|
6
|
+
*
|
|
7
|
+
* 当前只做静态统计,不修改任何样本:
|
|
8
|
+
* - 扫描 openai-responses 下所有 *.json;
|
|
9
|
+
* - 抓取以下错误字符串:
|
|
10
|
+
* - "apply_patch verification failed"
|
|
11
|
+
* - "failed to parse function arguments: missing field `cmd`"
|
|
12
|
+
* - "failed to parse function arguments: missing field `input`"
|
|
13
|
+
* - "Instructions are not valid"
|
|
14
|
+
* - 输出每种模式的命中次数和示例文件列表。
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from 'node:fs/promises';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
import os from 'node:os';
|
|
20
|
+
|
|
21
|
+
const HOME = os.homedir();
|
|
22
|
+
const RESPONSES_DIR = path.join(HOME, '.routecodex', 'codex-samples', 'openai-responses');
|
|
23
|
+
|
|
24
|
+
const PATTERNS = [
|
|
25
|
+
'apply_patch verification failed',
|
|
26
|
+
'failed to parse function arguments: missing field `cmd`',
|
|
27
|
+
'failed to parse function arguments: missing field `input`',
|
|
28
|
+
'Instructions are not valid'
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
async function fileExists(p) {
|
|
32
|
+
try {
|
|
33
|
+
await fs.access(p);
|
|
34
|
+
return true;
|
|
35
|
+
} catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function listJsonFiles(root) {
|
|
41
|
+
const entries = await fs.readdir(root);
|
|
42
|
+
return entries
|
|
43
|
+
.filter((name) => name.toLowerCase().endsWith('.json'))
|
|
44
|
+
.map((name) => path.join(root, name));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function analyzeFile(filePath) {
|
|
48
|
+
const text = await fs.readFile(filePath, 'utf-8');
|
|
49
|
+
const hits = [];
|
|
50
|
+
for (const key of PATTERNS) {
|
|
51
|
+
if (text.includes(key)) {
|
|
52
|
+
hits.push(key);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { filePath, hits };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function main() {
|
|
59
|
+
if (!(await fileExists(RESPONSES_DIR))) {
|
|
60
|
+
console.error('[analyze-codex-error-failures] no codex-samples at', RESPONSES_DIR);
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const files = await listJsonFiles(RESPONSES_DIR);
|
|
65
|
+
if (!files.length) {
|
|
66
|
+
console.log('[analyze-codex-error-failures] no JSON files under', RESPONSES_DIR);
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.log(`[analyze-codex-error-failures] scanning ${files.length} file(s) under ${RESPONSES_DIR}`);
|
|
71
|
+
|
|
72
|
+
const summary = new Map();
|
|
73
|
+
for (const p of PATTERNS) {
|
|
74
|
+
summary.set(p, { count: 0, files: [] });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
for (const file of files) {
|
|
78
|
+
let res;
|
|
79
|
+
try {
|
|
80
|
+
res = await analyzeFile(file);
|
|
81
|
+
} catch {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (!res.hits.length) continue;
|
|
85
|
+
for (const key of res.hits) {
|
|
86
|
+
const entry = summary.get(key);
|
|
87
|
+
if (!entry) continue;
|
|
88
|
+
entry.count += 1;
|
|
89
|
+
if (entry.files.length < 10) {
|
|
90
|
+
entry.files.push(path.basename(file));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const key of PATTERNS) {
|
|
96
|
+
const { count, files } = summary.get(key);
|
|
97
|
+
console.log(`\n=== Pattern: "${key}" ===`);
|
|
98
|
+
console.log(`count: ${count}`);
|
|
99
|
+
if (files.length) {
|
|
100
|
+
console.log('examples:');
|
|
101
|
+
for (const f of files) {
|
|
102
|
+
console.log(` - ${f}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
main().catch((error) => {
|
|
109
|
+
console.error('[analyze-codex-error-failures] failed:', error);
|
|
110
|
+
process.exit(99);
|
|
111
|
+
});
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Offline analysis script:
|
|
4
|
+
* - Walks ~/.routecodex/codex-samples/openai-responses
|
|
5
|
+
* - For each resp_outbound_stage1_client_remap.json sample:
|
|
6
|
+
* - Reads upstream usage.input_tokens/prompt_tokens
|
|
7
|
+
* - Estimates input tokens from the matching client-request payload
|
|
8
|
+
* using a unified tiktoken-based counter.
|
|
9
|
+
* - Computes relative error and compares with the previous sample
|
|
10
|
+
* from a different provider.
|
|
11
|
+
*
|
|
12
|
+
* This does NOT change runtime behaviour; it only prints statistics
|
|
13
|
+
* about how often our estimator would override upstream usage under
|
|
14
|
+
* the "20% + previous-provider" heuristic.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from 'node:fs';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
import os from 'node:os';
|
|
20
|
+
import { encoding_for_model } from 'tiktoken';
|
|
21
|
+
|
|
22
|
+
const BASE_DIR =
|
|
23
|
+
process.env.ROUTECODEX_CODEX_SAMPLES_DIR ||
|
|
24
|
+
path.join(os.homedir(), '.routecodex', 'codex-samples', 'openai-responses');
|
|
25
|
+
|
|
26
|
+
const RESP_SUFFIX = '_resp_outbound_stage1_client_remap.json';
|
|
27
|
+
const INBOUND_CHAT_SUFFIX = '_resp_inbound_stage3_semantic_map.chat.json';
|
|
28
|
+
const CLIENT_REQ_SUFFIX = '_client-request.json';
|
|
29
|
+
|
|
30
|
+
function listRespSamples() {
|
|
31
|
+
const entries = fs.readdirSync(BASE_DIR);
|
|
32
|
+
return entries
|
|
33
|
+
.filter((name) => name.endsWith(RESP_SUFFIX))
|
|
34
|
+
.sort(); // lexicographic sort ~ time order for our filenames
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function loadJson(filePath) {
|
|
38
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function deriveClientRequestName(respName) {
|
|
42
|
+
// Example:
|
|
43
|
+
// resp: openai-responses-tabglm.key1.glm-4.7-...-20260110T182319509-047_resp_outbound_stage1_client_remap.json
|
|
44
|
+
// client: openai-responses-unknown-unknown-20260110T182319509-047_client-request.json
|
|
45
|
+
//
|
|
46
|
+
// 部分旧样本并没有保存对应的 client-request 快照,遇到这种情况直接跳过。
|
|
47
|
+
const match = respName.match(/openai-responses-.*-(\d{8}T\d{9}-\d+)_resp_outbound_stage1_client_remap\.json$/);
|
|
48
|
+
if (!match) return null;
|
|
49
|
+
const tsPart = match[1];
|
|
50
|
+
return `openai-responses-unknown-unknown-${tsPart}${CLIENT_REQ_SUFFIX}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function extractProviderKey(respName) {
|
|
54
|
+
// openai-responses-<providerKey>-<model>-<timestamp>_resp_outbound...
|
|
55
|
+
const withoutSuffix = respName.replace(RESP_SUFFIX, '');
|
|
56
|
+
const parts = withoutSuffix.split('-');
|
|
57
|
+
if (parts.length < 4) return 'unknown';
|
|
58
|
+
// parts[0] = 'openai-responses'
|
|
59
|
+
return parts[1] || 'unknown';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const encoder = encoding_for_model('gpt-4o');
|
|
63
|
+
|
|
64
|
+
function encodeText(text) {
|
|
65
|
+
if (!text || !text.trim()) return 0;
|
|
66
|
+
return encoder.encode(text).length;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function estimateInputTokensFromClientRequest(clientPayload) {
|
|
70
|
+
// For /v1/responses, most recent samples store the original
|
|
71
|
+
// OpenAI/Responses request under requestMetadata.__raw_request_body.
|
|
72
|
+
// We use that as the canonical context snapshot for estimation.
|
|
73
|
+
try {
|
|
74
|
+
const body = clientPayload.body && typeof clientPayload.body === 'object'
|
|
75
|
+
? clientPayload.body
|
|
76
|
+
: clientPayload;
|
|
77
|
+
const raw =
|
|
78
|
+
body?.requestMetadata?.__raw_request_body ??
|
|
79
|
+
body?.__raw_request_body ??
|
|
80
|
+
body;
|
|
81
|
+
return encodeText(JSON.stringify(raw));
|
|
82
|
+
} catch {
|
|
83
|
+
// Fallback: encode entire payload JSON
|
|
84
|
+
return encodeText(JSON.stringify(clientPayload));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function loadRawUpstreamUsage(respName, remapJson) {
|
|
89
|
+
// Read ONLY the inbound semantic-map.chat snapshot, which preserves
|
|
90
|
+
// the provider's original usage as closely as possible.
|
|
91
|
+
// 如果没有这份快照,就跳过该样本,不再回退到 remap usage。
|
|
92
|
+
const prefix = respName.replace(RESP_SUFFIX, '');
|
|
93
|
+
const inboundChatName = `${prefix}${INBOUND_CHAT_SUFFIX}`;
|
|
94
|
+
const inboundChatPath = path.join(BASE_DIR, inboundChatName);
|
|
95
|
+
if (fs.existsSync(inboundChatPath)) {
|
|
96
|
+
try {
|
|
97
|
+
const inbound = loadJson(inboundChatPath);
|
|
98
|
+
const usage =
|
|
99
|
+
(inbound && typeof inbound === 'object' && inbound.usage) ||
|
|
100
|
+
(inbound && inbound.payload && inbound.payload.usage) ||
|
|
101
|
+
undefined;
|
|
102
|
+
if (usage && typeof usage === 'object') {
|
|
103
|
+
return usage;
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
// malformed inbound snapshot, treat as missing
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// No raw upstream usage available for this sample.
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function extractUpstreamInputUsage(usageNode) {
|
|
115
|
+
if (!usageNode || typeof usageNode !== 'object') return undefined;
|
|
116
|
+
const u = usageNode;
|
|
117
|
+
const prompt =
|
|
118
|
+
typeof u.prompt_tokens === 'number'
|
|
119
|
+
? u.prompt_tokens
|
|
120
|
+
: typeof u.input_tokens === 'number'
|
|
121
|
+
? u.input_tokens
|
|
122
|
+
: undefined;
|
|
123
|
+
return typeof prompt === 'number' && Number.isFinite(prompt) && prompt > 0 ? prompt : undefined;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function main() {
|
|
127
|
+
if (!fs.existsSync(BASE_DIR) || !fs.statSync(BASE_DIR).isDirectory()) {
|
|
128
|
+
console.error('[analyze-usage-estimate] codex-samples directory not found:', BASE_DIR);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const respFiles = listRespSamples();
|
|
133
|
+
if (!respFiles.length) {
|
|
134
|
+
console.log('[analyze-usage-estimate] no resp_outbound_stage1_client_remap samples found');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const samples = [];
|
|
139
|
+
|
|
140
|
+
for (const respName of respFiles) {
|
|
141
|
+
const respPath = path.join(BASE_DIR, respName);
|
|
142
|
+
let resp;
|
|
143
|
+
try {
|
|
144
|
+
resp = loadJson(respPath);
|
|
145
|
+
} catch {
|
|
146
|
+
// skip malformed
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const upstreamUsage = loadRawUpstreamUsage(respName, resp);
|
|
150
|
+
const upstreamInput = extractUpstreamInputUsage(upstreamUsage);
|
|
151
|
+
if (upstreamInput === undefined) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const clientReqName = deriveClientRequestName(respName);
|
|
156
|
+
if (!clientReqName) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const clientReqPath = path.join(BASE_DIR, clientReqName);
|
|
160
|
+
if (!fs.existsSync(clientReqPath)) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
let clientReq;
|
|
164
|
+
try {
|
|
165
|
+
clientReq = loadJson(clientReqPath);
|
|
166
|
+
} catch {
|
|
167
|
+
// malformed client snapshot, skip
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const estimatedInput = estimateInputTokensFromClientRequest(clientReq);
|
|
171
|
+
if (!Number.isFinite(estimatedInput) || estimatedInput <= 0) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const providerKey = extractProviderKey(respName);
|
|
176
|
+
samples.push({
|
|
177
|
+
file: respName,
|
|
178
|
+
providerKey,
|
|
179
|
+
upstreamInput,
|
|
180
|
+
estimatedInput,
|
|
181
|
+
relError: Math.abs(upstreamInput - estimatedInput) / Math.max(upstreamInput, 1)
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Sort by filename (approximate time order)
|
|
186
|
+
samples.sort((a, b) => a.file.localeCompare(b.file));
|
|
187
|
+
|
|
188
|
+
const THRESHOLD = 0.4;
|
|
189
|
+
let total = 0;
|
|
190
|
+
let withPrev = 0;
|
|
191
|
+
let overrideCount = 0;
|
|
192
|
+
const perProvider = new Map();
|
|
193
|
+
|
|
194
|
+
for (let i = 0; i < samples.length; i++) {
|
|
195
|
+
const s = samples[i];
|
|
196
|
+
total++;
|
|
197
|
+
|
|
198
|
+
// Find previous sample from a different provider
|
|
199
|
+
let prev = null;
|
|
200
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
201
|
+
if (samples[j].providerKey !== s.providerKey) {
|
|
202
|
+
prev = samples[j];
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
let decision = 'keep_upstream';
|
|
208
|
+
if (prev) {
|
|
209
|
+
withPrev++;
|
|
210
|
+
const currErr = s.relError;
|
|
211
|
+
const prevErr = prev.relError;
|
|
212
|
+
if (currErr > THRESHOLD && prevErr <= THRESHOLD && prevErr < currErr) {
|
|
213
|
+
decision = 'prefer_estimate';
|
|
214
|
+
overrideCount++;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const bucket = perProvider.get(s.providerKey) || { total: 0, overrides: 0 };
|
|
219
|
+
bucket.total++;
|
|
220
|
+
if (decision === 'prefer_estimate') bucket.overrides++;
|
|
221
|
+
perProvider.set(s.providerKey, bucket);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
console.log('=== Usage vs estimatedInputTokens analysis (offline) ===');
|
|
225
|
+
console.log('Base directory:', BASE_DIR);
|
|
226
|
+
console.log('Total samples with upstream+estimated input:', total);
|
|
227
|
+
console.log('Samples with previous different-provider call:', withPrev);
|
|
228
|
+
console.log('Would override (prefer our estimate):', overrideCount);
|
|
229
|
+
console.log('');
|
|
230
|
+
console.log('Per-provider overview:');
|
|
231
|
+
for (const [providerKey, stats] of perProvider.entries()) {
|
|
232
|
+
const ratio =
|
|
233
|
+
stats.total > 0 ? (stats.overrides / stats.total * 100).toFixed(1) : '0.0';
|
|
234
|
+
console.log(
|
|
235
|
+
` - ${providerKey}: total=${stats.total}, overrides=${stats.overrides} (${ratio}%)`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
main();
|