@jsonstudio/llms 0.6.3409 → 0.6.3541

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 (85) hide show
  1. package/dist/conversion/codecs/anthropic-openai-codec.d.ts +12 -3
  2. package/dist/conversion/codecs/anthropic-openai-codec.js +32 -92
  3. package/dist/conversion/codecs/gemini-openai-codec.d.ts +6 -5
  4. package/dist/conversion/codecs/gemini-openai-codec.js +48 -685
  5. package/dist/conversion/codecs/openai-openai-codec.d.ts +1 -1
  6. package/dist/conversion/codecs/openai-openai-codec.js +34 -100
  7. package/dist/conversion/codecs/responses-openai-codec.d.ts +1 -1
  8. package/dist/conversion/codecs/responses-openai-codec.js +47 -159
  9. package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.d.ts +2 -6
  10. package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.js +29 -245
  11. package/dist/conversion/compat/actions/anthropic-claude-code-user-id.d.ts +3 -0
  12. package/dist/conversion/compat/actions/anthropic-claude-code-user-id.js +30 -0
  13. package/dist/conversion/compat/actions/antigravity-thought-signature-prepare.js +21 -232
  14. package/dist/conversion/compat/actions/deepseek-web-request.js +41 -276
  15. package/dist/conversion/compat/actions/deepseek-web-response.js +117 -855
  16. package/dist/conversion/compat/actions/gemini-cli-request.d.ts +1 -1
  17. package/dist/conversion/compat/actions/gemini-cli-request.js +20 -613
  18. package/dist/conversion/compat/actions/gemini-web-search.d.ts +1 -15
  19. package/dist/conversion/compat/actions/gemini-web-search.js +22 -69
  20. package/dist/conversion/compat/actions/glm-tool-extraction.d.ts +3 -2
  21. package/dist/conversion/compat/actions/glm-tool-extraction.js +28 -257
  22. package/dist/conversion/compat/actions/iflow-tool-text-fallback.d.ts +0 -8
  23. package/dist/conversion/compat/actions/iflow-tool-text-fallback.js +24 -206
  24. package/dist/conversion/compat/actions/qwen-transform.d.ts +3 -2
  25. package/dist/conversion/compat/actions/qwen-transform.js +30 -271
  26. package/dist/conversion/compat/actions/tool-text-request-guidance.js +3 -173
  27. package/dist/conversion/compat/actions/universal-shape-filter.d.ts +6 -23
  28. package/dist/conversion/compat/actions/universal-shape-filter.js +4 -383
  29. package/dist/conversion/hub/pipeline/compat/native-adapter-context.js +1 -0
  30. package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.d.ts +1 -2
  31. package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.js +50 -104
  32. package/dist/conversion/pipeline/codecs/v2/openai-openai-pipeline.js +12 -10
  33. package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.d.ts +0 -2
  34. package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.js +46 -67
  35. package/dist/conversion/pipeline/codecs/v2/shared/openai-chat-helpers.js +15 -40
  36. package/dist/conversion/responses/responses-openai-bridge/response-payload.js +47 -348
  37. package/dist/conversion/responses/responses-openai-bridge.js +129 -611
  38. package/dist/conversion/shared/chat-output-normalizer.js +6 -0
  39. package/dist/conversion/shared/chat-request-filters.js +1 -1
  40. package/dist/conversion/shared/output-content-normalizer.js +10 -0
  41. package/dist/conversion/shared/responses-conversation-store.js +22 -135
  42. package/dist/conversion/shared/responses-output-builder.d.ts +0 -2
  43. package/dist/conversion/shared/responses-output-builder.js +28 -318
  44. package/dist/conversion/shared/responses-response-utils.js +35 -86
  45. package/dist/conversion/shared/streaming-text-extractor.d.ts +1 -2
  46. package/dist/conversion/shared/streaming-text-extractor.js +13 -14
  47. package/dist/native/router_hotpath_napi.node +0 -0
  48. package/dist/quota/quota-state.js +29 -7
  49. package/dist/quota/types.d.ts +1 -0
  50. package/dist/router/virtual-router/bootstrap/routing-config.js +11 -3
  51. package/dist/router/virtual-router/engine-legacy.d.ts +3 -3
  52. package/dist/router/virtual-router/engine-legacy.js +15 -7
  53. package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.d.ts +16 -0
  54. package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.js +434 -46
  55. package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.d.ts +83 -0
  56. package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js +295 -0
  57. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-req-outbound-semantics.d.ts +1 -0
  58. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.d.ts +7 -0
  59. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js +8 -1
  60. package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +383 -298
  61. package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.d.ts +20 -0
  62. package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.js +201 -0
  63. package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.d.ts +1 -0
  64. package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.js +37 -0
  65. package/dist/router/virtual-router/engine.js +0 -38
  66. package/dist/router/virtual-router/features.js +44 -3
  67. package/dist/router/virtual-router/routing-instructions/parse.d.ts +0 -12
  68. package/dist/router/virtual-router/routing-instructions/parse.js +9 -389
  69. package/dist/router/virtual-router/stop-message-state-sync.d.ts +3 -6
  70. package/dist/router/virtual-router/stop-message-state-sync.js +50 -21
  71. package/dist/servertool/handlers/followup-request-builder.js +12 -2
  72. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +1 -0
  73. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +26 -0
  74. package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +12 -2
  75. package/package.json +1 -1
  76. package/dist/router/virtual-router/engine-legacy/route-finalize.d.ts +0 -9
  77. package/dist/router/virtual-router/engine-legacy/route-finalize.js +0 -84
  78. package/dist/router/virtual-router/engine-legacy/route-selection.d.ts +0 -17
  79. package/dist/router/virtual-router/engine-legacy/route-selection.js +0 -205
  80. package/dist/router/virtual-router/engine-legacy/route-state-allowlist.d.ts +0 -3
  81. package/dist/router/virtual-router/engine-legacy/route-state-allowlist.js +0 -36
  82. package/dist/router/virtual-router/engine-legacy/route-state.d.ts +0 -12
  83. package/dist/router/virtual-router/engine-legacy/route-state.js +0 -386
  84. package/dist/router/virtual-router/engine-legacy/routing.d.ts +0 -8
  85. package/dist/router/virtual-router/engine-legacy/routing.js +0 -8
