@jsonstudio/llms 0.6.1449 → 0.6.1643
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/codecs/gemini-openai-codec.js +6 -1
- package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.d.ts +4 -6
- package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.js +179 -41
- package/dist/conversion/compat/actions/antigravity-thought-signature-cache.js +73 -14
- package/dist/conversion/compat/actions/antigravity-thought-signature-prepare.js +165 -10
- package/dist/conversion/compat/actions/gemini-cli-request.js +72 -13
- package/dist/conversion/compat/antigravity-session-signature.d.ts +68 -1
- package/dist/conversion/compat/antigravity-session-signature.js +833 -21
- package/dist/conversion/compat/profiles/anthropic-claude-code.json +17 -0
- package/dist/conversion/compat/profiles/chat-gemini-cli.json +1 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +33 -8
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +17 -1
- package/dist/conversion/hub/pipeline/compat/compat-profile-store.js +12 -3
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +1 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +24 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +20 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +26 -1
- package/dist/conversion/hub/process/chat-process.js +300 -67
- package/dist/conversion/hub/response/provider-response.js +4 -3
- package/dist/conversion/shared/gemini-tool-utils.js +134 -9
- package/dist/conversion/shared/text-markup-normalizer.js +90 -1
- package/dist/conversion/shared/thought-signature-validator.d.ts +1 -1
- package/dist/conversion/shared/thought-signature-validator.js +2 -1
- package/dist/quota/apikey-reset.d.ts +17 -0
- package/dist/quota/apikey-reset.js +43 -0
- package/dist/quota/index.d.ts +2 -0
- package/dist/quota/index.js +1 -0
- package/dist/quota/quota-manager.d.ts +44 -0
- package/dist/quota/quota-manager.js +491 -0
- package/dist/quota/quota-state.d.ts +6 -0
- package/dist/quota/quota-state.js +167 -0
- package/dist/quota/types.d.ts +61 -0
- package/dist/quota/types.js +1 -0
- package/dist/router/virtual-router/bootstrap.js +103 -6
- package/dist/router/virtual-router/engine-health.js +104 -0
- package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +18 -0
- package/dist/router/virtual-router/engine-selection/tier-priority.d.ts +1 -2
- package/dist/router/virtual-router/engine-selection/tier-priority.js +2 -2
- package/dist/router/virtual-router/engine-selection/tier-selection-select.js +34 -10
- package/dist/router/virtual-router/engine-selection/tier-selection.js +250 -6
- package/dist/router/virtual-router/engine-selection.js +2 -2
- package/dist/router/virtual-router/engine.d.ts +16 -1
- package/dist/router/virtual-router/engine.js +320 -42
- package/dist/router/virtual-router/features.js +20 -2
- package/dist/router/virtual-router/success-center.d.ts +10 -0
- package/dist/router/virtual-router/success-center.js +32 -0
- package/dist/router/virtual-router/types.d.ts +48 -0
- package/dist/servertool/clock/config.d.ts +2 -0
- package/dist/servertool/clock/config.js +10 -2
- package/dist/servertool/clock/daemon.js +3 -0
- package/dist/servertool/clock/ntp.d.ts +18 -0
- package/dist/servertool/clock/ntp.js +318 -0
- package/dist/servertool/clock/paths.d.ts +1 -0
- package/dist/servertool/clock/paths.js +3 -0
- package/dist/servertool/clock/state.d.ts +2 -0
- package/dist/servertool/clock/state.js +15 -2
- package/dist/servertool/clock/tasks.d.ts +1 -0
- package/dist/servertool/clock/tasks.js +24 -1
- package/dist/servertool/clock/types.d.ts +21 -0
- package/dist/servertool/engine.js +105 -1
- package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.d.ts +1 -0
- package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.js +201 -0
- package/dist/servertool/handlers/clock-auto.js +39 -4
- package/dist/servertool/handlers/clock.js +145 -16
- package/dist/servertool/handlers/followup-request-builder.js +84 -0
- package/dist/servertool/handlers/stop-message-auto.js +1 -1
- package/dist/servertool/server-side-tools.d.ts +1 -0
- package/dist/servertool/server-side-tools.js +1 -0
- package/dist/servertool/types.d.ts +2 -0
- package/dist/tools/apply-patch/execution-capturer.js +24 -3
- package/package.json +3 -2
|
@@ -4,6 +4,34 @@ import { resolveHealthWeightedConfig } from '../health-weighted.js';
|
|
|
4
4
|
import { pinCandidatesByAliasQueue, resolveAliasSelectionStrategy } from './alias-selection.js';
|
|
5
5
|
import { extractKeyAlias, extractKeyIndex, extractProviderId, getProviderModelId } from './key-parsing.js';
|
|
6
6
|
import { selectProviderKeyFromCandidatePool } from './tier-selection-select.js';
|
|
7
|
+
import { lookupAntigravityPinnedAliasForSessionId, unpinAntigravitySessionAliasForSessionId } from '../../../conversion/compat/antigravity-session-signature.js';
|
|
8
|
+
const DEFAULT_ANTIGRAVITY_ALIAS_SESSION_COOLDOWN_MS = 5 * 60_000;
|
|
9
|
+
function isAntigravityGeminiModelKey(providerKey, deps) {
|
|
10
|
+
if ((extractProviderId(providerKey) ?? '') !== 'antigravity') {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
const modelId = getProviderModelId(providerKey, deps.providerRegistry) ?? '';
|
|
14
|
+
return modelId.trim().toLowerCase().startsWith('gemini-');
|
|
15
|
+
}
|
|
16
|
+
function extractAntigravityRuntimeBase(providerKey) {
|
|
17
|
+
const value = typeof providerKey === 'string' ? providerKey.trim() : '';
|
|
18
|
+
if (!value)
|
|
19
|
+
return null;
|
|
20
|
+
const firstDot = value.indexOf('.');
|
|
21
|
+
if (firstDot <= 0 || firstDot === value.length - 1)
|
|
22
|
+
return null;
|
|
23
|
+
const secondDot = value.indexOf('.', firstDot + 1);
|
|
24
|
+
if (secondDot <= firstDot + 1)
|
|
25
|
+
return null;
|
|
26
|
+
const providerId = value.slice(0, firstDot);
|
|
27
|
+
const alias = value.slice(firstDot + 1, secondDot);
|
|
28
|
+
if (!providerId || !alias)
|
|
29
|
+
return null;
|
|
30
|
+
return `${providerId}.${alias}`;
|
|
31
|
+
}
|
|
32
|
+
function buildAntigravityLeaseRuntimeKey(runtimeBase) {
|
|
33
|
+
return `${runtimeBase}::gemini`;
|
|
34
|
+
}
|
|
7
35
|
function shouldAvoidAllAntigravityOnRetry(metadata) {
|
|
8
36
|
if (!metadata || typeof metadata !== 'object') {
|
|
9
37
|
return false;
|
|
@@ -15,6 +43,27 @@ function shouldAvoidAllAntigravityOnRetry(metadata) {
|
|
|
15
43
|
const rt = rtRaw;
|
|
16
44
|
return rt.antigravityAvoidAllOnRetry === true;
|
|
17
45
|
}
|
|
46
|
+
function isAntigravityGeminiSessionBindingDisabled(metadata) {
|
|
47
|
+
if (!metadata || typeof metadata !== 'object') {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const rtRaw = metadata.__rt;
|
|
51
|
+
if (!rtRaw || typeof rtRaw !== 'object' || Array.isArray(rtRaw)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const rt = rtRaw;
|
|
55
|
+
if (rt.disableAntigravitySessionBinding === true) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
const mode = rt.antigravitySessionBinding;
|
|
59
|
+
if (mode === false) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
if (typeof mode === 'string' && ['0', 'false', 'off', 'disabled', 'none'].includes(mode.trim().toLowerCase())) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
18
67
|
function shouldAvoidAntigravityAfterRepeatedError(metadata) {
|
|
19
68
|
if (!metadata || typeof metadata !== 'object') {
|
|
20
69
|
return false;
|
|
@@ -46,9 +95,173 @@ function extractNonAntigravityTargets(targets) {
|
|
|
46
95
|
}
|
|
47
96
|
return targets.filter((key) => (extractProviderId(key) ?? '') !== 'antigravity');
|
|
48
97
|
}
|
|
98
|
+
function resolveSessionScopeKey(metadata) {
|
|
99
|
+
if (!metadata || typeof metadata !== 'object') {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const record = metadata;
|
|
103
|
+
const sessionId = typeof record.sessionId === 'string' ? record.sessionId.trim() : '';
|
|
104
|
+
if (sessionId) {
|
|
105
|
+
return `session:${sessionId}`;
|
|
106
|
+
}
|
|
107
|
+
const conversationId = typeof record.conversationId === 'string' ? record.conversationId.trim() : '';
|
|
108
|
+
if (conversationId) {
|
|
109
|
+
return `conversation:${conversationId}`;
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
function buildScopedSessionKey(sessionKey) {
|
|
114
|
+
// Policy: antigravity alias/session binding applies only to Gemini models.
|
|
115
|
+
return `${sessionKey}::gemini`;
|
|
116
|
+
}
|
|
117
|
+
function extractLeaseRuntimeKey(providerKey, deps) {
|
|
118
|
+
const base = extractAntigravityRuntimeBase(providerKey);
|
|
119
|
+
if (!base)
|
|
120
|
+
return null;
|
|
121
|
+
if ((extractProviderId(providerKey) ?? '') !== 'antigravity')
|
|
122
|
+
return base;
|
|
123
|
+
if (!isAntigravityGeminiModelKey(providerKey, deps)) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
return buildAntigravityLeaseRuntimeKey(base);
|
|
127
|
+
}
|
|
128
|
+
function applyAntigravityAliasSessionLeases(targets, deps, metadata) {
|
|
129
|
+
if (!Array.isArray(targets) || targets.length === 0) {
|
|
130
|
+
return { targets, blocked: 0, preferredPinned: false, pinnedStrict: false };
|
|
131
|
+
}
|
|
132
|
+
if (isAntigravityGeminiSessionBindingDisabled(metadata)) {
|
|
133
|
+
return { targets, blocked: 0, preferredPinned: false, pinnedStrict: false };
|
|
134
|
+
}
|
|
135
|
+
const leaseStore = deps.antigravityAliasLeaseStore;
|
|
136
|
+
const sessionAliasStore = deps.antigravitySessionAliasStore;
|
|
137
|
+
if (!leaseStore || !sessionAliasStore) {
|
|
138
|
+
return { targets, blocked: 0, preferredPinned: false, pinnedStrict: false };
|
|
139
|
+
}
|
|
140
|
+
const sessionKey = resolveSessionScopeKey(metadata);
|
|
141
|
+
if (!sessionKey) {
|
|
142
|
+
return { targets, blocked: 0, preferredPinned: false, pinnedStrict: false };
|
|
143
|
+
}
|
|
144
|
+
const cooldownMs = typeof deps.antigravityAliasReuseCooldownMs === 'number' && Number.isFinite(deps.antigravityAliasReuseCooldownMs)
|
|
145
|
+
? Math.max(0, Math.floor(deps.antigravityAliasReuseCooldownMs))
|
|
146
|
+
: DEFAULT_ANTIGRAVITY_ALIAS_SESSION_COOLDOWN_MS;
|
|
147
|
+
const now = Date.now();
|
|
148
|
+
const bindingModeRaw = deps.loadBalancer.getPolicy().aliasSelection
|
|
149
|
+
?.antigravitySessionBinding;
|
|
150
|
+
const strictRequested = typeof bindingModeRaw === 'string' && bindingModeRaw.trim().toLowerCase() === 'strict';
|
|
151
|
+
const agSessionId = metadata && typeof metadata === 'object' && typeof metadata.antigravitySessionId === 'string'
|
|
152
|
+
? String(metadata.antigravitySessionId).trim()
|
|
153
|
+
: '';
|
|
154
|
+
const hasAntigravityGeminiTargets = targets.some((key) => isAntigravityGeminiModelKey(key, deps));
|
|
155
|
+
let pinnedRuntimeKey = strictRequested && agSessionId && hasAntigravityGeminiTargets
|
|
156
|
+
? lookupAntigravityPinnedAliasForSessionId(agSessionId, { hydrate: true })
|
|
157
|
+
: undefined;
|
|
158
|
+
const pinnedLeaseKey = pinnedRuntimeKey ? buildAntigravityLeaseRuntimeKey(pinnedRuntimeKey) : undefined;
|
|
159
|
+
// If the pinned alias is completely out of pool (quota exhausted), release the pin so we can rotate.
|
|
160
|
+
if (pinnedRuntimeKey && deps.quotaView && agSessionId) {
|
|
161
|
+
const pinnedKeys = targets.filter((key) => isAntigravityGeminiModelKey(key, deps) && extractLeaseRuntimeKey(key, deps) === pinnedLeaseKey);
|
|
162
|
+
if (pinnedKeys.length > 0) {
|
|
163
|
+
const allOutOfPool = pinnedKeys.every((key) => deps.quotaView?.(key)?.inPool === false);
|
|
164
|
+
if (allOutOfPool) {
|
|
165
|
+
const releasedRuntimeKey = pinnedRuntimeKey;
|
|
166
|
+
unpinAntigravitySessionAliasForSessionId(agSessionId);
|
|
167
|
+
pinnedRuntimeKey = undefined;
|
|
168
|
+
sessionAliasStore.delete(buildScopedSessionKey(sessionKey));
|
|
169
|
+
try {
|
|
170
|
+
const raw = String(process.env.ROUTECODEX_STAGE_LOG || process.env.RCC_STAGE_LOG || '').trim().toLowerCase();
|
|
171
|
+
const enabled = raw !== '' && raw !== '0' && raw !== 'false' && raw !== 'no';
|
|
172
|
+
if (enabled) {
|
|
173
|
+
console.log('[virtual-router][antigravity-session-binding] unpin', JSON.stringify({ agSessionId, runtimeKey: releasedRuntimeKey }));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// ignore
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const strictBinding = strictRequested && Boolean(pinnedLeaseKey);
|
|
183
|
+
const geminiSessionKey = buildScopedSessionKey(sessionKey);
|
|
184
|
+
let preferredGeminiRuntimeKey = pinnedLeaseKey || sessionAliasStore.get(geminiSessionKey);
|
|
185
|
+
if (preferredGeminiRuntimeKey && !pinnedLeaseKey) {
|
|
186
|
+
const lease = leaseStore.get(preferredGeminiRuntimeKey);
|
|
187
|
+
if (lease && lease.sessionKey !== geminiSessionKey && now - lease.lastSeenAt < cooldownMs) {
|
|
188
|
+
preferredGeminiRuntimeKey = undefined;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// If a previously bound alias is completely out of pool (quota exhausted / blacklisted),
|
|
192
|
+
// release the binding so the session can rebind to a different alias on the next successful call.
|
|
193
|
+
if (deps.quotaView && !pinnedLeaseKey && preferredGeminiRuntimeKey) {
|
|
194
|
+
const pinnedKeys = targets.filter((key) => isAntigravityGeminiModelKey(key, deps) && extractLeaseRuntimeKey(key, deps) === preferredGeminiRuntimeKey);
|
|
195
|
+
if (pinnedKeys.length > 0) {
|
|
196
|
+
const allOutOfPool = pinnedKeys.every((key) => deps.quotaView?.(key)?.inPool === false);
|
|
197
|
+
if (allOutOfPool) {
|
|
198
|
+
const releasedRuntimeKey = preferredGeminiRuntimeKey;
|
|
199
|
+
sessionAliasStore.delete(geminiSessionKey);
|
|
200
|
+
preferredGeminiRuntimeKey = undefined;
|
|
201
|
+
try {
|
|
202
|
+
const raw = String(process.env.ROUTECODEX_STAGE_LOG || process.env.RCC_STAGE_LOG || '').trim().toLowerCase();
|
|
203
|
+
const enabled = raw !== '' && raw !== '0' && raw !== 'false' && raw !== 'no';
|
|
204
|
+
if (enabled) {
|
|
205
|
+
console.log('[virtual-router][antigravity-session-binding] release', JSON.stringify({ sessionKey: geminiSessionKey, runtimeKey: releasedRuntimeKey }));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// ignore
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const pinnedGemini = preferredGeminiRuntimeKey
|
|
215
|
+
? targets.filter((key) => isAntigravityGeminiModelKey(key, deps) && extractLeaseRuntimeKey(key, deps) === preferredGeminiRuntimeKey)
|
|
216
|
+
: [];
|
|
217
|
+
const preferredPinned = pinnedGemini.length > 0;
|
|
218
|
+
const pinnedSet = preferredPinned ? new Set([...pinnedGemini]) : null;
|
|
219
|
+
const candidates = preferredPinned
|
|
220
|
+
? [...pinnedGemini, ...targets.filter((key) => !pinnedSet.has(key))]
|
|
221
|
+
: targets;
|
|
222
|
+
const pinnedStrict = strictBinding && Boolean(preferredGeminiRuntimeKey);
|
|
223
|
+
let blocked = 0;
|
|
224
|
+
const filtered = candidates.filter((key) => {
|
|
225
|
+
const providerId = extractProviderId(key);
|
|
226
|
+
if (providerId !== 'antigravity') {
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
// Policy: antigravity alias/session binding applies only to Gemini models.
|
|
230
|
+
if (!isAntigravityGeminiModelKey(key, deps)) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
const scopedSessionKey = geminiSessionKey;
|
|
234
|
+
const runtimeKey = extractLeaseRuntimeKey(key, deps);
|
|
235
|
+
if (!runtimeKey) {
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
if (pinnedStrict) {
|
|
239
|
+
if (!isAntigravityGeminiModelKey(key, deps)) {
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
if (preferredGeminiRuntimeKey && runtimeKey !== preferredGeminiRuntimeKey) {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const lease = leaseStore.get(runtimeKey);
|
|
247
|
+
if (!lease) {
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
if (lease.sessionKey === scopedSessionKey) {
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
if (now - lease.lastSeenAt >= cooldownMs) {
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
blocked += 1;
|
|
257
|
+
return false;
|
|
258
|
+
});
|
|
259
|
+
return { targets: filtered, blocked, preferredPinned, pinnedStrict };
|
|
260
|
+
}
|
|
49
261
|
export function trySelectFromTier(routeName, tier, stickyKey, estimatedTokens, features, deps, options) {
|
|
50
262
|
const { disabledProviders, disabledKeysMap, allowedProviders, disabledModels, requiredProviderKeys } = options;
|
|
51
263
|
let targets = Array.isArray(tier.targets) ? tier.targets : [];
|
|
264
|
+
let preLeaseTargets = null;
|
|
52
265
|
const excludedRaw = Array.isArray(features.metadata?.excludedProviderKeys)
|
|
53
266
|
? features.metadata.excludedProviderKeys
|
|
54
267
|
.filter((val) => typeof val === 'string')
|
|
@@ -70,10 +283,14 @@ export function trySelectFromTier(routeName, tier, stickyKey, estimatedTokens, f
|
|
|
70
283
|
}
|
|
71
284
|
const singleCandidateFallback = targets.length === 1 ? targets[0] : undefined;
|
|
72
285
|
if (targets.length > 0) {
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
286
|
+
// When quotaView is present, cooldown is expressed via quotaView.{cooldownUntil,blacklistUntil,inPool}.
|
|
287
|
+
// Do not apply router-local cooldown filters in that mode.
|
|
288
|
+
if (!deps.quotaView) {
|
|
289
|
+
// Always respect cooldown signals. If a route/tier is depleted due to cooldown,
|
|
290
|
+
// routing is expected to fall back to other tiers/routes (e.g. longcontext → default),
|
|
291
|
+
// rather than repeatedly selecting the cooled-down provider.
|
|
292
|
+
targets = targets.filter((key) => !deps.isProviderCoolingDown(key));
|
|
293
|
+
}
|
|
77
294
|
}
|
|
78
295
|
if (allowedProviders && allowedProviders.size > 0) {
|
|
79
296
|
targets = targets.filter((key) => {
|
|
@@ -126,6 +343,23 @@ export function trySelectFromTier(routeName, tier, stickyKey, estimatedTokens, f
|
|
|
126
343
|
if (requiredProviderKeys && requiredProviderKeys.size > 0) {
|
|
127
344
|
targets = targets.filter((key) => requiredProviderKeys.has(key));
|
|
128
345
|
}
|
|
346
|
+
// Antigravity session isolation:
|
|
347
|
+
// - One alias (auth key) must not be shared across different sessions within the cooldown window,
|
|
348
|
+
// otherwise upstream may respond with 429 due to cross-session contamination.
|
|
349
|
+
// - If the current session already has a leased alias, pin it when possible.
|
|
350
|
+
preLeaseTargets = targets;
|
|
351
|
+
const leaseResult = applyAntigravityAliasSessionLeases(targets, deps, features.metadata);
|
|
352
|
+
targets = leaseResult.targets;
|
|
353
|
+
// Default route must not fail purely due to Antigravity alias leasing.
|
|
354
|
+
// If *all* candidates are blocked by lease, fall back to the pre-lease pool and let upstream decide.
|
|
355
|
+
if (!targets.length &&
|
|
356
|
+
routeName === DEFAULT_ROUTE &&
|
|
357
|
+
preLeaseTargets &&
|
|
358
|
+
preLeaseTargets.length > 0 &&
|
|
359
|
+
leaseResult.blocked > 0 &&
|
|
360
|
+
!leaseResult.pinnedStrict) {
|
|
361
|
+
targets = preLeaseTargets;
|
|
362
|
+
}
|
|
129
363
|
const serverToolRequired = features.metadata?.serverToolRequired === true;
|
|
130
364
|
if (serverToolRequired) {
|
|
131
365
|
const filtered = [];
|
|
@@ -167,10 +401,20 @@ export function trySelectFromTier(routeName, tier, stickyKey, estimatedTokens, f
|
|
|
167
401
|
}
|
|
168
402
|
}
|
|
169
403
|
if (!targets.length) {
|
|
170
|
-
|
|
404
|
+
const leaseHint = leaseResult.blocked > 0
|
|
405
|
+
? `${routeName}:${tier.id}:antigravity_alias_session_busy(${leaseResult.blocked})`
|
|
406
|
+
: `${routeName}:${tier.id}:empty`;
|
|
407
|
+
return { providerKey: null, poolTargets: [], tierId: tier.id, failureHint: leaseHint };
|
|
171
408
|
}
|
|
172
409
|
const contextResult = deps.contextAdvisor.classify(targets, estimatedTokens, (key) => deps.providerRegistry.get(key));
|
|
173
|
-
|
|
410
|
+
let prioritizedPools = buildContextCandidatePools(contextResult);
|
|
411
|
+
// ContextAdvisor overflow (ratio >= 1) is not always a hard stop: token estimation is approximate.
|
|
412
|
+
// For the default route, treat overflow as a last-resort candidate pool when hardLimit=false,
|
|
413
|
+
// to avoid route exhaustion when no other providers are available.
|
|
414
|
+
const hardLimit = deps.contextAdvisor.getConfig().hardLimit;
|
|
415
|
+
if (!hardLimit && routeName === DEFAULT_ROUTE && contextResult.overflow.length > 0) {
|
|
416
|
+
prioritizedPools = [...prioritizedPools, contextResult.overflow];
|
|
417
|
+
}
|
|
174
418
|
const avoidAntigravityOnRetry = isRecoveryAttempt && shouldAvoidAntigravityAfterRepeatedError(features.metadata);
|
|
175
419
|
const nonAntigravityTargets = avoidAntigravityOnRetry ? extractNonAntigravityTargets(targets) : [];
|
|
176
420
|
const poolsToTry = avoidAntigravityOnRetry && nonAntigravityTargets.length > 0
|
|
@@ -49,7 +49,7 @@ export function selectProviderImpl(requestedRoute, metadata, classification, fea
|
|
|
49
49
|
stickyResolution = resolveInstructionTarget(state.stickyTarget, deps.providerRegistry);
|
|
50
50
|
if (stickyResolution && stickyResolution.mode === 'exact') {
|
|
51
51
|
const stickyKey = stickyResolution.keys[0];
|
|
52
|
-
if (deps.healthManager.isAvailable(stickyKey) &&
|
|
52
|
+
if ((deps.quotaView ? true : deps.healthManager.isAvailable(stickyKey)) &&
|
|
53
53
|
!excludedProviderKeys.has(stickyKey) &&
|
|
54
54
|
!deps.isProviderCoolingDown(stickyKey) &&
|
|
55
55
|
isAllowedByQuota(stickyKey)) {
|
|
@@ -62,7 +62,7 @@ export function selectProviderImpl(requestedRoute, metadata, classification, fea
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
if (stickyResolution && stickyResolution.mode === 'filter' && stickyResolution.keys.length > 0) {
|
|
65
|
-
const liveKeys = stickyResolution.keys.filter((key) => deps.healthManager.isAvailable(key) &&
|
|
65
|
+
const liveKeys = stickyResolution.keys.filter((key) => (deps.quotaView ? true : deps.healthManager.isAvailable(key)) &&
|
|
66
66
|
!excludedProviderKeys.has(key) &&
|
|
67
67
|
!deps.isProviderCoolingDown(key) &&
|
|
68
68
|
isAllowedByQuota(key));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type RoutingDecision, type RoutingDiagnostics, type StopMessageStateSnapshot, type RouterMetadataInput, type VirtualRouterConfig, type TargetMetadata, type ProviderFailureEvent, type ProviderErrorEvent, type VirtualRouterHealthStore } from './types.js';
|
|
1
|
+
import { type RoutingDecision, type RoutingDiagnostics, type StopMessageStateSnapshot, type RouterMetadataInput, type VirtualRouterConfig, type TargetMetadata, type ProviderFailureEvent, type ProviderErrorEvent, type ProviderSuccessEvent, type VirtualRouterHealthStore } from './types.js';
|
|
2
2
|
import type { ProcessedRequest, StandardizedRequest } from '../../conversion/hub/types/standardized.js';
|
|
3
3
|
import { type RoutingInstructionState } from './routing-instructions.js';
|
|
4
4
|
import type { ProviderQuotaView } from './types.js';
|
|
@@ -18,6 +18,10 @@ export declare class VirtualRouterEngine {
|
|
|
18
18
|
private contextRouting;
|
|
19
19
|
private routeStats;
|
|
20
20
|
private readonly aliasQueueStore;
|
|
21
|
+
private readonly antigravityAliasLeaseStore;
|
|
22
|
+
private readonly antigravitySessionAliasStore;
|
|
23
|
+
private antigravityAliasReuseCooldownMs;
|
|
24
|
+
private antigravityLeasePersistence;
|
|
21
25
|
private readonly debug;
|
|
22
26
|
private healthConfig;
|
|
23
27
|
private readonly statsCenter;
|
|
@@ -46,6 +50,7 @@ export declare class VirtualRouterEngine {
|
|
|
46
50
|
getStopMessageState(metadata: RouterMetadataInput): StopMessageStateSnapshot | null;
|
|
47
51
|
handleProviderFailure(event: ProviderFailureEvent): void;
|
|
48
52
|
handleProviderError(event: ProviderErrorEvent): void;
|
|
53
|
+
handleProviderSuccess(event: ProviderSuccessEvent): void;
|
|
49
54
|
getStatus(): {
|
|
50
55
|
routes: Record<string, {
|
|
51
56
|
providers: string[];
|
|
@@ -65,6 +70,16 @@ export declare class VirtualRouterEngine {
|
|
|
65
70
|
private providerHealthConfig;
|
|
66
71
|
private resolveStickyKey;
|
|
67
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;
|
|
68
83
|
private resolveStopMessageScope;
|
|
69
84
|
private getRoutingInstructionState;
|
|
70
85
|
private buildMetadataInstructions;
|