@jsonstudio/llms 0.6.1643 → 0.6.1739
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/compat/actions/harvest-tool-calls-from-text.d.ts +10 -0
- package/dist/conversion/compat/actions/harvest-tool-calls-from-text.js +121 -0
- package/dist/conversion/compat/actions/iflow-kimi-cli-defaults.d.ts +10 -0
- package/dist/conversion/compat/actions/iflow-kimi-cli-defaults.js +80 -0
- package/dist/conversion/compat/actions/iflow-kimi-history-media-placeholder.d.ts +7 -0
- package/dist/conversion/compat/actions/iflow-kimi-history-media-placeholder.js +161 -0
- package/dist/conversion/compat/actions/iflow-kimi-thinking-reasoning-fill.d.ts +12 -0
- package/dist/conversion/compat/actions/iflow-kimi-thinking-reasoning-fill.js +67 -0
- package/dist/conversion/compat/actions/iflow-response-body-unwrap.d.ts +9 -0
- package/dist/conversion/compat/actions/iflow-response-body-unwrap.js +140 -0
- package/dist/conversion/compat/actions/lmstudio-responses-fc-ids.d.ts +10 -0
- package/dist/conversion/compat/actions/lmstudio-responses-fc-ids.js +59 -0
- package/dist/conversion/compat/actions/lmstudio-responses-input-stringify.d.ts +14 -0
- package/dist/conversion/compat/actions/lmstudio-responses-input-stringify.js +125 -0
- package/dist/conversion/compat/actions/normalize-tool-call-ids.d.ts +11 -0
- package/dist/conversion/compat/actions/normalize-tool-call-ids.js +140 -0
- package/dist/conversion/compat/actions/strip-orphan-function-calls-tag.d.ts +2 -0
- package/dist/conversion/compat/actions/strip-orphan-function-calls-tag.js +152 -0
- package/dist/conversion/compat/antigravity-session-signature.d.ts +1 -1
- package/dist/conversion/compat/antigravity-session-signature.js +5 -4
- package/dist/conversion/compat/profiles/chat-iflow.json +6 -0
- package/dist/conversion/compat/profiles/chat-lmstudio.json +7 -1
- package/dist/conversion/hub/operation-table/operation-table-runner.js +1 -1
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +19 -2
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +101 -5
- package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.d.ts +2 -0
- package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.js +63 -0
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +18 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +1 -1
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +8 -5
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +5 -1
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +113 -0
- package/dist/conversion/hub/pipeline/target-utils.js +3 -0
- package/dist/conversion/hub/response/provider-response.js +27 -1
- package/dist/conversion/responses/responses-openai-bridge.js +32 -6
- package/dist/conversion/shared/anthropic-message-utils.js +20 -5
- package/dist/conversion/shared/bridge-id-utils.d.ts +2 -0
- package/dist/conversion/shared/bridge-id-utils.js +52 -15
- package/dist/conversion/shared/responses-conversation-store.js +40 -5
- package/dist/conversion/shared/responses-output-builder.js +23 -7
- package/dist/conversion/shared/responses-tool-utils.d.ts +1 -0
- package/dist/conversion/shared/responses-tool-utils.js +30 -13
- package/dist/conversion/shared/text-markup-normalizer.d.ts +1 -0
- package/dist/conversion/shared/text-markup-normalizer.js +269 -1
- package/dist/router/virtual-router/bootstrap.js +31 -7
- package/dist/router/virtual-router/classifier.js +1 -1
- package/dist/router/virtual-router/engine/antigravity/alias-lease.d.ts +33 -0
- package/dist/router/virtual-router/engine/antigravity/alias-lease.js +247 -0
- package/dist/router/virtual-router/engine/health/index.d.ts +23 -0
- package/dist/router/virtual-router/engine/health/index.js +720 -0
- package/dist/router/virtual-router/engine/provider-key/parse.d.ts +6 -0
- package/dist/router/virtual-router/engine/provider-key/parse.js +43 -0
- package/dist/router/virtual-router/engine/routing-pools/index.d.ts +13 -0
- package/dist/router/virtual-router/engine/routing-pools/index.js +225 -0
- package/dist/router/virtual-router/engine/routing-state/keys.d.ts +3 -0
- package/dist/router/virtual-router/engine/routing-state/keys.js +30 -0
- package/dist/router/virtual-router/engine/routing-state/metadata.d.ts +6 -0
- package/dist/router/virtual-router/engine/routing-state/metadata.js +132 -0
- package/dist/router/virtual-router/engine/routing-state/store.d.ts +11 -0
- package/dist/router/virtual-router/engine/routing-state/store.js +107 -0
- package/dist/router/virtual-router/engine-health.d.ts +1 -23
- package/dist/router/virtual-router/engine-health.js +1 -720
- package/dist/router/virtual-router/engine-selection/route-utils.js +57 -0
- package/dist/router/virtual-router/engine-selection/tier-selection-select.js +8 -48
- package/dist/router/virtual-router/engine-selection/tier-selection.js +34 -17
- package/dist/router/virtual-router/engine-selection.d.ts +1 -13
- package/dist/router/virtual-router/engine-selection.js +1 -225
- package/dist/router/virtual-router/engine.d.ts +2 -23
- package/dist/router/virtual-router/engine.js +130 -603
- package/dist/router/virtual-router/message-utils.js +15 -5
- package/dist/servertool/engine.js +4 -4
- package/dist/servertool/handlers/followup-request-builder.js +46 -0
- package/dist/servertool/handlers/gemini-empty-reply-continue.js +48 -47
- package/dist/servertool/handlers/stop-message-auto.js +64 -7
- package/dist/servertool/handlers/vision.js +10 -0
- package/dist/servertool/types.d.ts +3 -0
- package/dist/sse/sse-to-json/builders/response-builder.js +6 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +32 -2
- package/dist/sse/sse-to-json/parsers/sse-parser.js +34 -0
- package/dist/sse/sse-to-json/responses-sse-to-json-converter.d.ts +1 -0
- package/dist/sse/sse-to-json/responses-sse-to-json-converter.js +33 -1
- package/dist/tools/apply-patch/args-normalizer/default-actions.d.ts +2 -0
- package/dist/tools/apply-patch/args-normalizer/default-actions.js +12 -0
- package/dist/tools/apply-patch/args-normalizer/extract-patch.d.ts +2 -0
- package/dist/tools/apply-patch/args-normalizer/extract-patch.js +15 -0
- package/dist/tools/apply-patch/args-normalizer/index.d.ts +2 -0
- package/dist/tools/apply-patch/args-normalizer/index.js +164 -0
- package/dist/tools/apply-patch/args-normalizer/structured-builders.d.ts +7 -0
- package/dist/tools/apply-patch/args-normalizer/structured-builders.js +85 -0
- package/dist/tools/apply-patch/args-normalizer/types.d.ts +54 -0
- package/dist/tools/apply-patch/args-normalizer/types.js +1 -0
- package/dist/tools/apply-patch/patch-text/looks-like-patch.js +1 -0
- package/dist/tools/apply-patch/patch-text/normalize.js +104 -5
- package/dist/tools/apply-patch/structured/coercion.js +28 -4
- package/dist/tools/apply-patch/validator.js +7 -146
- package/package.json +1 -1
|
@@ -61,10 +61,27 @@ export function buildRouteCandidates(requestedRoute, classificationCandidates, f
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
+
if (features.hasImageAttachment) {
|
|
65
|
+
const allRouteNames = Object.keys(routing);
|
|
66
|
+
for (const routeName of allRouteNames) {
|
|
67
|
+
if (!routeHasTargets(routing[routeName])) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (!routeSupportsModel(routeName, 'kimi-k2.5', routing, providerRegistry)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (!baseList.includes(routeName)) {
|
|
74
|
+
baseList.push(routeName);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
64
78
|
let ordered = sortByPriority(baseList);
|
|
65
79
|
if (features.hasImageAttachment && !forceVision) {
|
|
66
80
|
ordered = reorderForInlineVision(ordered, routing, providerRegistry);
|
|
67
81
|
}
|
|
82
|
+
if (features.hasImageAttachment) {
|
|
83
|
+
ordered = reorderForPreferredModel(ordered, 'kimi-k2.5', routing, providerRegistry);
|
|
84
|
+
}
|
|
68
85
|
const deduped = [];
|
|
69
86
|
for (const routeName of ordered) {
|
|
70
87
|
if (routeName && !deduped.includes(routeName)) {
|
|
@@ -142,3 +159,43 @@ function routeSupportsInlineVision(routeName, routing, providerRegistry) {
|
|
|
142
159
|
}
|
|
143
160
|
return false;
|
|
144
161
|
}
|
|
162
|
+
function reorderForPreferredModel(routeNames, modelId, routing, providerRegistry) {
|
|
163
|
+
const unique = Array.from(new Set(routeNames.filter(Boolean)));
|
|
164
|
+
if (!unique.length) {
|
|
165
|
+
return unique;
|
|
166
|
+
}
|
|
167
|
+
const preferred = unique.filter((routeName) => routeSupportsModel(routeName, modelId, routing, providerRegistry));
|
|
168
|
+
if (!preferred.length) {
|
|
169
|
+
return unique;
|
|
170
|
+
}
|
|
171
|
+
const remaining = unique.filter((routeName) => !preferred.includes(routeName));
|
|
172
|
+
return [...preferred, ...remaining];
|
|
173
|
+
}
|
|
174
|
+
function routeSupportsModel(routeName, modelId, routing, providerRegistry) {
|
|
175
|
+
const normalizedModel = modelId.trim().toLowerCase();
|
|
176
|
+
if (!normalizedModel) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
const pools = routing[routeName];
|
|
180
|
+
if (!Array.isArray(pools)) {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
for (const pool of pools) {
|
|
184
|
+
if (!Array.isArray(pool.targets)) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
for (const providerKey of pool.targets) {
|
|
188
|
+
try {
|
|
189
|
+
const profile = providerRegistry.get(providerKey);
|
|
190
|
+
const candidate = typeof profile.modelId === 'string' ? profile.modelId.trim().toLowerCase() : '';
|
|
191
|
+
if (candidate === normalizedModel) {
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// ignore unknown providers when probing capabilities
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
@@ -282,7 +282,8 @@ export function selectProviderKeyFromCandidatePool(opts) {
|
|
|
282
282
|
if (!bucket.length) {
|
|
283
283
|
continue;
|
|
284
284
|
}
|
|
285
|
-
|
|
285
|
+
// Keep candidate ordering stable (config order). Availability/blacklist/cooldown still apply.
|
|
286
|
+
bucket.sort((a, b) => a.order - b.order);
|
|
286
287
|
let bucketCandidates = bucket.map((item) => item.key);
|
|
287
288
|
// Single-provider pool should never be "emptied" by health/cooldown.
|
|
288
289
|
if (bucketCandidates.length === 1) {
|
|
@@ -299,10 +300,6 @@ export function selectProviderKeyFromCandidatePool(opts) {
|
|
|
299
300
|
deps,
|
|
300
301
|
excludedKeys
|
|
301
302
|
});
|
|
302
|
-
const bucketPenaltyMap = {};
|
|
303
|
-
for (const item of bucket) {
|
|
304
|
-
bucketPenaltyMap[item.key] = item.penalty;
|
|
305
|
-
}
|
|
306
303
|
const bucketWeights = {};
|
|
307
304
|
const bucketMultipliers = {};
|
|
308
305
|
for (const item of bucket) {
|
|
@@ -337,8 +334,7 @@ export function selectProviderKeyFromCandidatePool(opts) {
|
|
|
337
334
|
candidates: bucketCandidates,
|
|
338
335
|
orderedTargets: tier.targets,
|
|
339
336
|
providerRegistry: deps.providerRegistry,
|
|
340
|
-
availabilityCheck: isAvailable
|
|
341
|
-
penalties: bucketPenaltyMap
|
|
337
|
+
availabilityCheck: isAvailable
|
|
342
338
|
});
|
|
343
339
|
if (!group) {
|
|
344
340
|
continue;
|
|
@@ -359,50 +355,14 @@ export function selectProviderKeyFromCandidatePool(opts) {
|
|
|
359
355
|
}
|
|
360
356
|
continue;
|
|
361
357
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
if (!isAvailable(key))
|
|
367
|
-
continue;
|
|
368
|
-
const m = bucketMultipliers[key] ?? 1;
|
|
369
|
-
if (m > bestM) {
|
|
370
|
-
bestM = m;
|
|
371
|
-
best = key;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
if (best) {
|
|
375
|
-
return best;
|
|
376
|
-
}
|
|
377
|
-
continue;
|
|
378
|
-
}
|
|
379
|
-
else if (isRecoveryAttempt) {
|
|
380
|
-
const recovered = selectFirstAvailable(bucketCandidates);
|
|
381
|
-
if (recovered)
|
|
382
|
-
return recovered;
|
|
383
|
-
continue;
|
|
384
|
-
}
|
|
358
|
+
const recovered = selectFirstAvailable(bucketCandidates);
|
|
359
|
+
if (recovered)
|
|
360
|
+
return recovered;
|
|
361
|
+
continue;
|
|
385
362
|
// (unreachable) recovery handled above
|
|
386
363
|
}
|
|
387
364
|
else {
|
|
388
|
-
if (isRecoveryAttempt
|
|
389
|
-
let best = null;
|
|
390
|
-
let bestM = Number.NEGATIVE_INFINITY;
|
|
391
|
-
for (const key of bucketCandidates) {
|
|
392
|
-
if (!isAvailable(key))
|
|
393
|
-
continue;
|
|
394
|
-
const m = bucketMultipliers[key] ?? 1;
|
|
395
|
-
if (m > bestM) {
|
|
396
|
-
bestM = m;
|
|
397
|
-
best = key;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
if (best) {
|
|
401
|
-
return best;
|
|
402
|
-
}
|
|
403
|
-
continue;
|
|
404
|
-
}
|
|
405
|
-
else if (isRecoveryAttempt) {
|
|
365
|
+
if (isRecoveryAttempt) {
|
|
406
366
|
const recovered = selectFirstAvailable(bucketCandidates);
|
|
407
367
|
if (recovered)
|
|
408
368
|
return recovered;
|
|
@@ -108,6 +108,14 @@ function resolveSessionScopeKey(metadata) {
|
|
|
108
108
|
if (conversationId) {
|
|
109
109
|
return `conversation:${conversationId}`;
|
|
110
110
|
}
|
|
111
|
+
// Antigravity-Manager alignment: when the client does not provide session_id/conversation_id,
|
|
112
|
+
// fall back to the derived antigravitySessionId so alias/session binding still works.
|
|
113
|
+
const antigravitySessionId = typeof record.antigravitySessionId === 'string'
|
|
114
|
+
? String(record.antigravitySessionId).trim()
|
|
115
|
+
: '';
|
|
116
|
+
if (antigravitySessionId) {
|
|
117
|
+
return `session:${antigravitySessionId}`;
|
|
118
|
+
}
|
|
111
119
|
return null;
|
|
112
120
|
}
|
|
113
121
|
function buildScopedSessionKey(sessionKey) {
|
|
@@ -376,29 +384,38 @@ export function trySelectFromTier(routeName, tier, stickyKey, estimatedTokens, f
|
|
|
376
384
|
}
|
|
377
385
|
targets = filtered;
|
|
378
386
|
}
|
|
379
|
-
if (features.hasImageAttachment
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
387
|
+
if (features.hasImageAttachment) {
|
|
388
|
+
const kimiTargets = targets.filter((key) => {
|
|
389
|
+
const modelId = getProviderModelId(key, deps.providerRegistry) ?? '';
|
|
390
|
+
return modelId.trim().toLowerCase() === 'kimi-k2.5';
|
|
391
|
+
});
|
|
392
|
+
if (kimiTargets.length) {
|
|
393
|
+
targets = kimiTargets;
|
|
394
|
+
}
|
|
395
|
+
else if (routeName === DEFAULT_ROUTE || routeName === 'thinking') {
|
|
396
|
+
const prioritized = [];
|
|
397
|
+
const fallthrough = [];
|
|
398
|
+
for (const key of targets) {
|
|
399
|
+
try {
|
|
400
|
+
const profile = deps.providerRegistry.get(key);
|
|
401
|
+
if (profile.providerType === 'responses') {
|
|
402
|
+
prioritized.push(key);
|
|
403
|
+
}
|
|
404
|
+
else if (profile.providerType === 'gemini') {
|
|
405
|
+
prioritized.push(key);
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
fallthrough.push(key);
|
|
409
|
+
}
|
|
390
410
|
}
|
|
391
|
-
|
|
411
|
+
catch {
|
|
392
412
|
fallthrough.push(key);
|
|
393
413
|
}
|
|
394
414
|
}
|
|
395
|
-
|
|
396
|
-
|
|
415
|
+
if (prioritized.length) {
|
|
416
|
+
targets = prioritized;
|
|
397
417
|
}
|
|
398
418
|
}
|
|
399
|
-
if (prioritized.length) {
|
|
400
|
-
targets = prioritized;
|
|
401
|
-
}
|
|
402
419
|
}
|
|
403
420
|
if (!targets.length) {
|
|
404
421
|
const leaseHint = leaseResult.blocked > 0
|
|
@@ -1,13 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type { RoutingInstructionState } from './routing-instructions.js';
|
|
3
|
-
import type { SelectionDeps } from './engine-selection/selection-deps.js';
|
|
4
|
-
export { selectDirectProviderModel } from './engine-selection/direct-provider-model.js';
|
|
5
|
-
export { selectFromStickyPool } from './engine-selection/sticky-pool.js';
|
|
6
|
-
export declare function selectProviderImpl(requestedRoute: string, metadata: RouterMetadataInput, classification: ClassificationResult, features: RoutingFeatures, activeState: RoutingInstructionState, deps: SelectionDeps, options?: {
|
|
7
|
-
routingState?: RoutingInstructionState;
|
|
8
|
-
}): {
|
|
9
|
-
providerKey: string;
|
|
10
|
-
routeUsed: string;
|
|
11
|
-
pool: string[];
|
|
12
|
-
poolId?: string;
|
|
13
|
-
};
|
|
1
|
+
export { selectProviderImpl, selectDirectProviderModel, selectFromStickyPool } from './engine/routing-pools/index.js';
|
|
@@ -1,225 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { extractExcludedProviderKeySet, extractProviderId } from './engine-selection/key-parsing.js';
|
|
3
|
-
import { trySelectFromTier } from './engine-selection/tier-selection.js';
|
|
4
|
-
import { resolveInstructionTarget } from './engine-selection/instruction-target.js';
|
|
5
|
-
import { filterCandidatesByRoutingState } from './engine-selection/routing-state-filter.js';
|
|
6
|
-
import { selectFromStickyPool as selectFromStickyPoolImpl } from './engine-selection/sticky-pool.js';
|
|
7
|
-
export { selectDirectProviderModel } from './engine-selection/direct-provider-model.js';
|
|
8
|
-
export { selectFromStickyPool } from './engine-selection/sticky-pool.js';
|
|
9
|
-
import { buildRouteCandidates, extendRouteCandidatesForState, initializeRouteQueue, normalizeRouteAlias, routeHasTargets, sortRoutePools } from './engine-selection/route-utils.js';
|
|
10
|
-
export function selectProviderImpl(requestedRoute, metadata, classification, features, activeState, deps, options = {}) {
|
|
11
|
-
const state = options.routingState ?? activeState;
|
|
12
|
-
const quotaView = deps.quotaView;
|
|
13
|
-
const quotaNow = quotaView ? Date.now() : 0;
|
|
14
|
-
const isAllowedByQuota = (key) => {
|
|
15
|
-
if (!quotaView) {
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
const entry = quotaView(key);
|
|
19
|
-
if (!entry) {
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
if (!entry.inPool) {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
if (entry.cooldownUntil && entry.cooldownUntil > quotaNow) {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
if (entry.blacklistUntil && entry.blacklistUntil > quotaNow) {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
return true;
|
|
32
|
-
};
|
|
33
|
-
const excludedProviderKeys = extractExcludedProviderKeySet(features.metadata);
|
|
34
|
-
const forcedResolution = state.forcedTarget ? resolveInstructionTarget(state.forcedTarget, deps.providerRegistry) : null;
|
|
35
|
-
if (forcedResolution && forcedResolution.mode === 'exact') {
|
|
36
|
-
const forcedKey = forcedResolution.keys[0];
|
|
37
|
-
if (!excludedProviderKeys.has(forcedKey) && !deps.isProviderCoolingDown(forcedKey) && isAllowedByQuota(forcedKey)) {
|
|
38
|
-
return {
|
|
39
|
-
providerKey: forcedKey,
|
|
40
|
-
routeUsed: requestedRoute,
|
|
41
|
-
pool: [forcedKey],
|
|
42
|
-
poolId: 'forced'
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
let stickyResolution = null;
|
|
47
|
-
let stickyKeySet;
|
|
48
|
-
if (!forcedResolution && state.stickyTarget) {
|
|
49
|
-
stickyResolution = resolveInstructionTarget(state.stickyTarget, deps.providerRegistry);
|
|
50
|
-
if (stickyResolution && stickyResolution.mode === 'exact') {
|
|
51
|
-
const stickyKey = stickyResolution.keys[0];
|
|
52
|
-
if ((deps.quotaView ? true : deps.healthManager.isAvailable(stickyKey)) &&
|
|
53
|
-
!excludedProviderKeys.has(stickyKey) &&
|
|
54
|
-
!deps.isProviderCoolingDown(stickyKey) &&
|
|
55
|
-
isAllowedByQuota(stickyKey)) {
|
|
56
|
-
return {
|
|
57
|
-
providerKey: stickyKey,
|
|
58
|
-
routeUsed: requestedRoute,
|
|
59
|
-
pool: [stickyKey],
|
|
60
|
-
poolId: 'sticky'
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (stickyResolution && stickyResolution.mode === 'filter' && stickyResolution.keys.length > 0) {
|
|
65
|
-
const liveKeys = stickyResolution.keys.filter((key) => (deps.quotaView ? true : deps.healthManager.isAvailable(key)) &&
|
|
66
|
-
!excludedProviderKeys.has(key) &&
|
|
67
|
-
!deps.isProviderCoolingDown(key) &&
|
|
68
|
-
isAllowedByQuota(key));
|
|
69
|
-
if (liveKeys.length > 0) {
|
|
70
|
-
stickyKeySet = new Set(liveKeys);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const allowAliasRotation = Boolean(state.stickyTarget) &&
|
|
75
|
-
!state.stickyTarget?.keyAlias &&
|
|
76
|
-
state.stickyTarget?.keyIndex === undefined;
|
|
77
|
-
if (forcedResolution && forcedResolution.mode === 'filter') {
|
|
78
|
-
const forcedKeySet = new Set(forcedResolution.keys);
|
|
79
|
-
if (forcedKeySet.size > 0) {
|
|
80
|
-
for (const key of Array.from(forcedKeySet)) {
|
|
81
|
-
if (excludedProviderKeys.has(key) || deps.isProviderCoolingDown(key)) {
|
|
82
|
-
forcedKeySet.delete(key);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (forcedKeySet.size > 0) {
|
|
87
|
-
const candidates = extendRouteCandidatesForState(buildRouteCandidates(requestedRoute, classification.candidates, features, deps.routing, deps.providerRegistry), state, deps.routing);
|
|
88
|
-
const filteredCandidates = filterCandidatesByRoutingState(candidates, state, deps.routing, deps.providerRegistry);
|
|
89
|
-
if (filteredCandidates.length === 0) {
|
|
90
|
-
const allowedProviders = Array.from(state.allowedProviders);
|
|
91
|
-
const disabledProviders = Array.from(state.disabledProviders);
|
|
92
|
-
const providersInRouting = new Set();
|
|
93
|
-
for (const pools of Object.values(deps.routing)) {
|
|
94
|
-
if (!Array.isArray(pools))
|
|
95
|
-
continue;
|
|
96
|
-
for (const pool of pools) {
|
|
97
|
-
if (!pool || !Array.isArray(pool.targets))
|
|
98
|
-
continue;
|
|
99
|
-
for (const key of pool.targets) {
|
|
100
|
-
if (typeof key !== 'string' || !key)
|
|
101
|
-
continue;
|
|
102
|
-
const providerId = extractProviderId(key);
|
|
103
|
-
if (providerId) {
|
|
104
|
-
providersInRouting.add(providerId);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
const missingAllowedProviders = allowedProviders.length > 0 ? allowedProviders.filter((provider) => !providersInRouting.has(provider)) : [];
|
|
110
|
-
const hint = (() => {
|
|
111
|
-
if (missingAllowedProviders.length > 0) {
|
|
112
|
-
return `Allowed providers not present in routing pools: ${missingAllowedProviders.join(', ')}`;
|
|
113
|
-
}
|
|
114
|
-
return 'Routing instructions excluded all route candidates';
|
|
115
|
-
})();
|
|
116
|
-
throw new VirtualRouterError(`No available providers after applying routing instructions (${hint}). ` +
|
|
117
|
-
`Tip: remove/adjust <**...**> routing instructions (or use <**clear**>), or add providers/models to routing.`, VirtualRouterErrorCode.PROVIDER_NOT_AVAILABLE, {
|
|
118
|
-
requestedRoute,
|
|
119
|
-
allowedProviders,
|
|
120
|
-
disabledProviders,
|
|
121
|
-
missingAllowedProviders
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
return selectFromCandidates(filteredCandidates, metadata, classification, features, state, deps, {
|
|
125
|
-
requiredProviderKeys: forcedKeySet,
|
|
126
|
-
allowAliasRotation
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
if (stickyKeySet && stickyKeySet.size > 0) {
|
|
131
|
-
const stickySelection = selectFromStickyPoolImpl(stickyKeySet, metadata, features, state, deps, { allowAliasRotation });
|
|
132
|
-
if (stickySelection) {
|
|
133
|
-
return stickySelection;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
const candidates = buildRouteCandidates(requestedRoute, classification.candidates, features, deps.routing, deps.providerRegistry);
|
|
137
|
-
const expandedCandidates = extendRouteCandidatesForState(candidates, state, deps.routing);
|
|
138
|
-
const filteredCandidates = filterCandidatesByRoutingState(expandedCandidates, state, deps.routing, deps.providerRegistry);
|
|
139
|
-
if (filteredCandidates.length === 0) {
|
|
140
|
-
const allowedProviders = Array.from(state.allowedProviders);
|
|
141
|
-
const disabledProviders = Array.from(state.disabledProviders);
|
|
142
|
-
const providersInRouting = new Set();
|
|
143
|
-
for (const pools of Object.values(deps.routing)) {
|
|
144
|
-
if (!Array.isArray(pools))
|
|
145
|
-
continue;
|
|
146
|
-
for (const pool of pools) {
|
|
147
|
-
if (!pool || !Array.isArray(pool.targets))
|
|
148
|
-
continue;
|
|
149
|
-
for (const key of pool.targets) {
|
|
150
|
-
if (typeof key !== 'string' || !key)
|
|
151
|
-
continue;
|
|
152
|
-
const providerId = extractProviderId(key);
|
|
153
|
-
if (providerId) {
|
|
154
|
-
providersInRouting.add(providerId);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
const missingAllowedProviders = allowedProviders.length > 0 ? allowedProviders.filter((provider) => !providersInRouting.has(provider)) : [];
|
|
160
|
-
const hint = (() => {
|
|
161
|
-
if (missingAllowedProviders.length > 0) {
|
|
162
|
-
return `Allowed providers not present in routing pools: ${missingAllowedProviders.join(', ')}`;
|
|
163
|
-
}
|
|
164
|
-
return 'Routing instructions excluded all route candidates';
|
|
165
|
-
})();
|
|
166
|
-
throw new VirtualRouterError(`No available providers after applying routing instructions (${hint}). ` +
|
|
167
|
-
`Tip: remove/adjust <**...**> routing instructions (or use <**clear**>), or add providers/models to routing.`, VirtualRouterErrorCode.PROVIDER_NOT_AVAILABLE, {
|
|
168
|
-
requestedRoute,
|
|
169
|
-
allowedProviders,
|
|
170
|
-
disabledProviders,
|
|
171
|
-
missingAllowedProviders
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
return selectFromCandidates(filteredCandidates, metadata, classification, features, state, deps, {
|
|
175
|
-
allowAliasRotation
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
function selectFromCandidates(routes, metadata, classification, features, state, deps, options) {
|
|
179
|
-
const allowedProviders = new Set(state.allowedProviders);
|
|
180
|
-
const disabledProviders = new Set(state.disabledProviders);
|
|
181
|
-
const disabledKeysMap = new Map(Array.from(state.disabledKeys.entries()).map(([provider, keys]) => [
|
|
182
|
-
provider,
|
|
183
|
-
new Set(Array.from(keys).map((k) => (typeof k === 'string' ? k : k + 1)))
|
|
184
|
-
]));
|
|
185
|
-
const disabledModels = new Map(Array.from(state.disabledModels.entries()).map(([provider, models]) => [provider, new Set(models)]));
|
|
186
|
-
const stickyKey = options.allowAliasRotation ? undefined : deps.resolveStickyKey(metadata);
|
|
187
|
-
const attempted = [];
|
|
188
|
-
const visitedRoutes = new Set();
|
|
189
|
-
const routeQueue = initializeRouteQueue(routes);
|
|
190
|
-
const estimatedTokens = typeof features.estimatedTokens === 'number' && Number.isFinite(features.estimatedTokens)
|
|
191
|
-
? Math.max(0, features.estimatedTokens)
|
|
192
|
-
: 0;
|
|
193
|
-
while (routeQueue.length) {
|
|
194
|
-
const routeName = routeQueue.shift();
|
|
195
|
-
if (visitedRoutes.has(routeName)) {
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
const routePools = deps.routing[routeName];
|
|
199
|
-
if (!routeHasTargets(routePools)) {
|
|
200
|
-
visitedRoutes.add(routeName);
|
|
201
|
-
attempted.push(`${routeName}:empty`);
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
visitedRoutes.add(routeName);
|
|
205
|
-
const orderedPools = sortRoutePools(routePools);
|
|
206
|
-
for (const poolTier of orderedPools) {
|
|
207
|
-
const { providerKey, poolTargets, tierId, failureHint } = trySelectFromTier(routeName, poolTier, stickyKey, estimatedTokens, features, deps, {
|
|
208
|
-
disabledProviders,
|
|
209
|
-
disabledKeysMap,
|
|
210
|
-
allowedProviders,
|
|
211
|
-
disabledModels,
|
|
212
|
-
requiredProviderKeys: options.requiredProviderKeys,
|
|
213
|
-
allowAliasRotation: options.allowAliasRotation
|
|
214
|
-
});
|
|
215
|
-
if (providerKey) {
|
|
216
|
-
return { providerKey, routeUsed: routeName, pool: poolTargets, poolId: tierId };
|
|
217
|
-
}
|
|
218
|
-
if (failureHint) {
|
|
219
|
-
attempted.push(failureHint);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
const requestedRoute = normalizeRouteAlias(classification.routeName || DEFAULT_ROUTE);
|
|
224
|
-
throw new VirtualRouterError(`All providers unavailable for route ${requestedRoute}`, VirtualRouterErrorCode.PROVIDER_NOT_AVAILABLE, { routeName: requestedRoute, attempted });
|
|
225
|
-
}
|
|
1
|
+
export { selectProviderImpl, selectDirectProviderModel, selectFromStickyPool } from './engine/routing-pools/index.js';
|
|
@@ -70,26 +70,9 @@ export declare class VirtualRouterEngine {
|
|
|
70
70
|
private providerHealthConfig;
|
|
71
71
|
private resolveStickyKey;
|
|
72
72
|
private resolveSessionScope;
|
|
73
|
-
private resolveAntigravityAliasReuseCooldownMs;
|
|
74
|
-
private resolveAntigravityLeaseScope;
|
|
75
|
-
private buildScopedSessionKey;
|
|
76
|
-
private buildAntigravityLeaseRuntimeKey;
|
|
77
|
-
private extractRuntimeKey;
|
|
78
|
-
private recordAntigravitySessionLease;
|
|
79
|
-
private resolveAntigravityAliasLeasePersistPath;
|
|
80
|
-
private hydrateAntigravityAliasLeaseStoreIfNeeded;
|
|
81
|
-
private scheduleAntigravityAliasLeaseStoreFlush;
|
|
82
|
-
private flushAntigravityAliasLeaseStoreSync;
|
|
83
|
-
private resolveStopMessageScope;
|
|
84
|
-
private getRoutingInstructionState;
|
|
85
|
-
private buildMetadataInstructions;
|
|
86
|
-
private parseMetadataDisableDescriptor;
|
|
87
|
-
private parseMetadataForceProviderKey;
|
|
88
|
-
private resolveRoutingMode;
|
|
89
73
|
private resolveInstructionTarget;
|
|
90
74
|
private filterCandidatesByRoutingState;
|
|
91
75
|
private selectFromCandidates;
|
|
92
|
-
private extractProviderId;
|
|
93
76
|
/**
|
|
94
77
|
* 在已有候选路由集合上,筛选出真正挂载了 sticky 池内 providerKey 的路由,
|
|
95
78
|
* 并按 ROUTE_PRIORITY 进行排序;同时显式排除 tools 路由,保证一旦进入
|
|
@@ -104,13 +87,11 @@ export declare class VirtualRouterEngine {
|
|
|
104
87
|
* - 仍然尊重 allowed/disabledProviders、disabledKeys、disabledModels 以及上下文长度。
|
|
105
88
|
*/
|
|
106
89
|
private selectFromStickyPool;
|
|
107
|
-
private extractKeyAlias;
|
|
108
|
-
private normalizeAliasDescriptor;
|
|
109
|
-
private extractKeyIndex;
|
|
110
|
-
private getProviderModelId;
|
|
111
90
|
private extractExcludedProviderKeySet;
|
|
112
91
|
private buildRouteCandidates;
|
|
113
92
|
private reorderForInlineVision;
|
|
93
|
+
private reorderForPreferredModel;
|
|
94
|
+
private routeSupportsModel;
|
|
114
95
|
private routeSupportsInlineVision;
|
|
115
96
|
private sortByPriority;
|
|
116
97
|
private routeWeight;
|
|
@@ -119,8 +100,6 @@ export declare class VirtualRouterEngine {
|
|
|
119
100
|
private hasPrimaryPool;
|
|
120
101
|
private sortRoutePools;
|
|
121
102
|
private flattenPoolTargets;
|
|
122
|
-
private isRoutingStateEmpty;
|
|
123
|
-
private persistRoutingInstructionState;
|
|
124
103
|
private markProviderCooldown;
|
|
125
104
|
private clearProviderCooldown;
|
|
126
105
|
private isProviderCoolingDown;
|