@jsonstudio/llms 0.6.3405 → 0.6.3539
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/anthropic-openai-codec.d.ts +12 -3
- package/dist/conversion/codecs/anthropic-openai-codec.js +32 -92
- package/dist/conversion/codecs/gemini-openai-codec.d.ts +6 -5
- package/dist/conversion/codecs/gemini-openai-codec.js +48 -685
- package/dist/conversion/codecs/openai-openai-codec.d.ts +1 -1
- package/dist/conversion/codecs/openai-openai-codec.js +34 -100
- package/dist/conversion/codecs/responses-openai-codec.d.ts +1 -1
- package/dist/conversion/codecs/responses-openai-codec.js +47 -159
- package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.d.ts +2 -6
- package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.js +29 -245
- package/dist/conversion/compat/actions/anthropic-claude-code-user-id.d.ts +3 -0
- package/dist/conversion/compat/actions/anthropic-claude-code-user-id.js +30 -0
- package/dist/conversion/compat/actions/antigravity-thought-signature-prepare.js +21 -232
- package/dist/conversion/compat/actions/deepseek-web-request.js +41 -276
- package/dist/conversion/compat/actions/deepseek-web-response.js +64 -859
- package/dist/conversion/compat/actions/gemini-cli-request.d.ts +1 -1
- package/dist/conversion/compat/actions/gemini-cli-request.js +20 -613
- package/dist/conversion/compat/actions/gemini-web-search.d.ts +1 -15
- package/dist/conversion/compat/actions/gemini-web-search.js +22 -69
- package/dist/conversion/compat/actions/glm-tool-extraction.d.ts +3 -2
- package/dist/conversion/compat/actions/glm-tool-extraction.js +28 -257
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.d.ts +0 -8
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.js +24 -206
- package/dist/conversion/compat/actions/qwen-transform.d.ts +3 -2
- package/dist/conversion/compat/actions/qwen-transform.js +30 -271
- package/dist/conversion/compat/actions/tool-text-request-guidance.js +3 -173
- package/dist/conversion/compat/actions/universal-shape-filter.d.ts +6 -23
- package/dist/conversion/compat/actions/universal-shape-filter.js +4 -383
- package/dist/conversion/hub/pipeline/compat/native-adapter-context.js +1 -0
- package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.d.ts +1 -2
- package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.js +50 -104
- package/dist/conversion/pipeline/codecs/v2/openai-openai-pipeline.js +12 -10
- package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.d.ts +0 -2
- package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.js +46 -67
- package/dist/conversion/pipeline/codecs/v2/shared/openai-chat-helpers.js +15 -40
- package/dist/conversion/responses/responses-openai-bridge/response-payload.js +47 -348
- package/dist/conversion/responses/responses-openai-bridge.js +129 -611
- package/dist/conversion/shared/chat-output-normalizer.js +6 -0
- package/dist/conversion/shared/chat-request-filters.js +1 -1
- package/dist/conversion/shared/output-content-normalizer.js +10 -0
- package/dist/conversion/shared/responses-conversation-store.js +22 -135
- package/dist/conversion/shared/responses-output-builder.d.ts +0 -2
- package/dist/conversion/shared/responses-output-builder.js +28 -318
- package/dist/conversion/shared/responses-response-utils.js +35 -86
- package/dist/conversion/shared/streaming-text-extractor.d.ts +1 -2
- package/dist/conversion/shared/streaming-text-extractor.js +13 -14
- package/dist/conversion/shared/tool-call-id-manager.js +18 -21
- package/dist/native/router_hotpath_napi.node +0 -0
- package/dist/router/virtual-router/bootstrap/routing-config.d.ts +2 -1
- package/dist/router/virtual-router/bootstrap/routing-config.js +57 -4
- package/dist/router/virtual-router/engine-legacy.d.ts +3 -3
- package/dist/router/virtual-router/engine-legacy.js +15 -7
- package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.d.ts +16 -0
- package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.js +434 -46
- package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.d.ts +83 -0
- package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js +295 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-req-outbound-semantics.d.ts +1 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.d.ts +7 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js +8 -1
- package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +383 -298
- package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.d.ts +20 -0
- package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.js +201 -0
- package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.d.ts +1 -0
- package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.js +37 -0
- package/dist/router/virtual-router/engine-selection/tier-load-balancing.d.ts +16 -0
- package/dist/router/virtual-router/engine-selection/tier-load-balancing.js +120 -0
- package/dist/router/virtual-router/engine-selection/tier-selection-quota-integration.d.ts +2 -0
- package/dist/router/virtual-router/engine-selection/tier-selection-quota-integration.js +44 -66
- package/dist/router/virtual-router/engine-selection/tier-selection-select.js +53 -84
- package/dist/router/virtual-router/engine.js +0 -38
- package/dist/router/virtual-router/features.js +44 -3
- package/dist/router/virtual-router/routing-instructions/parse.d.ts +0 -12
- package/dist/router/virtual-router/routing-instructions/parse.js +9 -389
- package/dist/router/virtual-router/stop-message-state-sync.d.ts +3 -6
- package/dist/router/virtual-router/stop-message-state-sync.js +50 -21
- package/dist/router/virtual-router/types.d.ts +16 -0
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +1 -0
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +26 -0
- package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +12 -2
- package/package.json +1 -1
- package/dist/router/virtual-router/engine-legacy/route-finalize.d.ts +0 -9
- package/dist/router/virtual-router/engine-legacy/route-finalize.js +0 -84
- package/dist/router/virtual-router/engine-legacy/route-selection.d.ts +0 -17
- package/dist/router/virtual-router/engine-legacy/route-selection.js +0 -205
- package/dist/router/virtual-router/engine-legacy/route-state-allowlist.d.ts +0 -3
- package/dist/router/virtual-router/engine-legacy/route-state-allowlist.js +0 -36
- package/dist/router/virtual-router/engine-legacy/route-state.d.ts +0 -12
- package/dist/router/virtual-router/engine-legacy/route-state.js +0 -386
- package/dist/router/virtual-router/engine-legacy/routing.d.ts +0 -8
- 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
|
|
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
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const
|
|
211
|
-
const
|
|
212
|
-
|
|
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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
|
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 {
|
|
4
|
+
import { createStreamingToolExtractorStateWithNative, feedStreamingToolExtractorWithNative, resetStreamingToolExtractorStateWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
|
|
5
5
|
function assertStreamingToolExtractorNativeAvailable() {
|
|
6
|
-
if (typeof
|
|
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
|
-
|
|
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
|
-
|
|
19
|
-
this.
|
|
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
|
|
26
|
-
|
|
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.
|
|
34
|
-
|
|
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) {
|
|
@@ -35,11 +35,9 @@ export class ToolCallIdManager {
|
|
|
35
35
|
*/
|
|
36
36
|
generateId() {
|
|
37
37
|
assertToolCallIdManagerNativeAvailable();
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
return normalizeIdValueWithNative(undefined, true);
|
|
38
|
+
const output = transformToolCallIdWithNative(this.state, '');
|
|
39
|
+
this.state = output.state;
|
|
40
|
+
return output.id;
|
|
43
41
|
}
|
|
44
42
|
/**
|
|
45
43
|
* 规范化工具调用 ID
|
|
@@ -50,13 +48,9 @@ export class ToolCallIdManager {
|
|
|
50
48
|
normalizeId(id) {
|
|
51
49
|
assertToolCallIdManagerNativeAvailable();
|
|
52
50
|
const raw = typeof id === 'string' ? id : '';
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return output.id;
|
|
57
|
-
}
|
|
58
|
-
const trimmed = raw.trim();
|
|
59
|
-
return trimmed ? trimmed : normalizeIdValueWithNative(undefined, true);
|
|
51
|
+
const output = transformToolCallIdWithNative(this.state, raw);
|
|
52
|
+
this.state = output.state;
|
|
53
|
+
return output.id;
|
|
60
54
|
}
|
|
61
55
|
/**
|
|
62
56
|
* 规范化工具调用 ID(带别名注册)
|
|
@@ -68,18 +62,21 @@ export class ToolCallIdManager {
|
|
|
68
62
|
normalizeIdWithAlias(id, aliasMap) {
|
|
69
63
|
assertToolCallIdManagerNativeAvailable();
|
|
70
64
|
const raw = typeof id === 'string' ? id : '';
|
|
71
|
-
if (this.options.style !== 'preserve') {
|
|
72
|
-
return this.normalizeId(raw);
|
|
73
|
-
}
|
|
74
65
|
const trimmed = raw.trim();
|
|
75
|
-
if (
|
|
76
|
-
|
|
66
|
+
if (this.options.style === 'preserve' && trimmed && aliasMap?.has(trimmed)) {
|
|
67
|
+
const existing = aliasMap.get(trimmed);
|
|
68
|
+
const aliasState = this.state.aliasMap;
|
|
69
|
+
if (aliasState && typeof aliasState === 'object') {
|
|
70
|
+
aliasState[trimmed] = existing;
|
|
71
|
+
}
|
|
72
|
+
return existing;
|
|
77
73
|
}
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
const output = transformToolCallIdWithNative(this.state, raw);
|
|
75
|
+
this.state = output.state;
|
|
76
|
+
if (this.options.style === 'preserve' && trimmed && aliasMap) {
|
|
77
|
+
aliasMap.set(trimmed, output.id);
|
|
81
78
|
}
|
|
82
|
-
return
|
|
79
|
+
return output.id;
|
|
83
80
|
}
|
|
84
81
|
/**
|
|
85
82
|
* 批量规范化工具调用 ID
|
|
Binary file
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type RoutingPools } from '../types.js';
|
|
1
|
+
import { type RoutingPools, type RoutePoolLoadBalancingPolicy } from '../types.js';
|
|
2
2
|
export interface NormalizedRoutePoolConfig {
|
|
3
3
|
id: string;
|
|
4
4
|
priority: number;
|
|
@@ -6,6 +6,7 @@ export interface NormalizedRoutePoolConfig {
|
|
|
6
6
|
targets: string[];
|
|
7
7
|
mode?: 'round-robin' | 'priority';
|
|
8
8
|
force?: boolean;
|
|
9
|
+
loadBalancing?: RoutePoolLoadBalancingPolicy;
|
|
9
10
|
}
|
|
10
11
|
export declare function normalizeRouting(source: Record<string, unknown>): Record<string, NormalizedRoutePoolConfig[]>;
|
|
11
12
|
export declare function expandRoutingTable(routingSource: Record<string, NormalizedRoutePoolConfig[]>, aliasIndex: Map<string, string[]>, modelIndex: Map<string, {
|
|
@@ -91,7 +91,8 @@ export function expandRoutingTable(routingSource, aliasIndex, modelIndex) {
|
|
|
91
91
|
backup: pool.backup,
|
|
92
92
|
targets: sortedTargets,
|
|
93
93
|
...(pool.mode ? { mode: pool.mode } : {}),
|
|
94
|
-
...(pool.force ? { force: true } : {})
|
|
94
|
+
...(pool.force ? { force: true } : {}),
|
|
95
|
+
...(pool.loadBalancing ? { loadBalancing: pool.loadBalancing } : {})
|
|
95
96
|
});
|
|
96
97
|
}
|
|
97
98
|
}
|
|
@@ -130,7 +131,8 @@ function normalizeRoutePoolEntry(routeName, entry, index, total) {
|
|
|
130
131
|
record.isBackup === true ||
|
|
131
132
|
(typeof record.type === 'string' && record.type.toLowerCase() === 'backup');
|
|
132
133
|
const priority = normalizePriorityValue(record.priority, total - index);
|
|
133
|
-
const
|
|
134
|
+
const loadBalancing = normalizeRoutePoolLoadBalancing(record.loadBalancing);
|
|
135
|
+
const targets = normalizeRouteTargets(record, loadBalancing);
|
|
134
136
|
const mode = normalizeRoutePoolMode(record.mode ?? record.strategy ?? record.routingMode);
|
|
135
137
|
const force = record.force === true ||
|
|
136
138
|
(typeof record.force === 'string' && record.force.trim().toLowerCase() === 'true');
|
|
@@ -141,10 +143,53 @@ function normalizeRoutePoolEntry(routeName, entry, index, total) {
|
|
|
141
143
|
backup,
|
|
142
144
|
targets,
|
|
143
145
|
...(mode ? { mode } : {}),
|
|
144
|
-
...(force ? { force: true } : {})
|
|
146
|
+
...(force ? { force: true } : {}),
|
|
147
|
+
...(loadBalancing ? { loadBalancing } : {})
|
|
145
148
|
}
|
|
146
149
|
: null;
|
|
147
150
|
}
|
|
151
|
+
function normalizeRoutePoolLoadBalancing(input) {
|
|
152
|
+
if (!input || typeof input !== 'object' || Array.isArray(input)) {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
const record = input;
|
|
156
|
+
const strategy = normalizeWeightedStrategy(record.strategy);
|
|
157
|
+
const weightsRaw = record.weights && typeof record.weights === 'object' && !Array.isArray(record.weights)
|
|
158
|
+
? record.weights
|
|
159
|
+
: {};
|
|
160
|
+
const weights = {};
|
|
161
|
+
for (const [key, value] of Object.entries(weightsRaw)) {
|
|
162
|
+
if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
|
|
163
|
+
weights[key] = value;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (!strategy && Object.keys(weights).length === 0) {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
...(strategy ? { strategy } : {}),
|
|
171
|
+
...(Object.keys(weights).length ? { weights } : {})
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function normalizeWeightedStrategy(value) {
|
|
175
|
+
if (typeof value !== 'string') {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
const normalized = value.trim().toLowerCase();
|
|
179
|
+
if (!normalized) {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
if (normalized === 'weighted') {
|
|
183
|
+
return 'weighted';
|
|
184
|
+
}
|
|
185
|
+
if (normalized === 'sticky') {
|
|
186
|
+
return 'sticky';
|
|
187
|
+
}
|
|
188
|
+
if (normalized === 'round-robin' || normalized === 'round_robin' || normalized === 'roundrobin' || normalized === 'rr') {
|
|
189
|
+
return 'round-robin';
|
|
190
|
+
}
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
148
193
|
function normalizeRoutePoolMode(value) {
|
|
149
194
|
if (typeof value !== 'string') {
|
|
150
195
|
return undefined;
|
|
@@ -164,7 +209,7 @@ function normalizeRoutePoolMode(value) {
|
|
|
164
209
|
}
|
|
165
210
|
return undefined;
|
|
166
211
|
}
|
|
167
|
-
function normalizeRouteTargets(record) {
|
|
212
|
+
function normalizeRouteTargets(record, loadBalancing) {
|
|
168
213
|
const buckets = [record.targets, record.providers, record.pool, record.entries, record.items, record.routes];
|
|
169
214
|
const normalized = [];
|
|
170
215
|
for (const bucket of buckets) {
|
|
@@ -182,6 +227,14 @@ function normalizeRouteTargets(record) {
|
|
|
182
227
|
}
|
|
183
228
|
}
|
|
184
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
|
+
}
|
|
185
238
|
return normalized;
|
|
186
239
|
}
|
|
187
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():
|
|
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 {
|
|
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.
|
|
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
|
|
78
|
+
return this.nativeEngine.route(request, metadata);
|
|
76
79
|
}
|
|
77
80
|
getStopMessageState(metadata) {
|
|
78
|
-
return
|
|
81
|
+
return this.nativeEngine.getStopMessageState(metadata);
|
|
79
82
|
}
|
|
80
83
|
getPreCommandState(metadata) {
|
|
81
|
-
return
|
|
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
|
|
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>;
|