@jsonstudio/llms 0.6.97 → 0.6.104
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/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +12 -0
- package/dist/router/virtual-router/engine.d.ts +1 -0
- package/dist/router/virtual-router/engine.js +35 -11
- package/dist/router/virtual-router/types.d.ts +1 -0
- package/dist/test-output/virtual-router/results.json +1 -0
- package/dist/test-output/virtual-router/summary.json +12 -0
- package/package.json +1 -1
package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js
CHANGED
|
@@ -62,4 +62,16 @@ function mergeOriginalResponsesPayload(payload, adapterContext) {
|
|
|
62
62
|
if (rawStatus === 'requires_action') {
|
|
63
63
|
payload.status = 'requires_action';
|
|
64
64
|
}
|
|
65
|
+
// 如果桥接后的 payload 没有 usage,而原始 Responses 载荷带有 usage,则回填原始 usage,
|
|
66
|
+
// 确保 token usage 不在工具/桥接路径中丢失。
|
|
67
|
+
const payloadUsage = payload.usage;
|
|
68
|
+
const rawUsage = raw.usage;
|
|
69
|
+
if ((payloadUsage == null || typeof payloadUsage !== 'object') && rawUsage && typeof rawUsage === 'object') {
|
|
70
|
+
try {
|
|
71
|
+
payload.usage = JSON.parse(JSON.stringify(rawUsage));
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
payload.usage = rawUsage;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
65
77
|
}
|
|
@@ -35,7 +35,8 @@ export class VirtualRouterEngine {
|
|
|
35
35
|
const target = this.providerRegistry.buildTarget(selection.providerKey);
|
|
36
36
|
this.healthManager.recordSuccess(selection.providerKey);
|
|
37
37
|
this.incrementRouteStat(selection.routeUsed, selection.providerKey);
|
|
38
|
-
this.
|
|
38
|
+
const hitReason = this.buildHitReason(selection.routeUsed, classification, features);
|
|
39
|
+
this.debug?.log?.('[virtual-router-hit]', selection.routeUsed, selection.providerKey, target.modelId || '', hitReason ? `reason=${hitReason}` : '');
|
|
39
40
|
const didFallback = selection.routeUsed !== routeName || classification.fallback;
|
|
40
41
|
return {
|
|
41
42
|
target,
|
|
@@ -179,22 +180,23 @@ export class VirtualRouterEngine {
|
|
|
179
180
|
const code = event.code?.toUpperCase() ?? 'ERR_UNKNOWN';
|
|
180
181
|
const stage = event.stage?.toLowerCase() ?? 'unknown';
|
|
181
182
|
const recoverable = event.recoverable === true;
|
|
182
|
-
//
|
|
183
|
+
// 默认策略:只有显式可恢复的错误才视为非致命;其余一律按致命处理。
|
|
184
|
+
// 注意:provider 层已经对 429 做了「连续 4 次升级为不可恢复」的判断,这里不再把所有 429 强行当作可恢复。
|
|
183
185
|
let fatal = !recoverable;
|
|
184
186
|
let reason = this.deriveReason(code, stage, statusCode);
|
|
185
187
|
let cooldownOverrideMs;
|
|
186
|
-
//
|
|
187
|
-
if (statusCode ===
|
|
188
|
-
fatal = false;
|
|
189
|
-
cooldownOverrideMs = Math.max(30_000, this.providerHealthConfig().cooldownMs);
|
|
190
|
-
reason = 'rate_limit';
|
|
191
|
-
// 401 / 402 / 500 / 524 以及所有未被标记为可恢复的错误一律视为不可恢复
|
|
192
|
-
}
|
|
193
|
-
else if (statusCode === 401 || statusCode === 402 || statusCode === 403 || code.includes('AUTH')) {
|
|
188
|
+
// 401 / 402 / 500 / 524 以及所有未被标记为可恢复的错误一律视为不可恢复
|
|
189
|
+
if (statusCode === 401 || statusCode === 402 || statusCode === 403 || code.includes('AUTH')) {
|
|
194
190
|
fatal = true;
|
|
195
191
|
cooldownOverrideMs = Math.max(10 * 60_000, this.providerHealthConfig().fatalCooldownMs ?? 10 * 60_000);
|
|
196
192
|
reason = 'auth';
|
|
197
193
|
}
|
|
194
|
+
else if (statusCode === 429 && !recoverable) {
|
|
195
|
+
// 连续 429 已在 provider 层被升级为不可恢复:这里按致命限流处理(长冷却,等同熔断)
|
|
196
|
+
fatal = true;
|
|
197
|
+
cooldownOverrideMs = Math.max(10 * 60_000, this.providerHealthConfig().fatalCooldownMs ?? 10 * 60_000);
|
|
198
|
+
reason = 'rate_limit';
|
|
199
|
+
}
|
|
198
200
|
else if (statusCode && statusCode >= 500) {
|
|
199
201
|
fatal = true;
|
|
200
202
|
cooldownOverrideMs = Math.max(5 * 60_000, this.providerHealthConfig().fatalCooldownMs ?? 5 * 60_000);
|
|
@@ -213,7 +215,8 @@ export class VirtualRouterEngine {
|
|
|
213
215
|
statusCode,
|
|
214
216
|
errorCode: code,
|
|
215
217
|
retryable: recoverable,
|
|
216
|
-
affectsHealth
|
|
218
|
+
// 是否影响健康由 provider 层决定;这里仅在 event.affectsHealth !== false 时才计入健康状态
|
|
219
|
+
affectsHealth: event.affectsHealth !== false,
|
|
217
220
|
cooldownOverrideMs,
|
|
218
221
|
metadata: {
|
|
219
222
|
...event.runtime,
|
|
@@ -274,4 +277,25 @@ export class VirtualRouterEngine {
|
|
|
274
277
|
const idx = ROUTE_PRIORITY.indexOf(routeName);
|
|
275
278
|
return idx >= 0 ? idx : ROUTE_PRIORITY.length;
|
|
276
279
|
}
|
|
280
|
+
buildHitReason(routeUsed, classification, features) {
|
|
281
|
+
const reasoning = classification.reasoning || '';
|
|
282
|
+
const primary = reasoning.split('|')[0] || '';
|
|
283
|
+
const lastToolName = features.lastAssistantToolName;
|
|
284
|
+
if (routeUsed === 'tools') {
|
|
285
|
+
if (lastToolName) {
|
|
286
|
+
return primary ? `${primary}(${lastToolName})` : `tools(${lastToolName})`;
|
|
287
|
+
}
|
|
288
|
+
return primary || 'tools';
|
|
289
|
+
}
|
|
290
|
+
if (routeUsed === 'thinking') {
|
|
291
|
+
return primary || 'thinking';
|
|
292
|
+
}
|
|
293
|
+
if (routeUsed === DEFAULT_ROUTE && classification.fallback) {
|
|
294
|
+
return primary || 'fallback:default';
|
|
295
|
+
}
|
|
296
|
+
if (primary) {
|
|
297
|
+
return primary;
|
|
298
|
+
}
|
|
299
|
+
return routeUsed ? `route:${routeUsed}` : 'route:unknown';
|
|
300
|
+
}
|
|
277
301
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"samplesRoot": "/Users/fanzhang/.routecodex/codex-samples",
|
|
3
|
+
"configPath": "/Users/fanzhang/Documents/github/sharedmodule/llmswitch-core/test/virtual-router/virtual-router.config.json",
|
|
4
|
+
"stats": {
|
|
5
|
+
"totalSamples": 0,
|
|
6
|
+
"processed": 0,
|
|
7
|
+
"routes": {},
|
|
8
|
+
"providers": {},
|
|
9
|
+
"errors": [],
|
|
10
|
+
"scenarios": {}
|
|
11
|
+
}
|
|
12
|
+
}
|