@jsonstudio/llms 0.6.467 → 0.6.567

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.
Files changed (45) hide show
  1. package/dist/conversion/compat/actions/claude-thinking-tools.d.ts +15 -0
  2. package/dist/conversion/compat/actions/claude-thinking-tools.js +72 -0
  3. package/dist/conversion/compat/profiles/chat-gemini.json +1 -1
  4. package/dist/conversion/compat/profiles/responses-output2choices-test.json +12 -0
  5. package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +6 -0
  6. package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +2 -0
  7. package/dist/conversion/hub/pipeline/hub-pipeline.js +15 -0
  8. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +15 -0
  9. package/dist/conversion/hub/process/chat-process.js +44 -17
  10. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +8 -0
  11. package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +13 -8
  12. package/dist/conversion/hub/tool-session-compat.d.ts +26 -0
  13. package/dist/conversion/hub/tool-session-compat.js +299 -0
  14. package/dist/conversion/responses/responses-openai-bridge.d.ts +0 -1
  15. package/dist/conversion/responses/responses-openai-bridge.js +0 -71
  16. package/dist/conversion/shared/gemini-tool-utils.js +8 -0
  17. package/dist/conversion/shared/responses-output-builder.js +6 -68
  18. package/dist/conversion/shared/tool-governor.js +75 -4
  19. package/dist/conversion/shared/tool-mapping.js +14 -8
  20. package/dist/filters/special/request-toolcalls-stringify.js +5 -55
  21. package/dist/filters/special/request-tools-normalize.js +0 -19
  22. package/dist/guidance/index.js +25 -9
  23. package/dist/router/virtual-router/engine-health.d.ts +11 -0
  24. package/dist/router/virtual-router/engine-health.js +210 -0
  25. package/dist/router/virtual-router/engine-logging.d.ts +19 -0
  26. package/dist/router/virtual-router/engine-logging.js +165 -0
  27. package/dist/router/virtual-router/engine-selection.d.ts +32 -0
  28. package/dist/router/virtual-router/engine-selection.js +649 -0
  29. package/dist/router/virtual-router/engine.d.ts +4 -13
  30. package/dist/router/virtual-router/engine.js +64 -517
  31. package/dist/router/virtual-router/health-manager.d.ts +23 -0
  32. package/dist/router/virtual-router/health-manager.js +14 -0
  33. package/dist/router/virtual-router/message-utils.js +22 -0
  34. package/dist/router/virtual-router/routing-instructions.d.ts +6 -1
  35. package/dist/router/virtual-router/routing-instructions.js +129 -3
  36. package/dist/router/virtual-router/types.d.ts +6 -0
  37. package/dist/servertool/handlers/gemini-empty-reply-continue.d.ts +1 -0
  38. package/dist/servertool/handlers/gemini-empty-reply-continue.js +120 -0
  39. package/dist/servertool/handlers/stop-message-auto.d.ts +1 -0
  40. package/dist/servertool/handlers/stop-message-auto.js +147 -0
  41. package/dist/servertool/handlers/vision.js +105 -7
  42. package/dist/servertool/server-side-tools.d.ts +2 -0
  43. package/dist/servertool/server-side-tools.js +2 -0
  44. package/dist/tools/tool-registry.js +195 -4
  45. package/package.json +1 -1