@@ -1,8 +1,7 @@
1
- import { extractOutputSegments } from './output-content-normalizer.js';
2
1
  import { createBridgeActionState, runBridgeActionPipeline } from '../bridge-actions.js';
3
2
  import { resolveBridgePolicy, resolvePolicyActions } from '../bridge-policies.js';
4
3
  import { registerResponsesPayloadSnapshot, registerResponsesPassthrough } from './responses-reasoning-registry.js';
5
- import { collectToolCallsFromResponsesWithNative, normalizeFunctionCallIdWithNative, resolveFinishReasonWithNative, sanitizeReasoningTaggedTextWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
4
+ import { buildChatResponseFromResponsesWithNative, collectToolCallsFromResponsesWithNative, normalizeFunctionCallIdWithNative, resolveFinishReasonWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
6
5
  import { sanitizeResponsesFunctionNameWithNative } from '../../router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js';
7
6
  function selectCallId(entry) {
8
7
  const candidates = [
@@ -194,6 +193,9 @@ function cloneSnapshot(value) {
194
193
  export function buildChatResponseFromResponses(payload) {
195
194
  if (!payload || typeof payload !== 'object')
196
195
  return payload;
196
+ if (typeof buildChatResponseFromResponsesWithNative !== 'function') {
197
+ throw new Error('[responses-response-utils] native bindings unavailable');
198
+ }
197
199
  const response = unwrapResponsesResponse(payload);
198
200
  if (!response) {
199
201
  if (Array.isArray(payload.choices)) {
@@ -202,99 +204,46 @@ export function buildChatResponseFromResponses(payload) {
202
204
  }
203
205
  return payload;
204
206
  }
205
- const id = typeof response.id === 'string' ? response.id : `resp_${Date.now()}`;
206
- const model = response.model;
207
- const created = typeof response.created_at === 'number'
208
- ? response.created_at
209
- : (response.created ?? Math.floor(Date.now() / 1000));
210
- const usage = response.usage;
211
- const toolCalls = collectToolCallsFromResponses(response);
212
- const { textParts, reasoningParts } = extractOutputSegments(response);
213
- const rawReasoningSegments = collectRawReasoningSegments(response);
214
- const summaryReasoningSegments = collectReasoningSummarySegments(response);
215
- const encryptedReasoning = collectReasoningEncryptedContent(response);
216
- const outputTextRaw = typeof response.output_text === 'string' && response.output_text.trim().length
217
- ? response.output_text
218
- : undefined;
219
- const explicitOutput = typeof outputTextRaw === 'string'
220
- ? sanitizeReasoningTaggedTextWithNative(outputTextRaw)
207
+ const chat = buildChatResponseFromResponsesWithNative(response);
208
+ if (!chat || typeof chat !== 'object' || Array.isArray(chat)) {
209
+ return payload;
210
+ }
211
+ const choices = Array.isArray(chat.choices) ? chat.choices : [];
212
+ const primary = choices[0] && typeof choices[0] === 'object' ? choices[0] : undefined;
213
+ const message = primary && typeof primary.message === 'object'
214
+ ? primary.message
221
215
  : undefined;
222
- const messageContentText = explicitOutput || textParts.join('\n').trim();
223
- const messageContent = messageContentText || '';
224
- const message = {
225
- role: 'assistant',
226
- content: messageContent
227
- };
228
216
  try {
229
- const bridgePolicy = resolveBridgePolicy({ protocol: 'openai-responses', moduleType: 'openai-responses' });
230
- const policyActions = resolvePolicyActions(bridgePolicy, 'response_inbound');
231
- if (policyActions?.length) {
232
- const actionState = createBridgeActionState({
233
- messages: [message],
234
- rawResponse: response
235
- });
236
- runBridgeActionPipeline({
237
- stage: 'response_inbound',
238
- actions: policyActions,
239
- protocol: bridgePolicy?.protocol ?? 'openai-responses',
240
- moduleType: bridgePolicy?.moduleType ?? 'openai-responses',
241
- requestId: typeof response?.id === 'string' ? response.id : undefined,
242
- state: actionState
243
- });
217
+ if (message) {
218
+ const bridgePolicy = resolveBridgePolicy({ protocol: 'openai-responses', moduleType: 'openai-responses' });
219
+ const policyActions = resolvePolicyActions(bridgePolicy, 'response_inbound');
220
+ if (policyActions?.length) {
221
+ const actionState = createBridgeActionState({
222
+ messages: [message],
223
+ rawResponse: response
224
+ });
225
+ runBridgeActionPipeline({
226
+ stage: 'response_inbound',
227
+ actions: policyActions,
228
+ protocol: bridgePolicy?.protocol ?? 'openai-responses',
229
+ moduleType: bridgePolicy?.moduleType ?? 'openai-responses',
230
+ requestId: typeof response?.id === 'string' ? response.id : undefined,
231
+ state: actionState
232
+ });
233
+ }
244
234
  }
245
235
  }
246
236
  catch {
247
237
  // Ignore policy errors
248
238
  }
249
- if (toolCalls.length) {
250
- message.tool_calls = toolCalls;
251
- }
252
- const reasoningSegments = rawReasoningSegments.length
253
- ? rawReasoningSegments
254
- : (reasoningParts.length ? reasoningParts : summaryReasoningSegments);
255
- if (reasoningSegments.length) {
256
- message.reasoning_content = reasoningSegments.join('\n');
239
+ const id = typeof chat.id === 'string' ? chat.id : undefined;
240
+ const requestId = typeof chat.request_id === 'string'
241
+ ? chat.request_id
242
+ : (typeof response.request_id === 'string' ? response.request_id : undefined);
243
+ if (id) {
244
+ registerResponsesPayloadSnapshot(id, response);
257
245
  }
258
- const finishReason = resolveFinishReason(response, toolCalls);
259
- const chat = {
260
- id,
261
- object: 'chat.completion',
262
- created,
263
- model,
264
- choices: [
265
- {
266
- index: 0,
267
- finish_reason: finishReason,
268
- message
269
- }
270
- ]
271
- };
272
- const hasOutputTextField = Object.prototype.hasOwnProperty.call(response, 'output_text');
273
- const reasoningPayload = buildReasoningPayload({
274
- summarySegments: summaryReasoningSegments,
275
- contentSegments: rawReasoningSegments.length ? rawReasoningSegments : reasoningParts,
276
- encryptedContent: encryptedReasoning
277
- });
278
- if (reasoningPayload) {
279
- chat.__responses_reasoning = reasoningPayload;
280
- }
281
- chat.__responses_output_text_meta = {
282
- hasField: hasOutputTextField,
283
- value: typeof outputTextRaw === 'string'
284
- ? sanitizeReasoningTaggedTextWithNative(outputTextRaw)
285
- : undefined
286
- };
287
- if (usage !== undefined) {
288
- chat.usage = usage;
289
- }
290
- const requestId = typeof response.request_id === 'string'
291
- ? response.request_id
292
- : (typeof response.id === 'string' ? response.id : undefined);
293
246
  if (requestId) {
294
- chat.request_id = requestId;
295
- }
296
- registerResponsesPayloadSnapshot(id, response);
297
- if (requestId && requestId !== id) {
298
247
  registerResponsesPayloadSnapshot(requestId, response);
299
248
  }
300
249
  const snapshot = cloneSnapshot(response);
@@ -11,8 +11,7 @@ export interface StreamingToolExtractorOptions {
11
11
  }
12
12
  export declare class StreamingTextToolExtractor {
13
13
  private opts;
14
- private buffer;
15
- private idCounter;
14
+ private state;
16
15
  constructor(opts?: StreamingToolExtractorOptions);
17
16
  reset(): void;
18
17
  feedText(text: string): StreamingToolCall[];
@@ -1,38 +1,37 @@
1
1
  // Streaming textual tool intent extractor (对齐)
2
2
  // Detects <function=execute> blocks and structured apply_patch payloads
3
3
  // and converts them into OpenAI tool_calls incrementally.
4
- import { extractStreamingToolCallsWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
4
+ import { createStreamingToolExtractorStateWithNative, feedStreamingToolExtractorWithNative, resetStreamingToolExtractorStateWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
5
5
  function assertStreamingToolExtractorNativeAvailable() {
6
- if (typeof extractStreamingToolCallsWithNative !== 'function') {
6
+ if (typeof createStreamingToolExtractorStateWithNative !== 'function' ||
7
+ typeof resetStreamingToolExtractorStateWithNative !== 'function' ||
8
+ typeof feedStreamingToolExtractorWithNative !== 'function') {
7
9
  throw new Error('[streaming-text-extractor] native bindings unavailable');
8
10
  }
9
11
  }
10
12
  export class StreamingTextToolExtractor {
11
13
  opts;
12
- buffer = '';
13
- idCounter = 0;
14
+ state;
14
15
  constructor(opts = {}) {
15
16
  this.opts = opts;
17
+ assertStreamingToolExtractorNativeAvailable();
18
+ this.state = createStreamingToolExtractorStateWithNative(this.opts.idPrefix || 'call');
16
19
  }
17
20
  reset() {
18
- this.buffer = '';
19
- this.idCounter = 0;
21
+ assertStreamingToolExtractorNativeAvailable();
22
+ this.state = resetStreamingToolExtractorStateWithNative(this.state);
20
23
  }
21
24
  feedText(text) {
22
25
  if (typeof text !== 'string' || !text)
23
26
  return [];
24
27
  assertStreamingToolExtractorNativeAvailable();
25
- const idPrefix = this.opts.idPrefix || 'call';
26
- const output = extractStreamingToolCallsWithNative({
27
- buffer: this.buffer,
28
+ const output = feedStreamingToolExtractorWithNative({
29
+ state: this.state,
28
30
  text,
29
- idPrefix,
30
- idCounter: this.idCounter,
31
31
  nowMs: Date.now()
32
32
  });
33
- this.buffer = typeof output.buffer === 'string' ? output.buffer : this.buffer;
34
- this.idCounter = typeof output.idCounter === 'number' ? output.idCounter : this.idCounter;
35
- return Array.isArray(output.toolCalls) ? output.toolCalls : [];
33
+ this.state = output.state;
34
+ return output.toolCalls;
36
35
  }
37
36
  }
38
37
  export function createStreamingToolExtractor(opts) {
@@ -1,6 +1,7 @@
1
1
  const COOLDOWN_SCHEDULE_429_MS = [3_000, 10_000, 31_000, 61_000];
2
2
  const COOLDOWN_SCHEDULE_FATAL_MS = [3_000, 10_000, 31_000, 61_000];
3
3
  const COOLDOWN_SCHEDULE_DEFAULT_MS = [3_000, 10_000, 31_000, 61_000];
4
+ const COOLDOWN_SCHEDULE_TRANSIENT_KEEP_POOL_MS = [3_000, 5_000, 10_000, 31_000];
4
5
  const ERROR_CHAIN_WINDOW_MS = 10 * 60_000;
5
6
  const NETWORK_ERROR_CODES = [
6
7
  'ECONNRESET',
@@ -84,10 +85,26 @@ function computeCooldownMsBySeries(series, consecutive) {
84
85
  const idx = Math.min(consecutive - 1, schedule.length - 1);
85
86
  return schedule[idx] ?? null;
86
87
  }
88
+ function shouldKeepProviderInPoolDuringCooldown(series, consecutive) {
89
+ if (consecutive <= 0) {
90
+ return false;
91
+ }
92
+ return (series === 'ENET' || series === 'E5XX' || series === 'EOTHER') && consecutive <= 2;
93
+ }
94
+ function shouldAccumulateBySeries(series) {
95
+ return series === 'ENET' || series === 'E5XX' || series === 'EOTHER';
96
+ }
97
+ function computeTransientKeepPoolCooldownMs(series, consecutive) {
98
+ if (!shouldKeepProviderInPoolDuringCooldown(series, consecutive)) {
99
+ return null;
100
+ }
101
+ const idx = Math.min(consecutive - 1, COOLDOWN_SCHEDULE_TRANSIENT_KEEP_POOL_MS.length - 1);
102
+ return COOLDOWN_SCHEDULE_TRANSIENT_KEEP_POOL_MS[idx] ?? null;
103
+ }
87
104
  export function tickQuotaStateTime(state, nowMs) {
88
105
  let next = state;
89
106
  if (typeof next.cooldownUntil === 'number' && next.cooldownUntil <= nowMs) {
90
- next = { ...next, cooldownUntil: null };
107
+ next = { ...next, cooldownUntil: null, cooldownKeepsPool: undefined };
91
108
  }
92
109
  if (typeof next.blacklistUntil === 'number' && next.blacklistUntil <= nowMs) {
93
110
  next = { ...next, blacklistUntil: null };
@@ -107,14 +124,15 @@ export function tickQuotaStateTime(state, nowMs) {
107
124
  return next;
108
125
  }
109
126
  if (inCooldown) {
110
- if (next.inPool !== false || next.reason !== 'cooldown') {
111
- next = { ...next, inPool: false, reason: 'cooldown' };
127
+ const keepInPool = next.cooldownKeepsPool === true;
128
+ if (next.inPool !== keepInPool || next.reason !== 'cooldown') {
129
+ next = { ...next, inPool: keepInPool, reason: 'cooldown' };
112
130
  }
113
131
  return next;
114
132
  }
115
133
  // TTLs expired: only auto-reset "cooldown/blacklist" back to ok.
116
134
  if (next.reason === 'cooldown' || next.reason === 'blacklist') {
117
- next = { ...next, inPool: true, reason: 'ok' };
135
+ next = { ...next, inPool: true, reason: 'ok', cooldownKeepsPool: undefined };
118
136
  }
119
137
  return next;
120
138
  }
@@ -131,7 +149,9 @@ export function applyErrorEvent(state, event, nowMs = event.timestampMs ?? Date.
131
149
  const withinChainWindow = typeof lastAt === 'number' &&
132
150
  nowMs - lastAt >= 0 &&
133
151
  nowMs - lastAt <= ERROR_CHAIN_WINDOW_MS;
134
- const sameErrorKey = withinChainWindow && state.lastErrorCode === errorKey;
152
+ const sameErrorKey = withinChainWindow &&
153
+ (state.lastErrorCode === errorKey ||
154
+ (shouldAccumulateBySeries(series) && state.lastErrorSeries === series));
135
155
  const schedule = series === 'E429'
136
156
  ? COOLDOWN_SCHEDULE_429_MS
137
157
  : series === 'EFATAL'
@@ -139,7 +159,7 @@ export function applyErrorEvent(state, event, nowMs = event.timestampMs ?? Date.
139
159
  : COOLDOWN_SCHEDULE_DEFAULT_MS;
140
160
  const rawNextCount = sameErrorKey ? state.consecutiveErrorCount + 1 : 1;
141
161
  const nextCount = rawNextCount > schedule.length ? 1 : rawNextCount;
142
- const cooldownMs = computeCooldownMsBySeries(series, nextCount);
162
+ const cooldownMs = computeTransientKeepPoolCooldownMs(series, nextCount) ?? computeCooldownMsBySeries(series, nextCount);
143
163
  const nextUntil = cooldownMs ? nowMs + cooldownMs : null;
144
164
  const existingUntil = typeof state.cooldownUntil === 'number' ? state.cooldownUntil : null;
145
165
  const cooldownUntil = typeof nextUntil === 'number' && Number.isFinite(nextUntil)
@@ -149,12 +169,14 @@ export function applyErrorEvent(state, event, nowMs = event.timestampMs ?? Date.
149
169
  : existingUntil;
150
170
  const inCooldown = typeof cooldownUntil === 'number' && cooldownUntil > nowMs;
151
171
  const inBlacklist = typeof state.blacklistUntil === 'number' && state.blacklistUntil > nowMs;
152
- const inPool = !inCooldown && !inBlacklist;
172
+ const cooldownKeepsPool = shouldKeepProviderInPoolDuringCooldown(series, nextCount);
173
+ const inPool = !inBlacklist && (!inCooldown || cooldownKeepsPool);
153
174
  return {
154
175
  ...state,
155
176
  inPool,
156
177
  reason: inBlacklist ? 'blacklist' : inCooldown ? 'cooldown' : 'ok',
157
178
  cooldownUntil,
179
+ cooldownKeepsPool: inCooldown ? cooldownKeepsPool : undefined,
158
180
  lastErrorSeries: series,
159
181
  lastErrorCode: errorKey,
160
182
  lastErrorAtMs: nowMs,
@@ -26,6 +26,7 @@ export interface QuotaState {
26
26
  authIssue?: QuotaAuthIssue;
27
27
  priorityTier: number;
28
28
  cooldownUntil: number | null;
29
+ cooldownKeepsPool?: boolean;
29
30
  blacklistUntil: number | null;
30
31
  lastErrorSeries: ErrorSeries | null;
31
32
  lastErrorCode: string | null;
@@ -131,11 +131,11 @@ function normalizeRoutePoolEntry(routeName, entry, index, total) {
131
131
  record.isBackup === true ||
132
132
  (typeof record.type === 'string' && record.type.toLowerCase() === 'backup');
133
133
  const priority = normalizePriorityValue(record.priority, total - index);
134
- const targets = normalizeRouteTargets(record);
134
+ const loadBalancing = normalizeRoutePoolLoadBalancing(record.loadBalancing);
135
+ const targets = normalizeRouteTargets(record, loadBalancing);
135
136
  const mode = normalizeRoutePoolMode(record.mode ?? record.strategy ?? record.routingMode);
136
137
  const force = record.force === true ||
137
138
  (typeof record.force === 'string' && record.force.trim().toLowerCase() === 'true');
138
- const loadBalancing = normalizeRoutePoolLoadBalancing(record.loadBalancing);
139
139
  return targets.length
140
140
  ? {
141
141
  id,
@@ -209,7 +209,7 @@ function normalizeRoutePoolMode(value) {
209
209
  }
210
210
  return undefined;
211
211
  }
212
- function normalizeRouteTargets(record) {
212
+ function normalizeRouteTargets(record, loadBalancing) {
213
213
  const buckets = [record.targets, record.providers, record.pool, record.entries, record.items, record.routes];
214
214
  const normalized = [];
215
215
  for (const bucket of buckets) {
@@ -227,6 +227,14 @@ function normalizeRouteTargets(record) {
227
227
  }
228
228
  }
229
229
  }
230
+ if (normalized.length === 0 && loadBalancing?.weights && Object.keys(loadBalancing.weights).length > 0) {
231
+ for (const target of Object.keys(loadBalancing.weights)) {
232
+ const trimmed = target.trim();
233
+ if (trimmed && !normalized.includes(trimmed)) {
234
+ normalized.push(trimmed);
235
+ }
236
+ }
237
+ }
230
238
  return normalized;
231
239
  }
232
240
  function normalizeTargetList(value) {
@@ -4,14 +4,13 @@ import { RouteLoadBalancer } from './load-balancer.js';
4
4
  import { RoutingClassifier } from './classifier.js';
5
5
  import { ContextAdvisor } from './context-advisor.js';
6
6
  import type { ProcessedRequest, StandardizedRequest } from '../../conversion/hub/types/standardized.js';
7
- import { type RoutingPools, type RoutingDecision, type RoutingDiagnostics, type StopMessageStateSnapshot, type PreCommandStateSnapshot, type RoutePoolTier, type RouterMetadataInput, type RoutingFeatures, type VirtualRouterConfig, type VirtualRouterContextRoutingConfig, type TargetMetadata, type ProviderFailureEvent, type ProviderErrorEvent, type ProviderSuccessEvent, type VirtualRouterHealthStore } from './types.js';
7
+ import { type RoutingPools, type RoutingDecision, type RoutingDiagnostics, type StopMessageStateSnapshot, type PreCommandStateSnapshot, type RoutePoolTier, type RouterMetadataInput, type RoutingFeatures, type VirtualRouterConfig, type VirtualRouterContextRoutingConfig, type TargetMetadata, type RoutingStatusSnapshot, type ProviderFailureEvent, type ProviderErrorEvent, type ProviderSuccessEvent, type VirtualRouterHealthStore } from './types.js';
8
8
  import type { RoutingInstructionState } from './routing-instructions.js';
9
9
  import type { ProviderQuotaView } from './types.js';
10
10
  import type { RoutingInstructionStateStoreLike } from './engine/routing-state/store.js';
11
11
  import { RouteAnalytics } from './engine/route-analytics.js';
12
12
  import { StickySessionManager } from './engine/sticky-session-manager.js';
13
13
  import { CooldownManager } from './engine/cooldown-manager.js';
14
- import { getStatus as getStatusImpl } from './engine-legacy/state-accessors.js';
15
14
  export declare class VirtualRouterEngine {
16
15
  routing: RoutingPools;
17
16
  readonly providerRegistry: ProviderRegistry;
@@ -36,6 +35,7 @@ export declare class VirtualRouterEngine {
36
35
  routingStateStore: RoutingInstructionStateStoreLike;
37
36
  routingInstructionState: Map<string, RoutingInstructionState>;
38
37
  quotaView?: ProviderQuotaView;
38
+ private readonly nativeEngine;
39
39
  /**
40
40
  * Backward-compatible test/debug surface used by existing regression scripts.
41
41
  * Keep this as a read-only view over StickySessionManager storage.
@@ -62,7 +62,7 @@ export declare class VirtualRouterEngine {
62
62
  handleProviderFailure(event: ProviderFailureEvent): void;
63
63
  handleProviderError(event: ProviderErrorEvent): void;
64
64
  handleProviderSuccess(event: ProviderSuccessEvent): void;
65
- getStatus(): ReturnType<typeof getStatusImpl>;
65
+ getStatus(): RoutingStatusSnapshot;
66
66
  normalizeRouteAlias(routeName: string | undefined): string;
67
67
  buildRouteCandidates(requestedRoute: string, classificationCandidates: string[] | undefined, features: RoutingFeatures): string[];
68
68
  reorderForInlineVision(routeNames: string[]): string[];
@@ -9,10 +9,9 @@ import { resolveStickyKey as resolveStickyKeyImpl, resolveSessionScope as resolv
9
9
  import { RouteAnalytics } from './engine/route-analytics.js';
10
10
  import { StickySessionManager } from './engine/sticky-session-manager.js';
11
11
  import { CooldownManager } from './engine/cooldown-manager.js';
12
- import { routeRequest } from './engine-legacy/routing.js';
12
+ import { VirtualRouterEngine as NativeVirtualRouterEngine } from './engine.js';
13
13
  import { updateDeps as updateDepsImpl, initialize as initializeImpl } from './engine-legacy/config.js';
14
14
  import { handleProviderError as handleProviderErrorImpl, handleProviderFailure as handleProviderFailureImpl, handleProviderSuccess as handleProviderSuccessImpl, buildHealthSnapshot as buildHealthSnapshotImpl, persistHealthSnapshot as persistHealthSnapshotImpl, markProviderCooldown as markProviderCooldownImpl, clearProviderCooldown as clearProviderCooldownImpl, isProviderCoolingDown as isProviderCoolingDownImpl, getProviderCooldownRemainingMs as getProviderCooldownRemainingMsImpl, restoreHealthFromStore as restoreHealthFromStoreImpl } from './engine-legacy/health.js';
15
- import { getStopMessageState as getStopMessageStateImpl, getPreCommandState as getPreCommandStateImpl, getStatus as getStatusImpl } from './engine-legacy/state-accessors.js';
16
15
  import { selectProvider as selectProviderImpl, selectFromCandidates as selectFromCandidatesImpl, selectFromStickyPool as selectFromStickyPoolImpl, extractExcludedProviderKeySet as extractExcludedProviderKeySetImpl } from './engine-legacy/selection-core.js';
17
16
  import { parseDirectProviderModel as parseDirectProviderModelImpl, shouldFallbackDirectModelForMedia as shouldFallbackDirectModelForMediaImpl } from './engine-legacy/direct-model.js';
18
17
  import { normalizeRouteAlias as normalizeRouteAliasImpl, buildRouteCandidates as buildRouteCandidatesImpl, reorderForInlineVision as reorderForInlineVisionImpl, reorderForPreferredModel as reorderForPreferredModelImpl, routeSupportsModel as routeSupportsModelImpl, routeSupportsInlineVision as routeSupportsInlineVisionImpl, sortByPriority as sortByPriorityImpl, routeWeight as routeWeightImpl, routeHasForceFlag as routeHasForceFlagImpl, routeHasTargets as routeHasTargetsImpl, hasPrimaryPool as hasPrimaryPoolImpl, sortRoutePools as sortRoutePoolsImpl, flattenPoolTargets as flattenPoolTargetsImpl } from './engine-legacy/route-utils.js';
@@ -42,14 +41,16 @@ export class VirtualRouterEngine {
42
41
  };
43
42
  routingInstructionState = new Map();
44
43
  quotaView;
44
+ nativeEngine;
45
45
  /**
46
46
  * Backward-compatible test/debug surface used by existing regression scripts.
47
47
  * Keep this as a read-only view over StickySessionManager storage.
48
48
  */
49
49
  get antigravitySessionAliasStore() {
50
- return this.stickySessionManager.getAllStores().sessionAliasStore;
50
+ return this.nativeEngine.antigravitySessionAliasStore;
51
51
  }
52
52
  constructor(deps) {
53
+ this.nativeEngine = new NativeVirtualRouterEngine(deps);
53
54
  this.cooldownManager = new CooldownManager({
54
55
  healthStore: deps?.healthStore,
55
56
  healthConfig: this.healthConfig,
@@ -67,30 +68,35 @@ export class VirtualRouterEngine {
67
68
  }
68
69
  updateDeps(deps) {
69
70
  updateDepsImpl(this, deps);
71
+ this.nativeEngine.updateDeps(deps);
70
72
  }
71
73
  initialize(config) {
72
74
  initializeImpl(this, config);
75
+ this.nativeEngine.initialize(config);
73
76
  }
74
77
  route(request, metadata) {
75
- return routeRequest(this, request, metadata);
78
+ return this.nativeEngine.route(request, metadata);
76
79
  }
77
80
  getStopMessageState(metadata) {
78
- return getStopMessageStateImpl(this, metadata);
81
+ return this.nativeEngine.getStopMessageState(metadata);
79
82
  }
80
83
  getPreCommandState(metadata) {
81
- return getPreCommandStateImpl(this, metadata);
84
+ return this.nativeEngine.getPreCommandState(metadata);
82
85
  }
83
86
  handleProviderFailure(event) {
84
87
  handleProviderFailureImpl(this, event);
88
+ this.nativeEngine.handleProviderFailure(event);
85
89
  }
86
90
  handleProviderError(event) {
87
91
  handleProviderErrorImpl(this, event);
92
+ this.nativeEngine.handleProviderError(event);
88
93
  }
89
94
  handleProviderSuccess(event) {
90
95
  handleProviderSuccessImpl(this, event);
96
+ this.nativeEngine.handleProviderSuccess(event);
91
97
  }
92
98
  getStatus() {
93
- return getStatusImpl(this);
99
+ return this.nativeEngine.getStatus();
94
100
  }
95
101
  normalizeRouteAlias(routeName) {
96
102
  return normalizeRouteAliasImpl(routeName);
@@ -133,9 +139,11 @@ export class VirtualRouterEngine {
133
139
  }
134
140
  markProviderCooldown(providerKey, cooldownMs) {
135
141
  markProviderCooldownImpl(this, providerKey, cooldownMs);
142
+ this.nativeEngine.markProviderCooldown(providerKey, cooldownMs);
136
143
  }
137
144
  clearProviderCooldown(providerKey) {
138
145
  clearProviderCooldownImpl(this, providerKey);
146
+ this.nativeEngine.clearProviderCooldown(providerKey);
139
147
  }
140
148
  isProviderCoolingDown(providerKey) {
141
149
  return isProviderCoolingDownImpl(this, providerKey);
@@ -4,3 +4,19 @@ export declare function applyRequestRulesWithNative(payload: Record<string, unkn
4
4
  export declare function applyResponseBlacklistWithNative(payload: Record<string, unknown>, config?: Record<string, unknown>): Record<string, unknown>;
5
5
  export declare function normalizeToolCallIdsWithNative(payload: Record<string, unknown>): Record<string, unknown>;
6
6
  export declare function enforceLmstudioResponsesFcToolCallIdsWithNative(payload: Record<string, unknown>): Record<string, unknown>;
7
+ export declare function applyAnthropicClaudeCodeUserIdWithNative(payload: Record<string, unknown>, adapterContext?: Record<string, unknown>): Record<string, unknown>;
8
+ export declare function applyGeminiWebSearchRequestCompatWithNative(payload: Record<string, unknown>, adapterContext?: Record<string, unknown>): Record<string, unknown>;
9
+ export declare function prepareAntigravityThoughtSignatureForGeminiRequestWithNative(payload: Record<string, unknown>, adapterContext?: Record<string, unknown>): Record<string, unknown>;
10
+ export declare function applyIflowToolTextFallbackWithNative(payload: Record<string, unknown>, adapterContext?: Record<string, unknown>, models?: string[]): Record<string, unknown>;
11
+ export declare function applyToolTextRequestGuidanceWithNative(payload: Record<string, unknown>, config?: Record<string, unknown>): Record<string, unknown>;
12
+ export declare function applyUniversalShapeRequestFilterWithNative(payload: Record<string, unknown>, config?: Record<string, unknown>): Record<string, unknown>;
13
+ export declare function applyUniversalShapeResponseFilterWithNative(payload: Record<string, unknown>, config?: Record<string, unknown>, adapterContext?: Record<string, unknown>): Record<string, unknown>;
14
+ export declare function buildOpenAIChatFromAnthropicWithNative(payload: Record<string, unknown>, options?: Record<string, unknown>): Record<string, unknown>;
15
+ export declare function buildAnthropicFromOpenAIChatWithNative(payload: Record<string, unknown>, options?: Record<string, unknown>): Record<string, unknown>;
16
+ export declare function runOpenAIRequestCodecWithNative(payload: Record<string, unknown>, options?: Record<string, unknown>): Record<string, unknown>;
17
+ export declare function runOpenAIResponseCodecWithNative(payload: Record<string, unknown>, options?: Record<string, unknown>): Record<string, unknown>;
18
+ export declare function runResponsesOpenAIRequestCodecWithNative(payload: Record<string, unknown>, options?: Record<string, unknown>): Record<string, unknown>;
19
+ export declare function runResponsesOpenAIResponseCodecWithNative(payload: Record<string, unknown>, context: Record<string, unknown>): Record<string, unknown>;
20
+ export declare function runGeminiOpenAIRequestCodecWithNative(payload: Record<string, unknown>, options?: Record<string, unknown>): Record<string, unknown>;
21
+ export declare function runGeminiOpenAIResponseCodecWithNative(payload: Record<string, unknown>, options?: Record<string, unknown>): Record<string, unknown>;
22
+ export declare function runGeminiFromOpenAIChatCodecWithNative(payload: Record<string, unknown>, options?: Record<string, unknown>): Record<string, unknown>;