@@ -0,0 +1,649 @@
1
+ import { DEFAULT_ROUTE, ROUTE_PRIORITY, VirtualRouterError, VirtualRouterErrorCode } from './types.js';
2
+ export function selectProviderImpl(requestedRoute, metadata, classification, features, activeState, deps, options = {}) {
3
+ const state = options.routingState ?? activeState;
4
+ const excludedProviderKeys = extractExcludedProviderKeySet(features.metadata);
5
+ const forcedResolution = state.forcedTarget ? resolveInstructionTarget(state.forcedTarget, deps.providerRegistry) : null;
6
+ if (forcedResolution && forcedResolution.mode === 'exact') {
7
+ const forcedKey = forcedResolution.keys[0];
8
+ if (!excludedProviderKeys.has(forcedKey) && !deps.isProviderCoolingDown(forcedKey)) {
9
+ return {
10
+ providerKey: forcedKey,
11
+ routeUsed: requestedRoute,
12
+ pool: [forcedKey],
13
+ poolId: 'forced'
14
+ };
15
+ }
16
+ }
17
+ let stickyResolution = null;
18
+ let stickyKeySet;
19
+ if (!forcedResolution && state.stickyTarget) {
20
+ stickyResolution = resolveInstructionTarget(state.stickyTarget, deps.providerRegistry);
21
+ if (stickyResolution && stickyResolution.mode === 'exact') {
22
+ const stickyKey = stickyResolution.keys[0];
23
+ if (deps.healthManager.isAvailable(stickyKey) &&
24
+ !excludedProviderKeys.has(stickyKey) &&
25
+ !deps.isProviderCoolingDown(stickyKey)) {
26
+ return {
27
+ providerKey: stickyKey,
28
+ routeUsed: requestedRoute,
29
+ pool: [stickyKey],
30
+ poolId: 'sticky'
31
+ };
32
+ }
33
+ }
34
+ if (stickyResolution && stickyResolution.mode === 'filter' && stickyResolution.keys.length > 0) {
35
+ const liveKeys = stickyResolution.keys.filter((key) => deps.healthManager.isAvailable(key) &&
36
+ !excludedProviderKeys.has(key) &&
37
+ !deps.isProviderCoolingDown(key));
38
+ if (liveKeys.length > 0) {
39
+ stickyKeySet = new Set(liveKeys);
40
+ }
41
+ }
42
+ }
43
+ const allowAliasRotation = Boolean(state.stickyTarget) &&
44
+ !state.stickyTarget?.keyAlias &&
45
+ state.stickyTarget?.keyIndex === undefined;
46
+ if (forcedResolution && forcedResolution.mode === 'filter') {
47
+ const forcedKeySet = new Set(forcedResolution.keys);
48
+ if (forcedKeySet.size > 0) {
49
+ for (const key of Array.from(forcedKeySet)) {
50
+ if (excludedProviderKeys.has(key) || deps.isProviderCoolingDown(key)) {
51
+ forcedKeySet.delete(key);
52
+ }
53
+ }
54
+ }
55
+ if (forcedKeySet.size > 0) {
56
+ const candidates = buildRouteCandidates(requestedRoute, classification.candidates, features, deps.routing, deps.providerRegistry);
57
+ const filteredCandidates = filterCandidatesByRoutingState(candidates, state, deps.routing, deps.providerRegistry);
58
+ if (filteredCandidates.length === 0) {
59
+ throw new VirtualRouterError('No available providers after applying routing instructions', VirtualRouterErrorCode.PROVIDER_NOT_AVAILABLE, {
60
+ requestedRoute,
61
+ allowedProviders: Array.from(state.allowedProviders),
62
+ disabledProviders: Array.from(state.disabledProviders)
63
+ });
64
+ }
65
+ return selectFromCandidates(filteredCandidates, metadata, classification, features, state, deps, {
66
+ requiredProviderKeys: forcedKeySet,
67
+ allowAliasRotation
68
+ });
69
+ }
70
+ }
71
+ if (stickyKeySet && stickyKeySet.size > 0) {
72
+ const stickySelection = selectFromStickyPool(stickyKeySet, metadata, features, state, deps, { allowAliasRotation });
73
+ if (stickySelection) {
74
+ return stickySelection;
75
+ }
76
+ }
77
+ const candidates = buildRouteCandidates(requestedRoute, classification.candidates, features, deps.routing, deps.providerRegistry);
78
+ const filteredCandidates = filterCandidatesByRoutingState(candidates, state, deps.routing, deps.providerRegistry);
79
+ if (filteredCandidates.length === 0) {
80
+ throw new VirtualRouterError('No available providers after applying routing instructions', VirtualRouterErrorCode.PROVIDER_NOT_AVAILABLE, {
81
+ requestedRoute,
82
+ allowedProviders: Array.from(state.allowedProviders),
83
+ disabledProviders: Array.from(state.disabledProviders)
84
+ });
85
+ }
86
+ return selectFromCandidates(filteredCandidates, metadata, classification, features, state, deps, {
87
+ allowAliasRotation
88
+ });
89
+ }
90
+ function selectFromCandidates(routes, metadata, classification, features, state, deps, options) {
91
+ const allowedProviders = new Set(state.allowedProviders);
92
+ const disabledProviders = new Set(state.disabledProviders);
93
+ const disabledKeysMap = new Map(Array.from(state.disabledKeys.entries()).map(([provider, keys]) => [
94
+ provider,
95
+ new Set(Array.from(keys).map((k) => (typeof k === 'string' ? k : k + 1)))
96
+ ]));
97
+ const disabledModels = new Map(Array.from(state.disabledModels.entries()).map(([provider, models]) => [provider, new Set(models)]));
98
+ const stickyKey = options.allowAliasRotation ? undefined : deps.resolveStickyKey(metadata);
99
+ const attempted = [];
100
+ const visitedRoutes = new Set();
101
+ const routeQueue = initializeRouteQueue(routes);
102
+ const estimatedTokens = typeof features.estimatedTokens === 'number' && Number.isFinite(features.estimatedTokens)
103
+ ? Math.max(0, features.estimatedTokens)
104
+ : 0;
105
+ while (routeQueue.length) {
106
+ const routeName = routeQueue.shift();
107
+ if (visitedRoutes.has(routeName)) {
108
+ continue;
109
+ }
110
+ const routePools = deps.routing[routeName];
111
+ if (!routeHasTargets(routePools)) {
112
+ visitedRoutes.add(routeName);
113
+ attempted.push(`${routeName}:empty`);
114
+ continue;
115
+ }
116
+ visitedRoutes.add(routeName);
117
+ const orderedPools = sortRoutePools(routePools);
118
+ for (const poolTier of orderedPools) {
119
+ const { providerKey, poolTargets, tierId, failureHint } = trySelectFromTier(routeName, poolTier, stickyKey, estimatedTokens, features, deps, {
120
+ disabledProviders,
121
+ disabledKeysMap,
122
+ allowedProviders,
123
+ disabledModels,
124
+ requiredProviderKeys: options.requiredProviderKeys,
125
+ allowAliasRotation: options.allowAliasRotation
126
+ });
127
+ if (providerKey) {
128
+ return { providerKey, routeUsed: routeName, pool: poolTargets, poolId: tierId };
129
+ }
130
+ if (failureHint) {
131
+ attempted.push(failureHint);
132
+ }
133
+ }
134
+ }
135
+ const requestedRoute = normalizeRouteAlias(classification.routeName || DEFAULT_ROUTE);
136
+ throw new VirtualRouterError(`All providers unavailable for route ${requestedRoute}`, VirtualRouterErrorCode.PROVIDER_NOT_AVAILABLE, { routeName: requestedRoute, attempted });
137
+ }
138
+ function trySelectFromTier(routeName, tier, stickyKey, estimatedTokens, features, deps, options) {
139
+ const { disabledProviders, disabledKeysMap, allowedProviders, disabledModels, requiredProviderKeys } = options;
140
+ let targets = Array.isArray(tier.targets) ? tier.targets : [];
141
+ const excludedRaw = features.metadata?.excludedProviderKeys &&
142
+ Array.isArray(features.metadata.excludedProviderKeys)
143
+ ? features.metadata.excludedProviderKeys
144
+ : [];
145
+ const excludedKeys = new Set(excludedRaw
146
+ .map((val) => (typeof val === 'string' ? val.trim() : ''))
147
+ .filter((val) => Boolean(val)));
148
+ if (excludedKeys.size > 0) {
149
+ targets = targets.filter((key) => !excludedKeys.has(key));
150
+ }
151
+ if (targets.length > 0) {
152
+ targets = targets.filter((key) => !deps.isProviderCoolingDown(key));
153
+ }
154
+ if (allowedProviders && allowedProviders.size > 0) {
155
+ targets = targets.filter((key) => {
156
+ const providerId = extractProviderId(key);
157
+ return providerId && allowedProviders.has(providerId);
158
+ });
159
+ }
160
+ if (disabledProviders && disabledProviders.size > 0) {
161
+ targets = targets.filter((key) => {
162
+ const providerId = extractProviderId(key);
163
+ return providerId && !disabledProviders.has(providerId);
164
+ });
165
+ }
166
+ if (disabledKeysMap && disabledKeysMap.size > 0) {
167
+ targets = targets.filter((key) => {
168
+ const providerId = extractProviderId(key);
169
+ if (!providerId)
170
+ return true;
171
+ const disabledKeys = disabledKeysMap.get(providerId);
172
+ if (!disabledKeys || disabledKeys.size === 0)
173
+ return true;
174
+ const keyAlias = extractKeyAlias(key);
175
+ const keyIndex = extractKeyIndex(key);
176
+ if (keyAlias && disabledKeys.has(keyAlias)) {
177
+ return false;
178
+ }
179
+ if (keyIndex !== undefined && disabledKeys.has(keyIndex + 1)) {
180
+ return false;
181
+ }
182
+ return true;
183
+ });
184
+ }
185
+ if (disabledModels && disabledModels.size > 0) {
186
+ targets = targets.filter((key) => {
187
+ const providerId = extractProviderId(key);
188
+ if (!providerId) {
189
+ return true;
190
+ }
191
+ const disabled = disabledModels.get(providerId);
192
+ if (!disabled || disabled.size === 0) {
193
+ return true;
194
+ }
195
+ const modelId = getProviderModelId(key, deps.providerRegistry);
196
+ if (!modelId) {
197
+ return true;
198
+ }
199
+ return !disabled.has(modelId);
200
+ });
201
+ }
202
+ if (requiredProviderKeys && requiredProviderKeys.size > 0) {
203
+ targets = targets.filter((key) => requiredProviderKeys.has(key));
204
+ }
205
+ const serverToolRequired = features.metadata?.serverToolRequired === true;
206
+ if (serverToolRequired) {
207
+ const filtered = [];
208
+ for (const key of targets) {
209
+ try {
210
+ const profile = deps.providerRegistry.get(key);
211
+ if (!profile.serverToolsDisabled) {
212
+ filtered.push(key);
213
+ }
214
+ }
215
+ catch {
216
+ // ignore unknown providers when filtering for servertools
217
+ }
218
+ }
219
+ targets = filtered;
220
+ }
221
+ if (features.hasImageAttachment && (routeName === DEFAULT_ROUTE || routeName === 'thinking')) {
222
+ const prioritized = [];
223
+ const fallthrough = [];
224
+ for (const key of targets) {
225
+ try {
226
+ const profile = deps.providerRegistry.get(key);
227
+ if (profile.providerType === 'responses') {
228
+ prioritized.push(key);
229
+ }
230
+ else if (profile.providerType === 'gemini') {
231
+ prioritized.push(key);
232
+ }
233
+ else {
234
+ fallthrough.push(key);
235
+ }
236
+ }
237
+ catch {
238
+ fallthrough.push(key);
239
+ }
240
+ }
241
+ if (prioritized.length) {
242
+ targets = prioritized;
243
+ }
244
+ }
245
+ if (!targets.length) {
246
+ return { providerKey: null, poolTargets: [], tierId: tier.id, failureHint: `${routeName}:${tier.id}:empty` };
247
+ }
248
+ const contextResult = deps.contextAdvisor.classify(targets, estimatedTokens, (key) => deps.providerRegistry.get(key));
249
+ const prioritizedPools = buildContextCandidatePools(contextResult);
250
+ for (const candidatePool of prioritizedPools) {
251
+ const providerKey = deps.loadBalancer.select({
252
+ routeName: `${routeName}:${tier.id}`,
253
+ candidates: candidatePool,
254
+ stickyKey: options.allowAliasRotation ? undefined : stickyKey,
255
+ availabilityCheck: (key) => deps.healthManager.isAvailable(key)
256
+ });
257
+ if (providerKey) {
258
+ return { providerKey, poolTargets: tier.targets, tierId: tier.id };
259
+ }
260
+ }
261
+ return {
262
+ providerKey: null,
263
+ poolTargets: tier.targets,
264
+ tierId: tier.id,
265
+ failureHint: describeAttempt(routeName, tier.id, contextResult)
266
+ };
267
+ }
268
+ export function selectFromStickyPool(stickyKeySet, metadata, features, state, deps, options) {
269
+ if (!stickyKeySet || stickyKeySet.size === 0) {
270
+ return null;
271
+ }
272
+ const allowedProviders = new Set(state.allowedProviders);
273
+ const disabledProviders = new Set(state.disabledProviders);
274
+ const disabledKeysMap = new Map(Array.from(state.disabledKeys.entries()).map(([provider, keys]) => [
275
+ provider,
276
+ new Set(Array.from(keys).map((k) => (typeof k === 'string' ? k : k + 1)))
277
+ ]));
278
+ const disabledModels = new Map(Array.from(state.disabledModels.entries()).map(([provider, models]) => [provider, new Set(models)]));
279
+ let candidates = Array.from(stickyKeySet).filter((key) => !deps.isProviderCoolingDown(key));
280
+ if (allowedProviders.size > 0) {
281
+ candidates = candidates.filter((key) => {
282
+ const providerId = extractProviderId(key);
283
+ return providerId && allowedProviders.has(providerId);
284
+ });
285
+ }
286
+ if (disabledProviders.size > 0) {
287
+ candidates = candidates.filter((key) => {
288
+ const providerId = extractProviderId(key);
289
+ return providerId && !disabledProviders.has(providerId);
290
+ });
291
+ }
292
+ if (disabledKeysMap.size > 0 || disabledModels.size > 0) {
293
+ candidates = candidates.filter((key) => {
294
+ const providerId = extractProviderId(key);
295
+ if (!providerId) {
296
+ return true;
297
+ }
298
+ const disabledKeys = disabledKeysMap.get(providerId);
299
+ if (disabledKeys && disabledKeys.size > 0) {
300
+ const keyAlias = extractKeyAlias(key);
301
+ const keyIndex = extractKeyIndex(key);
302
+ if (keyAlias && disabledKeys.has(keyAlias)) {
303
+ return false;
304
+ }
305
+ if (keyIndex !== undefined && disabledKeys.has(keyIndex + 1)) {
306
+ return false;
307
+ }
308
+ }
309
+ const disabledModelSet = disabledModels.get(providerId);
310
+ if (disabledModelSet && disabledModelSet.size > 0) {
311
+ const modelId = getProviderModelId(key, deps.providerRegistry);
312
+ if (modelId && disabledModelSet.has(modelId)) {
313
+ return false;
314
+ }
315
+ }
316
+ return true;
317
+ });
318
+ }
319
+ if (!candidates.length) {
320
+ return null;
321
+ }
322
+ const stickyKey = options.allowAliasRotation ? undefined : deps.resolveStickyKey(metadata);
323
+ const estimatedTokens = typeof features.estimatedTokens === 'number' && Number.isFinite(features.estimatedTokens)
324
+ ? Math.max(0, features.estimatedTokens)
325
+ : 0;
326
+ const tier = {
327
+ id: 'sticky-primary',
328
+ targets: candidates,
329
+ priority: 0
330
+ };
331
+ const { providerKey, poolTargets, tierId } = trySelectFromTier('sticky', tier, stickyKey, estimatedTokens, features, deps, {
332
+ disabledProviders,
333
+ disabledKeysMap,
334
+ allowedProviders,
335
+ disabledModels,
336
+ requiredProviderKeys: stickyKeySet,
337
+ allowAliasRotation: options.allowAliasRotation
338
+ });
339
+ if (!providerKey) {
340
+ return null;
341
+ }
342
+ return {
343
+ providerKey,
344
+ routeUsed: 'sticky',
345
+ pool: poolTargets,
346
+ poolId: tierId
347
+ };
348
+ }
349
+ function filterCandidatesByRoutingState(routes, state, routing, providerRegistry) {
350
+ if (state.allowedProviders.size === 0 &&
351
+ state.disabledProviders.size === 0 &&
352
+ state.disabledKeys.size === 0 &&
353
+ state.disabledModels.size === 0) {
354
+ return routes;
355
+ }
356
+ return routes.filter((routeName) => {
357
+ const pools = routing[routeName];
358
+ if (!pools)
359
+ return false;
360
+ for (const pool of pools) {
361
+ if (!Array.isArray(pool.targets) || pool.targets.length === 0) {
362
+ continue;
363
+ }
364
+ for (const providerKey of pool.targets) {
365
+ const providerId = extractProviderId(providerKey);
366
+ if (!providerId)
367
+ continue;
368
+ if (state.allowedProviders.size > 0 && !state.allowedProviders.has(providerId)) {
369
+ continue;
370
+ }
371
+ if (state.disabledProviders.has(providerId)) {
372
+ continue;
373
+ }
374
+ const disabledKeys = state.disabledKeys.get(providerId);
375
+ if (disabledKeys && disabledKeys.size > 0) {
376
+ const keyAlias = extractKeyAlias(providerKey);
377
+ const keyIndex = extractKeyIndex(providerKey);
378
+ if (keyAlias && disabledKeys.has(keyAlias)) {
379
+ continue;
380
+ }
381
+ if (keyIndex !== undefined && disabledKeys.has(keyIndex + 1)) {
382
+ continue;
383
+ }
384
+ }
385
+ const disabledModels = state.disabledModels.get(providerId);
386
+ if (disabledModels && disabledModels.size > 0) {
387
+ const modelId = getProviderModelId(providerKey, providerRegistry);
388
+ if (modelId && disabledModels.has(modelId)) {
389
+ continue;
390
+ }
391
+ }
392
+ return true;
393
+ }
394
+ }
395
+ return false;
396
+ });
397
+ }
398
+ function buildRouteCandidates(requestedRoute, classificationCandidates, features, routing, providerRegistry) {
399
+ const forceVision = routeHasForceFlag('vision', routing);
400
+ const normalized = normalizeRouteAlias(requestedRoute || DEFAULT_ROUTE);
401
+ const baseList = [];
402
+ if (classificationCandidates && classificationCandidates.length) {
403
+ for (const candidate of classificationCandidates) {
404
+ baseList.push(normalizeRouteAlias(candidate));
405
+ }
406
+ }
407
+ else if (normalized) {
408
+ baseList.push(normalized);
409
+ }
410
+ if (features.hasImageAttachment && !forceVision) {
411
+ const visionAwareRoutes = [DEFAULT_ROUTE, 'thinking'];
412
+ for (const routeName of visionAwareRoutes) {
413
+ if (routeHasTargets(routing[routeName])) {
414
+ if (!baseList.includes(routeName)) {
415
+ baseList.push(routeName);
416
+ }
417
+ }
418
+ }
419
+ }
420
+ let ordered = sortByPriority(baseList);
421
+ if (features.hasImageAttachment && !forceVision) {
422
+ ordered = reorderForInlineVision(ordered, routing, providerRegistry);
423
+ }
424
+ const deduped = [];
425
+ for (const routeName of ordered) {
426
+ if (routeName && !deduped.includes(routeName)) {
427
+ deduped.push(routeName);
428
+ }
429
+ }
430
+ if (!deduped.includes(DEFAULT_ROUTE)) {
431
+ deduped.push(DEFAULT_ROUTE);
432
+ }
433
+ const filtered = deduped.filter((routeName) => routeHasTargets(routing[routeName]));
434
+ if (!filtered.includes(DEFAULT_ROUTE) && routeHasTargets(routing[DEFAULT_ROUTE])) {
435
+ filtered.push(DEFAULT_ROUTE);
436
+ }
437
+ return filtered.length ? filtered : [DEFAULT_ROUTE];
438
+ }
439
+ function reorderForInlineVision(routeNames, routing, providerRegistry) {
440
+ const unique = Array.from(new Set(routeNames.filter(Boolean)));
441
+ if (!unique.length) {
442
+ return unique;
443
+ }
444
+ const inlinePreferred = [];
445
+ const inlineRoutes = [DEFAULT_ROUTE, 'thinking'];
446
+ for (const routeName of inlineRoutes) {
447
+ if (routeSupportsInlineVision(routeName, routing, providerRegistry) && !inlinePreferred.includes(routeName)) {
448
+ inlinePreferred.push(routeName);
449
+ }
450
+ }
451
+ if (!inlinePreferred.length) {
452
+ return unique;
453
+ }
454
+ const remaining = [];
455
+ for (const routeName of unique) {
456
+ if (!inlinePreferred.includes(routeName)) {
457
+ remaining.push(routeName);
458
+ }
459
+ }
460
+ return [...inlinePreferred, ...remaining];
461
+ }
462
+ function routeSupportsInlineVision(routeName, routing, providerRegistry) {
463
+ const pools = routing[routeName];
464
+ if (!Array.isArray(pools)) {
465
+ return false;
466
+ }
467
+ for (const pool of pools) {
468
+ if (!Array.isArray(pool.targets)) {
469
+ continue;
470
+ }
471
+ for (const providerKey of pool.targets) {
472
+ try {
473
+ const profile = providerRegistry.get(providerKey);
474
+ if (profile.providerType === 'responses' || profile.providerType === 'gemini') {
475
+ return true;
476
+ }
477
+ }
478
+ catch {
479
+ // ignore unknown providers when probing capabilities
480
+ }
481
+ }
482
+ }
483
+ return false;
484
+ }
485
+ function normalizeRouteAlias(routeName) {
486
+ const base = routeName && routeName.trim() ? routeName.trim() : DEFAULT_ROUTE;
487
+ return base;
488
+ }
489
+ function routeHasForceFlag(routeName, routing) {
490
+ const pools = routing[routeName];
491
+ if (!Array.isArray(pools)) {
492
+ return false;
493
+ }
494
+ return pools.some((pool) => pool.force);
495
+ }
496
+ function routeHasTargets(pools) {
497
+ if (!Array.isArray(pools)) {
498
+ return false;
499
+ }
500
+ return pools.some((pool) => Array.isArray(pool.targets) && pool.targets.length > 0);
501
+ }
502
+ function sortRoutePools(pools) {
503
+ if (!Array.isArray(pools)) {
504
+ return [];
505
+ }
506
+ return pools
507
+ .filter((pool) => Array.isArray(pool.targets) && pool.targets.length > 0)
508
+ .sort((a, b) => {
509
+ if (a.backup && !b.backup)
510
+ return 1;
511
+ if (!a.backup && b.backup)
512
+ return -1;
513
+ if (a.priority !== b.priority) {
514
+ return b.priority - a.priority;
515
+ }
516
+ return a.id.localeCompare(b.id);
517
+ });
518
+ }
519
+ function initializeRouteQueue(candidates) {
520
+ return Array.from(new Set(candidates));
521
+ }
522
+ function buildContextCandidatePools(result) {
523
+ const ordered = [];
524
+ if (result.safe.length) {
525
+ ordered.push(result.safe);
526
+ return ordered;
527
+ }
528
+ if (result.risky.length) {
529
+ ordered.push(result.risky);
530
+ }
531
+ return ordered;
532
+ }
533
+ function describeAttempt(routeName, poolId, result) {
534
+ const prefix = poolId ? `${routeName}:${poolId}` : routeName;
535
+ if (result.safe.length > 0) {
536
+ return `${prefix}:health`;
537
+ }
538
+ if (result.risky.length > 0) {
539
+ return `${prefix}:context_risky`;
540
+ }
541
+ if (result.overflow.length > 0) {
542
+ return `${prefix}:max_context_window`;
543
+ }
544
+ return prefix;
545
+ }
546
+ function extractProviderId(providerKey) {
547
+ const firstDot = providerKey.indexOf('.');
548
+ if (firstDot <= 0)
549
+ return null;
550
+ return providerKey.substring(0, firstDot);
551
+ }
552
+ function extractKeyAlias(providerKey) {
553
+ const parts = providerKey.split('.');
554
+ if (parts.length === 3) {
555
+ return normalizeAliasDescriptor(parts[1]);
556
+ }
557
+ return null;
558
+ }
559
+ function normalizeAliasDescriptor(alias) {
560
+ if (/^\d+-/.test(alias)) {
561
+ return alias.replace(/^\d+-/, '');
562
+ }
563
+ return alias;
564
+ }
565
+ function extractKeyIndex(providerKey) {
566
+ const parts = providerKey.split('.');
567
+ if (parts.length === 2) {
568
+ const index = parseInt(parts[1], 10);
569
+ if (!isNaN(index) && index > 0) {
570
+ return index;
571
+ }
572
+ }
573
+ return undefined;
574
+ }
575
+ function getProviderModelId(providerKey, providerRegistry) {
576
+ const profile = providerRegistry.get(providerKey);
577
+ if (profile.modelId) {
578
+ return profile.modelId;
579
+ }
580
+ const parts = providerKey.split('.');
581
+ if (parts.length === 2) {
582
+ return parts[1] || null;
583
+ }
584
+ if (parts.length === 3) {
585
+ return parts[2] || null;
586
+ }
587
+ return null;
588
+ }
589
+ function extractExcludedProviderKeySet(metadata) {
590
+ if (!metadata) {
591
+ return new Set();
592
+ }
593
+ const raw = metadata.excludedProviderKeys;
594
+ if (!Array.isArray(raw) || raw.length === 0) {
595
+ return new Set();
596
+ }
597
+ const normalized = raw
598
+ .map((value) => (typeof value === 'string' ? value.trim() : ''))
599
+ .filter((value) => Boolean(value));
600
+ return new Set(normalized);
601
+ }
602
+ function sortByPriority(routeNames) {
603
+ return [...routeNames].sort((a, b) => routeWeight(a) - routeWeight(b));
604
+ }
605
+ function routeWeight(routeName) {
606
+ const idx = ROUTE_PRIORITY.indexOf(routeName);
607
+ return idx >= 0 ? idx : ROUTE_PRIORITY.length;
608
+ }
609
+ function resolveInstructionTarget(target, providerRegistry) {
610
+ if (!target || !target.provider) {
611
+ return null;
612
+ }
613
+ const providerId = target.provider;
614
+ const providerKeys = providerRegistry.listProviderKeys(providerId);
615
+ if (providerKeys.length === 0) {
616
+ return null;
617
+ }
618
+ const alias = typeof target.keyAlias === 'string' ? target.keyAlias.trim() : '';
619
+ const aliasExplicit = alias.length > 0 && target.pathLength === 3;
620
+ if (aliasExplicit) {
621
+ const runtimeKey = providerRegistry.resolveRuntimeKeyByAlias(providerId, alias);
622
+ if (runtimeKey) {
623
+ return { mode: 'exact', keys: [runtimeKey] };
624
+ }
625
+ }
626
+ if (typeof target.keyIndex === 'number' && target.keyIndex > 0) {
627
+ const runtimeKey = providerRegistry.resolveRuntimeKeyByIndex(providerId, target.keyIndex);
628
+ if (runtimeKey) {
629
+ return { mode: 'exact', keys: [runtimeKey] };
630
+ }
631
+ }
632
+ if (target.model && target.model.trim()) {
633
+ const normalizedModel = target.model.trim();
634
+ const matchingKeys = providerKeys.filter((key) => {
635
+ const modelId = getProviderModelId(key, providerRegistry);
636
+ return modelId === normalizedModel;
637
+ });
638
+ if (matchingKeys.length > 0) {
639
+ return { mode: 'filter', keys: matchingKeys };
640
+ }
641
+ }
642
+ if (alias && !aliasExplicit) {
643
+ const legacyKey = providerRegistry.resolveRuntimeKeyByAlias(providerId, alias);
644
+ if (legacyKey) {
645
+ return { mode: 'exact', keys: [legacyKey] };
646
+ }
647
+ }
648
+ return { mode: 'filter', keys: providerKeys };
649
+ }
@@ -4,6 +4,7 @@ export declare class VirtualRouterEngine {
4
4
  private routing;
5
5
  private readonly providerRegistry;
6
6
  private readonly healthManager;
7
+ private readonly providerCooldowns;
7
8
  private loadBalancer;
8
9
  private classifier;
9
10
  private readonly contextAdvisor;
@@ -37,12 +38,8 @@ export declare class VirtualRouterEngine {
37
38
  private normalizeRouteAlias;
38
39
  private validateConfig;
39
40
  private selectProvider;
40
- private trySelectFromTier;
41
41
  private incrementRouteStat;
42
42
  private providerHealthConfig;
43
- private initializeRouteQueue;
44
- private buildContextCandidatePools;
45
- private describeAttempt;
46
43
  private resolveStickyKey;
47
44
  private resolveSessionScope;
48
45
  private getRoutingInstructionState;
@@ -71,8 +68,7 @@ export declare class VirtualRouterEngine {
71
68
  private normalizeAliasDescriptor;
72
69
  private extractKeyIndex;
73
70
  private getProviderModelId;
74
- private mapProviderError;
75
- private deriveReason;
71
+ private extractExcludedProviderKeySet;
76
72
  private buildRouteCandidates;
77
73
  private reorderForInlineVision;
78
74
  private routeSupportsInlineVision;
@@ -83,13 +79,8 @@ export declare class VirtualRouterEngine {
83
79
  private hasPrimaryPool;
84
80
  private sortRoutePools;
85
81
  private flattenPoolTargets;
86
- private buildHitReason;
87
82
  private isRoutingStateEmpty;
88
83
  private persistRoutingInstructionState;
89
- private decorateWithDetail;
90
- private formatVirtualRouterHit;
91
- private resolveRouteColor;
92
- private describeContextUsage;
93
- private describeTargetProvider;
94
- private parseProviderKey;
84
+ private markProviderCooldown;
85
+ private isProviderCoolingDown;
95
86
  }