@jsonstudio/llms 0.6.2979 → 0.6.3214
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/args-mapping.js +8 -0
- package/dist/conversion/{shared/bridge-actions.js → bridge-actions.js} +2 -1
- package/dist/conversion/{shared/bridge-id-utils.js → bridge-id-utils.js} +1 -1
- package/dist/conversion/{shared/bridge-instructions.js → bridge-instructions.js} +1 -1
- package/dist/conversion/{shared/bridge-message-utils.d.ts → bridge-message-utils.d.ts} +1 -1
- package/dist/conversion/{shared/bridge-message-utils.js → bridge-message-utils.js} +5 -149
- package/dist/conversion/{shared/bridge-metadata.js → bridge-metadata.js} +1 -1
- package/dist/conversion/{shared/bridge-policies.js → bridge-policies.js} +1 -1
- package/dist/conversion/codecs/gemini-openai-codec.js +27 -8
- package/dist/conversion/codecs/responses-openai-codec.js +1 -1
- package/dist/conversion/{shared/compaction-detect.d.ts → compaction-detect.d.ts} +1 -1
- package/dist/conversion/compaction-detect.js +4 -0
- package/dist/conversion/compat/actions/apply-patch-fixer.js +2 -2
- package/dist/conversion/compat/actions/deepseek-web-response.d.ts +0 -1
- package/dist/conversion/compat/actions/deepseek-web-response.js +15 -405
- package/dist/conversion/compat/actions/harvest-tool-calls-from-text.js +1 -1
- package/dist/conversion/compat/actions/lmstudio-responses-fc-ids.js +1 -1
- package/dist/conversion/compat/actions/qwen-transform.js +74 -2
- package/dist/conversion/compat/actions/snapshot.js +1 -1
- package/dist/conversion/compat/antigravity-session-signature.js +36 -0
- package/dist/conversion/compat/profiles/chat-deepseek-web.json +0 -22
- package/dist/conversion/compat/profiles/chat-glm.json +251 -72
- package/dist/conversion/compat/profiles/chat-iflow.json +174 -39
- package/dist/conversion/compat/profiles/chat-lmstudio.json +43 -14
- package/dist/conversion/hub/operation-table/operation-table-runner.js +2 -2
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +1 -1
- package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +7 -4
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +2 -2
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +2 -8
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +1 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +50 -3
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +1 -1
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +62 -0
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.js +3 -1
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +1 -1
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/chat-process-semantics-bridge.d.ts +1 -1
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +42 -29
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.js +12 -0
- package/dist/conversion/hub/policy/protocol-spec.js +1 -1
- package/dist/conversion/hub/process/chat-process-clock-reminders.js +1 -1
- package/dist/conversion/hub/process/chat-process-clock-tools.js +1 -1
- package/dist/conversion/hub/process/chat-process-continue-execution.js +1 -1
- package/dist/conversion/hub/process/chat-process-servertool-orchestration.js +1 -1
- package/dist/conversion/hub/process/chat-process-web-search.js +1 -1
- package/dist/conversion/hub/response/provider-response.js +14 -5
- package/dist/conversion/hub/response/response-mappers.js +23 -1
- package/dist/conversion/hub/response/response-runtime.js +28 -5
- package/dist/conversion/hub/snapshot-recorder.js +1 -1
- package/dist/conversion/hub/tool-governance/engine.d.ts +8 -0
- package/dist/conversion/hub/tool-governance/engine.js +25 -68
- package/dist/conversion/hub/tool-governance/rules.js +73 -69
- package/dist/conversion/hub/tool-surface/tool-surface-engine.js +1 -1
- package/dist/conversion/index.d.ts +1 -2
- package/dist/conversion/index.js +1 -2
- package/dist/conversion/{shared/jsonish.js → jsonish.js} +1 -1
- package/dist/conversion/{shared/mcp-injection.js → mcp-injection.js} +1 -1
- package/dist/conversion/media.js +4 -0
- package/dist/conversion/{shared/metadata-passthrough.d.ts → metadata-passthrough.d.ts} +1 -1
- package/dist/conversion/{shared/metadata-passthrough.js → metadata-passthrough.js} +2 -2
- package/dist/conversion/payload-budget.js +47 -0
- package/dist/conversion/protocol-field-allowlists.d.ts +7 -0
- package/dist/conversion/protocol-field-allowlists.js +9 -0
- package/dist/conversion/{shared/protocol-state.d.ts → protocol-state.d.ts} +2 -2
- package/dist/conversion/{shared/protocol-state.js → protocol-state.js} +2 -2
- package/dist/conversion/{shared/errors.d.ts → provider-protocol-error.d.ts} +0 -3
- package/dist/conversion/provider-protocol-error.js +25 -0
- package/dist/conversion/responses/responses-openai-bridge/response-payload.js +8 -5
- package/dist/conversion/responses/responses-openai-bridge/types.d.ts +1 -1
- package/dist/conversion/responses/responses-openai-bridge.d.ts +1 -1
- package/dist/conversion/responses/responses-openai-bridge.js +43 -10
- package/dist/conversion/{shared/runtime-metadata.d.ts → runtime-metadata.d.ts} +1 -1
- package/dist/conversion/{shared/runtime-metadata.js → runtime-metadata.js} +2 -2
- package/dist/conversion/shared/anthropic-message-utils.js +19 -8
- package/dist/conversion/shared/chat-request-filters.d.ts +3 -4
- package/dist/conversion/shared/chat-request-filters.js +22 -78
- package/dist/conversion/shared/gemini-tool-utils.d.ts +1 -1
- package/dist/conversion/shared/openai-finalizer.js +1 -0
- package/dist/conversion/shared/openai-message-normalize.js +2 -2
- package/dist/conversion/shared/reasoning-normalizer.js +6 -0
- package/dist/conversion/shared/reasoning-utils.js +5 -2
- package/dist/conversion/shared/responses-conversation-store.js +1 -1
- package/dist/conversion/shared/responses-output-builder.js +55 -11
- package/dist/conversion/shared/responses-reasoning-registry.d.ts +14 -2
- package/dist/conversion/shared/responses-reasoning-registry.js +34 -6
- package/dist/conversion/shared/responses-response-utils.js +99 -9
- package/dist/conversion/shared/responses-tool-utils.js +1 -1
- package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +1 -1
- package/dist/conversion/shared/text-markup-normalizer.d.ts +2 -2
- package/dist/conversion/shared/text-markup-normalizer.js +1 -1
- package/dist/conversion/shared/tool-filter-pipeline.js +1 -1
- package/dist/conversion/shared/tool-governor.js +3 -3
- package/dist/conversion/shared/tool-mapping.d.ts +1 -1
- package/dist/conversion/{shared/snapshot-utils.d.ts → snapshot-utils.d.ts} +11 -0
- package/dist/conversion/{shared/snapshot-utils.js → snapshot-utils.js} +14 -23
- package/dist/conversion/types/text-markup-normalizer.d.ts +13 -0
- package/dist/conversion/types/text-markup-normalizer.js +1 -0
- package/dist/filters/special/request-tools-normalize.js +1 -1
- package/dist/filters/special/response-tool-text-canonicalize.js +2 -2
- package/dist/native/router_hotpath_napi.node +0 -0
- package/dist/quota/quota-manager.js +31 -59
- package/dist/quota/quota-state.js +14 -7
- package/dist/router/virtual-router/bootstrap/profile-builder.d.ts +1 -0
- package/dist/router/virtual-router/bootstrap/profile-builder.js +13 -0
- package/dist/router/virtual-router/bootstrap/provider-normalization.d.ts +2 -0
- package/dist/router/virtual-router/bootstrap/provider-normalization.js +4 -1
- package/dist/router/virtual-router/bootstrap/streaming-helpers.d.ts +7 -0
- package/dist/router/virtual-router/bootstrap/streaming-helpers.js +44 -0
- package/dist/router/virtual-router/bootstrap.js +2 -0
- package/dist/router/virtual-router/engine/routing-state/store.d.ts +1 -2
- package/dist/router/virtual-router/engine/routing-state/store.js +2 -2
- package/dist/router/virtual-router/engine-legacy/config.d.ts +11 -0
- package/dist/router/virtual-router/engine-legacy/config.js +108 -0
- package/dist/router/virtual-router/engine-legacy/direct-model.d.ts +10 -0
- package/dist/router/virtual-router/engine-legacy/direct-model.js +38 -0
- package/dist/router/virtual-router/engine-legacy/health.d.ts +13 -0
- package/dist/router/virtual-router/engine-legacy/health.js +104 -0
- package/dist/router/virtual-router/engine-legacy/helpers.d.ts +16 -0
- package/dist/router/virtual-router/engine-legacy/helpers.js +226 -0
- package/dist/router/virtual-router/engine-legacy/route-finalize.d.ts +9 -0
- package/dist/router/virtual-router/engine-legacy/route-finalize.js +84 -0
- package/dist/router/virtual-router/engine-legacy/route-selection.d.ts +17 -0
- package/dist/router/virtual-router/engine-legacy/route-selection.js +205 -0
- package/dist/router/virtual-router/engine-legacy/route-state-allowlist.d.ts +3 -0
- package/dist/router/virtual-router/engine-legacy/route-state-allowlist.js +36 -0
- package/dist/router/virtual-router/engine-legacy/route-state.d.ts +12 -0
- package/dist/router/virtual-router/engine-legacy/route-state.js +386 -0
- package/dist/router/virtual-router/engine-legacy/route-utils.d.ts +19 -0
- package/dist/router/virtual-router/engine-legacy/route-utils.js +212 -0
- package/dist/router/virtual-router/engine-legacy/routing.d.ts +8 -0
- package/dist/router/virtual-router/engine-legacy/routing.js +8 -0
- package/dist/router/virtual-router/engine-legacy/selection-core.d.ts +28 -0
- package/dist/router/virtual-router/engine-legacy/selection-core.js +112 -0
- package/dist/router/virtual-router/engine-legacy/selection-state.d.ts +16 -0
- package/dist/router/virtual-router/engine-legacy/selection-state.js +187 -0
- package/dist/router/virtual-router/engine-legacy/state-accessors.d.ts +21 -0
- package/dist/router/virtual-router/engine-legacy/state-accessors.js +118 -0
- package/dist/router/virtual-router/engine-legacy.d.ts +123 -0
- package/dist/router/virtual-router/engine-legacy.js +194 -0
- package/dist/router/virtual-router/engine-logging.d.ts +2 -0
- package/dist/router/virtual-router/engine-logging.js +7 -2
- package/dist/router/virtual-router/engine-selection/key-parsing.js +0 -3
- package/dist/router/virtual-router/engine-selection/native-chat-request-filter-semantics.d.ts +1 -0
- package/dist/router/virtual-router/engine-selection/native-chat-request-filter-semantics.js +54 -0
- package/dist/router/virtual-router/engine-selection/native-hub-bridge-policy-semantics.d.ts +10 -0
- package/dist/router/virtual-router/engine-selection/native-hub-bridge-policy-semantics.js +67 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-governance-semantics.d.ts +22 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-governance-semantics.js +154 -0
- package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +38 -2
- package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.d.ts +75 -0
- package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.js +205 -0
- package/dist/router/virtual-router/engine-selection/native-snapshot-hooks.d.ts +2 -0
- package/dist/router/virtual-router/engine-selection/native-snapshot-hooks.js +69 -0
- package/dist/router/virtual-router/engine-selection/native-virtual-router-engine-proxy.d.ts +16 -0
- package/dist/router/virtual-router/engine-selection/native-virtual-router-engine-proxy.js +14 -0
- package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.d.ts +2 -0
- package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.js +86 -0
- package/dist/router/virtual-router/engine-selection/tier-selection-quota-integration.js +100 -0
- package/dist/router/virtual-router/engine-selection/tier-selection-select.js +99 -0
- package/dist/router/virtual-router/engine.d.ts +22 -105
- package/dist/router/virtual-router/engine.js +274 -1641
- package/dist/router/virtual-router/load-balancer.d.ts +8 -0
- package/dist/router/virtual-router/load-balancer.js +65 -2
- package/dist/router/virtual-router/provider-registry.js +2 -0
- package/dist/router/virtual-router/routing-instructions/clean.d.ts +3 -0
- package/dist/router/virtual-router/routing-instructions/clean.js +34 -0
- package/dist/router/virtual-router/routing-instructions/parse.d.ts +18 -0
- package/dist/router/virtual-router/routing-instructions/parse.js +377 -0
- package/dist/router/virtual-router/routing-instructions/state.d.ts +4 -0
- package/dist/router/virtual-router/routing-instructions/state.js +245 -0
- package/dist/router/virtual-router/routing-instructions/types.d.ts +70 -0
- package/dist/router/virtual-router/routing-instructions/types.js +2 -0
- package/dist/router/virtual-router/routing-instructions.d.ts +5 -89
- package/dist/router/virtual-router/routing-instructions.js +4 -655
- package/dist/router/virtual-router/sticky-session-store.d.ts +4 -0
- package/dist/router/virtual-router/sticky-session-store.js +19 -81
- package/dist/router/virtual-router/tool-signals.js +21 -3
- package/dist/router/virtual-router/types.d.ts +4 -0
- package/dist/servertool/clock/session-scope.js +32 -1
- package/dist/servertool/engine.js +79 -8
- package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.js +1 -1
- package/dist/servertool/handlers/clock-auto.js +1 -1
- package/dist/servertool/handlers/clock.js +1 -1
- package/dist/servertool/handlers/compaction-detect.d.ts +1 -1
- package/dist/servertool/handlers/compaction-detect.js +1 -1
- package/dist/servertool/handlers/gemini-empty-reply-continue.js +1 -1
- package/dist/servertool/handlers/iflow-model-error-retry.js +1 -1
- package/dist/servertool/handlers/recursive-detection-guard.js +1 -1
- package/dist/servertool/handlers/review.js +1 -1
- package/dist/servertool/handlers/stop-message-auto/iflow-followup.js +1 -1
- package/dist/servertool/handlers/stop-message-auto/runtime-utils.js +1 -1
- package/dist/servertool/handlers/stop-message-auto.js +1 -1
- package/dist/servertool/handlers/vision.js +1 -1
- package/dist/servertool/handlers/web-search.js +1 -1
- package/dist/servertool/reenter-backend.js +1 -1
- package/dist/servertool/server-side-tools.js +2 -2
- package/dist/servertool/stop-gateway-context.js +1 -1
- package/dist/servertool/stop-message-compare-context.js +1 -1
- package/dist/sse/json-to-sse/event-generators/responses.d.ts +4 -0
- package/dist/sse/json-to-sse/event-generators/responses.js +95 -1
- package/dist/sse/json-to-sse/sequencers/responses-sequencer.js +6 -4
- package/dist/sse/sse-to-json/builders/response-builder.d.ts +8 -0
- package/dist/sse/sse-to-json/builders/response-builder.js +162 -4
- package/dist/sse/sse-to-json/responses-sse-to-json-converter.js +2 -0
- package/dist/sse/types/responses-types.d.ts +6 -2
- package/dist/tools/apply-patch/structured/coercion.js +5 -0
- package/dist/tools/args-json.js +29 -0
- package/package.json +8 -5
- package/dist/conversion/shared/args-mapping.js +0 -77
- package/dist/conversion/shared/compaction-detect.js +0 -4
- package/dist/conversion/shared/errors.js +0 -31
- package/dist/conversion/shared/media.js +0 -4
- package/dist/conversion/shared/payload-budget.js +0 -165
- package/dist/conversion/shared/protocol-field-allowlists.d.ts +0 -7
- package/dist/conversion/shared/protocol-field-allowlists.js +0 -149
- package/dist/conversion/shared/snapshot-hooks.d.ts +0 -11
- package/dist/conversion/shared/snapshot-hooks.js +0 -503
- package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.d.ts +0 -2
- package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.js +0 -129
- package/dist/conversion/shared/text-markup-normalizer/extractors-json.d.ts +0 -4
- package/dist/conversion/shared/text-markup-normalizer/extractors-json.js +0 -637
- package/dist/conversion/shared/text-markup-normalizer/extractors-shared.d.ts +0 -21
- package/dist/conversion/shared/text-markup-normalizer/extractors-shared.js +0 -177
- package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.d.ts +0 -5
- package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.js +0 -385
- package/dist/conversion/shared/text-markup-normalizer/extractors-xml.d.ts +0 -10
- package/dist/conversion/shared/text-markup-normalizer/extractors-xml.js +0 -602
- package/dist/conversion/shared/text-markup-normalizer/extractors.d.ts +0 -5
- package/dist/conversion/shared/text-markup-normalizer/extractors.js +0 -4
- package/dist/conversion/shared/tool-canonicalizer.d.ts +0 -2
- package/dist/conversion/shared/tool-canonicalizer.js +0 -38
- /package/dist/conversion/{shared/args-mapping.d.ts → args-mapping.d.ts} +0 -0
- /package/dist/conversion/{shared/bridge-actions.d.ts → bridge-actions.d.ts} +0 -0
- /package/dist/conversion/{shared/bridge-id-utils.d.ts → bridge-id-utils.d.ts} +0 -0
- /package/dist/conversion/{shared/bridge-instructions.d.ts → bridge-instructions.d.ts} +0 -0
- /package/dist/conversion/{shared/bridge-metadata.d.ts → bridge-metadata.d.ts} +0 -0
- /package/dist/conversion/{shared/bridge-policies.d.ts → bridge-policies.d.ts} +0 -0
- /package/dist/conversion/{shared/jsonish.d.ts → jsonish.d.ts} +0 -0
- /package/dist/conversion/{shared/mcp-injection.d.ts → mcp-injection.d.ts} +0 -0
- /package/dist/conversion/{shared/media.d.ts → media.d.ts} +0 -0
- /package/dist/conversion/{shared/payload-budget.d.ts → payload-budget.d.ts} +0 -0
- /package/dist/conversion/{shared → types}/bridge-message-types.d.ts +0 -0
- /package/dist/conversion/{shared → types}/bridge-message-types.js +0 -0
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
export interface SnapshotHookOptions {
|
|
2
|
+
endpoint: string;
|
|
3
|
+
stage: string;
|
|
4
|
+
requestId: string;
|
|
5
|
+
data: unknown;
|
|
6
|
+
verbosity?: 'minimal' | 'verbose';
|
|
7
|
+
channel?: string;
|
|
8
|
+
providerKey?: string;
|
|
9
|
+
groupRequestId?: string;
|
|
10
|
+
}
|
|
1
11
|
interface SnapshotPayload {
|
|
2
12
|
stage: string;
|
|
3
13
|
requestId: string;
|
|
@@ -8,6 +18,7 @@ interface SnapshotPayload {
|
|
|
8
18
|
groupRequestId?: string;
|
|
9
19
|
}
|
|
10
20
|
export declare function shouldRecordSnapshots(): boolean;
|
|
21
|
+
export declare function writeSnapshotViaHooks(options: SnapshotHookOptions): Promise<void>;
|
|
11
22
|
export declare function recordSnapshot(options: SnapshotPayload): Promise<void>;
|
|
12
23
|
export type SnapshotWriter = (stage: string, payload: unknown) => void;
|
|
13
24
|
export declare function createSnapshotWriter(opts: {
|
|
@@ -1,27 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
function resolveBoolFromEnv(value, fallback) {
|
|
3
|
-
if (!value) {
|
|
4
|
-
return fallback;
|
|
5
|
-
}
|
|
6
|
-
const normalized = value.trim().toLowerCase();
|
|
7
|
-
if (['1', 'true', 'yes', 'on'].includes(normalized)) {
|
|
8
|
-
return true;
|
|
9
|
-
}
|
|
10
|
-
if (['0', 'false', 'no', 'off'].includes(normalized)) {
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
return fallback;
|
|
14
|
-
}
|
|
1
|
+
import { shouldRecordSnapshotsWithNative, writeSnapshotViaHooksWithNative } from '../router/virtual-router/engine-selection/native-snapshot-hooks.js';
|
|
15
2
|
export function shouldRecordSnapshots() {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
3
|
+
return shouldRecordSnapshotsWithNative();
|
|
4
|
+
}
|
|
5
|
+
export async function writeSnapshotViaHooks(options) {
|
|
6
|
+
writeSnapshotViaHooksWithNative({
|
|
7
|
+
endpoint: options.endpoint,
|
|
8
|
+
stage: options.stage,
|
|
9
|
+
requestId: options.requestId,
|
|
10
|
+
data: options.data,
|
|
11
|
+
verbosity: options.verbosity,
|
|
12
|
+
channel: options.channel,
|
|
13
|
+
providerKey: options.providerKey,
|
|
14
|
+
groupRequestId: options.groupRequestId
|
|
15
|
+
});
|
|
25
16
|
}
|
|
26
17
|
export async function recordSnapshot(options) {
|
|
27
18
|
if (!shouldRecordSnapshots())
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type JsonToolArgumentAliasMap = Record<string, string[]>;
|
|
2
|
+
export type JsonToolRepairConfig = {
|
|
3
|
+
toolNameAliases?: Record<string, string>;
|
|
4
|
+
argumentAliases?: Record<string, JsonToolArgumentAliasMap>;
|
|
5
|
+
};
|
|
6
|
+
export type TextMarkupNormalizeOptions = {
|
|
7
|
+
jsonToolRepair?: JsonToolRepairConfig;
|
|
8
|
+
};
|
|
9
|
+
export type ToolCallLite = {
|
|
10
|
+
id?: string;
|
|
11
|
+
name: string;
|
|
12
|
+
args: string;
|
|
13
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -26,7 +26,7 @@ export class RequestOpenAIToolsNormalizeFilter {
|
|
|
26
26
|
}
|
|
27
27
|
let normalizedList = [];
|
|
28
28
|
try {
|
|
29
|
-
const mod = await import('../../conversion/
|
|
29
|
+
const mod = await import('../../conversion/args-mapping.js');
|
|
30
30
|
const normalizeTools = mod?.normalizeTools;
|
|
31
31
|
if (typeof normalizeTools === 'function')
|
|
32
32
|
normalizedList = normalizeTools(tools);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeChatResponseReasoningToolsWithNative } from '../../router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js';
|
|
2
2
|
/**
|
|
3
3
|
* Canonicalize structured tool_calls (Chat path).
|
|
4
4
|
*
|
|
@@ -10,7 +10,7 @@ export class ResponseToolTextCanonicalizeFilter {
|
|
|
10
10
|
name = 'response_tool_text_canonicalize';
|
|
11
11
|
stage = 'response_pre';
|
|
12
12
|
apply(input) {
|
|
13
|
-
const out =
|
|
13
|
+
const out = normalizeChatResponseReasoningToolsWithNative(input);
|
|
14
14
|
return { ok: true, data: out };
|
|
15
15
|
}
|
|
16
16
|
}
|
|
Binary file
|
|
@@ -115,16 +115,6 @@ function collectUpstreamErrorSources(ev) {
|
|
|
115
115
|
function isAntigravityProviderKey(providerKey) {
|
|
116
116
|
return providerKey.toLowerCase().startsWith('antigravity.');
|
|
117
117
|
}
|
|
118
|
-
function resolveAntigravityRuntimeKey(providerKey, ev) {
|
|
119
|
-
const rtKey = safeTrim(ev?.runtime?.target?.runtimeKey);
|
|
120
|
-
if (rtKey)
|
|
121
|
-
return rtKey;
|
|
122
|
-
const parts = providerKey.split('.').filter(Boolean);
|
|
123
|
-
if (parts.length >= 2) {
|
|
124
|
-
return `${parts[0]}.${parts[1]}`;
|
|
125
|
-
}
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
118
|
function isGoogleAccountVerificationRequired(ev, sources) {
|
|
129
119
|
if (!sources.length) {
|
|
130
120
|
sources = collectUpstreamErrorSources(ev);
|
|
@@ -277,64 +267,46 @@ export class QuotaManager {
|
|
|
277
267
|
const code = safeTrim(ev.code) || safeTrim(ev?.runtime?.errorCode);
|
|
278
268
|
const details = ev.details && typeof ev.details === 'object' ? ev.details : undefined;
|
|
279
269
|
const state = this.ensureProvider(providerKey);
|
|
280
|
-
// Antigravity account-scope auth verification required:
|
|
270
|
+
// Antigravity account-scope auth verification required: isolate to current providerKey only.
|
|
281
271
|
if (isAntigravityProviderKey(providerKey)) {
|
|
282
272
|
const sources = collectUpstreamErrorSources(ev);
|
|
283
|
-
|
|
284
|
-
if (runtimeKey && isGoogleAccountVerificationRequired(ev, sources)) {
|
|
273
|
+
if (isGoogleAccountVerificationRequired(ev, sources)) {
|
|
285
274
|
const url = extractFirstUrl(sources);
|
|
286
275
|
const banUntil = nowMs + ANTIGRAVITY_AUTH_VERIFY_BAN_MS;
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
lastErrorSeries: 'EFATAL',
|
|
305
|
-
consecutiveErrorCount: 0
|
|
306
|
-
};
|
|
307
|
-
this.states.set(key, tickQuotaStateTime(next, nowMs));
|
|
308
|
-
}
|
|
276
|
+
const next = {
|
|
277
|
+
...state,
|
|
278
|
+
inPool: false,
|
|
279
|
+
reason: 'authVerify',
|
|
280
|
+
authIssue: {
|
|
281
|
+
kind: 'google_account_verification',
|
|
282
|
+
...(url ? { url } : {}),
|
|
283
|
+
message: 'account verification required'
|
|
284
|
+
},
|
|
285
|
+
blacklistUntil: Math.max(state.blacklistUntil ?? 0, banUntil) || banUntil,
|
|
286
|
+
cooldownUntil: null,
|
|
287
|
+
lastErrorAtMs: nowMs,
|
|
288
|
+
lastErrorCode: code || 'AUTH_VERIFY',
|
|
289
|
+
lastErrorSeries: 'EFATAL',
|
|
290
|
+
consecutiveErrorCount: 0
|
|
291
|
+
};
|
|
292
|
+
this.states.set(providerKey, tickQuotaStateTime(next, nowMs));
|
|
309
293
|
this.markDirty();
|
|
310
294
|
return;
|
|
311
295
|
}
|
|
312
|
-
// Thought signature missing:
|
|
296
|
+
// Thought signature missing: cooldown current providerKey only.
|
|
313
297
|
if (isThoughtSignatureMissing(ev, sources)) {
|
|
314
298
|
const freezeUntil = nowMs + ANTIGRAVITY_THOUGHT_SIGNATURE_MISSING_COOLDOWN_MS;
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const next = {
|
|
327
|
-
...s,
|
|
328
|
-
inPool: false,
|
|
329
|
-
reason: 'cooldown',
|
|
330
|
-
cooldownUntil: Math.max(s.cooldownUntil ?? 0, freezeUntil) || freezeUntil,
|
|
331
|
-
lastErrorAtMs: nowMs,
|
|
332
|
-
lastErrorCode: code || 'SIGNATURE_MISSING',
|
|
333
|
-
lastErrorSeries: 'EOTHER',
|
|
334
|
-
consecutiveErrorCount: 0
|
|
335
|
-
};
|
|
336
|
-
this.states.set(key, tickQuotaStateTime(next, nowMs));
|
|
337
|
-
}
|
|
299
|
+
const next = {
|
|
300
|
+
...state,
|
|
301
|
+
inPool: false,
|
|
302
|
+
reason: 'cooldown',
|
|
303
|
+
cooldownUntil: Math.max(state.cooldownUntil ?? 0, freezeUntil) || freezeUntil,
|
|
304
|
+
lastErrorAtMs: nowMs,
|
|
305
|
+
lastErrorCode: code || 'SIGNATURE_MISSING',
|
|
306
|
+
lastErrorSeries: 'EOTHER',
|
|
307
|
+
consecutiveErrorCount: 0
|
|
308
|
+
};
|
|
309
|
+
this.states.set(providerKey, tickQuotaStateTime(next, nowMs));
|
|
338
310
|
this.markDirty();
|
|
339
311
|
return;
|
|
340
312
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const COOLDOWN_SCHEDULE_429_MS = [
|
|
2
|
-
const COOLDOWN_SCHEDULE_FATAL_MS = [
|
|
3
|
-
const COOLDOWN_SCHEDULE_DEFAULT_MS = [
|
|
1
|
+
const COOLDOWN_SCHEDULE_429_MS = [3_000, 10_000, 31_000, 61_000];
|
|
2
|
+
const COOLDOWN_SCHEDULE_FATAL_MS = [3_000, 10_000, 31_000, 61_000];
|
|
3
|
+
const COOLDOWN_SCHEDULE_DEFAULT_MS = [3_000, 10_000, 31_000, 61_000];
|
|
4
4
|
const ERROR_CHAIN_WINDOW_MS = 10 * 60_000;
|
|
5
5
|
const NETWORK_ERROR_CODES = [
|
|
6
6
|
'ECONNRESET',
|
|
@@ -56,14 +56,21 @@ export function normalizeErrorSeries(event) {
|
|
|
56
56
|
}
|
|
57
57
|
function normalizeErrorKey(event) {
|
|
58
58
|
const rawCode = String(event.code || '').trim().toUpperCase();
|
|
59
|
-
|
|
59
|
+
const status = typeof event.httpStatus === 'number' ? event.httpStatus : null;
|
|
60
|
+
const isGenericCode = rawCode === '' ||
|
|
61
|
+
rawCode === 'ERR_PROVIDER_FAILURE' ||
|
|
62
|
+
rawCode === 'ERR_PIPELINE_FAILURE' ||
|
|
63
|
+
rawCode === 'ERR_COMPATIBILITY' ||
|
|
64
|
+
rawCode === 'EXTERNAL_ERROR' ||
|
|
65
|
+
rawCode === 'INTERNAL_ERROR' ||
|
|
66
|
+
rawCode === 'TOOL_ERROR';
|
|
67
|
+
if (!isGenericCode) {
|
|
60
68
|
return rawCode;
|
|
61
69
|
}
|
|
62
|
-
const status = typeof event.httpStatus === 'number' ? event.httpStatus : null;
|
|
63
70
|
if (status && Number.isFinite(status)) {
|
|
64
71
|
return `HTTP_${Math.floor(status)}`;
|
|
65
72
|
}
|
|
66
|
-
return 'ERR_UNKNOWN';
|
|
73
|
+
return rawCode || 'ERR_UNKNOWN';
|
|
67
74
|
}
|
|
68
75
|
function computeCooldownMsBySeries(series, consecutive) {
|
|
69
76
|
if (consecutive <= 0) {
|
|
@@ -125,12 +132,12 @@ export function applyErrorEvent(state, event, nowMs = event.timestampMs ?? Date.
|
|
|
125
132
|
nowMs - lastAt >= 0 &&
|
|
126
133
|
nowMs - lastAt <= ERROR_CHAIN_WINDOW_MS;
|
|
127
134
|
const sameErrorKey = withinChainWindow && state.lastErrorCode === errorKey;
|
|
128
|
-
const rawNextCount = sameErrorKey ? state.consecutiveErrorCount + 1 : 1;
|
|
129
135
|
const schedule = series === 'E429'
|
|
130
136
|
? COOLDOWN_SCHEDULE_429_MS
|
|
131
137
|
: series === 'EFATAL'
|
|
132
138
|
? COOLDOWN_SCHEDULE_FATAL_MS
|
|
133
139
|
: COOLDOWN_SCHEDULE_DEFAULT_MS;
|
|
140
|
+
const rawNextCount = sameErrorKey ? state.consecutiveErrorCount + 1 : 1;
|
|
134
141
|
const nextCount = rawNextCount > schedule.length ? 1 : rawNextCount;
|
|
135
142
|
const cooldownMs = computeCooldownMsBySeries(series, nextCount);
|
|
136
143
|
const nextUntil = cooldownMs ? nowMs + cooldownMs : null;
|
|
@@ -4,4 +4,5 @@ export declare function buildProviderProfiles(targetKeys: Set<string>, runtimeEn
|
|
|
4
4
|
targetRuntime: Record<string, ProviderRuntimeProfile>;
|
|
5
5
|
};
|
|
6
6
|
export declare function resolveContextTokens(runtime: ProviderRuntimeProfile, modelId: string): number;
|
|
7
|
+
export declare function resolveOutputTokens(runtime: ProviderRuntimeProfile, modelId: string): number | undefined;
|
|
7
8
|
export declare function normalizeHealth(input: unknown): ProviderHealthConfig | undefined;
|
|
@@ -16,6 +16,7 @@ export function buildProviderProfiles(targetKeys, runtimeEntries) {
|
|
|
16
16
|
? runtime.modelStreaming?.[parsed.modelId]
|
|
17
17
|
: runtime.streaming;
|
|
18
18
|
const contextTokens = resolveContextTokens(runtime, parsed.modelId);
|
|
19
|
+
const outputTokens = resolveOutputTokens(runtime, parsed.modelId);
|
|
19
20
|
profiles[targetKey] = {
|
|
20
21
|
providerKey: targetKey,
|
|
21
22
|
providerType: runtime.providerType,
|
|
@@ -28,6 +29,7 @@ export function buildProviderProfiles(targetKeys, runtimeEntries) {
|
|
|
28
29
|
processMode: runtime.processMode || 'chat',
|
|
29
30
|
responsesConfig: runtime.responsesConfig,
|
|
30
31
|
streaming: streamingPref,
|
|
32
|
+
maxOutputTokens: outputTokens,
|
|
31
33
|
maxContextTokens: contextTokens,
|
|
32
34
|
...(runtime.deepseek ? { deepseek: runtime.deepseek } : {}),
|
|
33
35
|
...(runtime.serverToolsDisabled ? { serverToolsDisabled: true } : {})
|
|
@@ -52,6 +54,17 @@ export function resolveContextTokens(runtime, modelId) {
|
|
|
52
54
|
}
|
|
53
55
|
return DEFAULT_MODEL_CONTEXT_TOKENS;
|
|
54
56
|
}
|
|
57
|
+
export function resolveOutputTokens(runtime, modelId) {
|
|
58
|
+
const specific = runtime.modelOutputTokens?.[modelId];
|
|
59
|
+
if (typeof specific === 'number' && Number.isFinite(specific) && specific > 0) {
|
|
60
|
+
return Math.floor(specific);
|
|
61
|
+
}
|
|
62
|
+
const fallback = runtime.defaultOutputTokens;
|
|
63
|
+
if (typeof fallback === 'number' && Number.isFinite(fallback) && fallback > 0) {
|
|
64
|
+
return Math.floor(fallback);
|
|
65
|
+
}
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
55
68
|
export function normalizeHealth(input) {
|
|
56
69
|
if (!input || typeof input !== 'object')
|
|
57
70
|
return undefined;
|
|
@@ -18,6 +18,8 @@ export interface NormalizedProvider {
|
|
|
18
18
|
responsesConfig?: ResponsesProviderConfig;
|
|
19
19
|
streaming?: 'always' | 'auto' | 'never';
|
|
20
20
|
modelStreaming?: Record<string, 'always' | 'auto' | 'never'>;
|
|
21
|
+
modelOutputTokens?: Record<string, number>;
|
|
22
|
+
defaultOutputTokens?: number;
|
|
21
23
|
modelContextTokens?: Record<string, number>;
|
|
22
24
|
defaultContextTokens?: number;
|
|
23
25
|
deepseek?: DeepSeekCompatRuntimeOptions;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { VirtualRouterError, VirtualRouterErrorCode } from '../types.js';
|
|
6
6
|
import { CLAUDE_CODE_DEFAULT_USER_AGENT, CLAUDE_CODE_DEFAULT_X_APP, CLAUDE_CODE_DEFAULT_ANTHROPIC_BETA, parseClaudeCodeAppVersionFromUserAgent } from './claude-code-helpers.js';
|
|
7
7
|
import { normalizeResponsesConfig, resolveProviderStreamingPreference } from './responses-helpers.js';
|
|
8
|
-
import { normalizeModelStreaming, normalizeModelContextTokens } from './streaming-helpers.js';
|
|
8
|
+
import { normalizeModelStreaming, normalizeModelContextTokens, normalizeModelOutputTokens } from './streaming-helpers.js';
|
|
9
9
|
/**
|
|
10
10
|
* Normalize a raw provider configuration into a NormalizedProvider.
|
|
11
11
|
*/
|
|
@@ -33,6 +33,7 @@ export function normalizeProvider(providerId, raw) {
|
|
|
33
33
|
const streaming = resolveProviderStreamingPreference(provider, responsesNode);
|
|
34
34
|
const modelStreaming = normalizeModelStreaming(provider);
|
|
35
35
|
const { modelContextTokens, defaultContextTokens } = normalizeModelContextTokens(provider);
|
|
36
|
+
const { modelOutputTokens, defaultOutputTokens } = normalizeModelOutputTokens(provider);
|
|
36
37
|
const deepseek = normalizeDeepSeekOptions(provider);
|
|
37
38
|
const serverToolsDisabled = provider.serverToolsDisabled === true ||
|
|
38
39
|
(typeof provider.serverToolsDisabled === 'string' &&
|
|
@@ -51,6 +52,8 @@ export function normalizeProvider(providerId, raw) {
|
|
|
51
52
|
responsesConfig,
|
|
52
53
|
streaming,
|
|
53
54
|
modelStreaming,
|
|
55
|
+
modelOutputTokens,
|
|
56
|
+
defaultOutputTokens,
|
|
54
57
|
modelContextTokens,
|
|
55
58
|
defaultContextTokens,
|
|
56
59
|
...(deepseek ? { deepseek } : {}),
|
|
@@ -10,3 +10,10 @@ export declare function normalizeModelContextTokens(provider: Record<string, unk
|
|
|
10
10
|
modelContextTokens?: Record<string, number>;
|
|
11
11
|
defaultContextTokens?: number;
|
|
12
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Normalize model-level output token limits (maxTokens / max_output_tokens).
|
|
15
|
+
*/
|
|
16
|
+
export declare function normalizeModelOutputTokens(provider: Record<string, unknown>): {
|
|
17
|
+
modelOutputTokens?: Record<string, number>;
|
|
18
|
+
defaultOutputTokens?: number;
|
|
19
|
+
};
|
|
@@ -83,6 +83,29 @@ export function normalizeModelContextTokens(provider) {
|
|
|
83
83
|
defaultContextTokens: defaultCandidate
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Normalize model-level output token limits (maxTokens / max_output_tokens).
|
|
88
|
+
*/
|
|
89
|
+
export function normalizeModelOutputTokens(provider) {
|
|
90
|
+
const modelsNode = asRecord(provider.models);
|
|
91
|
+
const normalized = {};
|
|
92
|
+
for (const [modelId, modelRaw] of Object.entries(modelsNode)) {
|
|
93
|
+
if (!modelRaw || typeof modelRaw !== 'object') {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const candidate = readOutputTokens(modelRaw);
|
|
97
|
+
if (candidate) {
|
|
98
|
+
normalized[modelId] = candidate;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const configNode = asRecord(provider.config);
|
|
102
|
+
const defaultsNode = asRecord(configNode?.userConfigDefaults);
|
|
103
|
+
const defaultCandidate = readOutputTokens(provider) ?? readOutputTokens(configNode) ?? readOutputTokens(defaultsNode);
|
|
104
|
+
return {
|
|
105
|
+
modelOutputTokens: Object.keys(normalized).length ? normalized : undefined,
|
|
106
|
+
defaultOutputTokens: defaultCandidate
|
|
107
|
+
};
|
|
108
|
+
}
|
|
86
109
|
/**
|
|
87
110
|
* Read context tokens from various field names.
|
|
88
111
|
*/
|
|
@@ -107,6 +130,27 @@ function readContextTokens(record) {
|
|
|
107
130
|
}
|
|
108
131
|
return undefined;
|
|
109
132
|
}
|
|
133
|
+
function readOutputTokens(record) {
|
|
134
|
+
if (!record) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
const keys = [
|
|
138
|
+
'maxOutputTokens',
|
|
139
|
+
'max_output_tokens',
|
|
140
|
+
'maxTokens',
|
|
141
|
+
'max_tokens',
|
|
142
|
+
'outputTokens',
|
|
143
|
+
'output_tokens'
|
|
144
|
+
];
|
|
145
|
+
for (const key of keys) {
|
|
146
|
+
const value = record[key];
|
|
147
|
+
const parsed = normalizePositiveInteger(value);
|
|
148
|
+
if (parsed) {
|
|
149
|
+
return parsed;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
110
154
|
/**
|
|
111
155
|
* Normalize positive integer value.
|
|
112
156
|
*/
|
|
@@ -129,6 +129,8 @@ function buildProviderRuntimeEntries(providers) {
|
|
|
129
129
|
responsesConfig: normalizedProvider.responsesConfig,
|
|
130
130
|
streaming: normalizedProvider.streaming,
|
|
131
131
|
modelStreaming: normalizedProvider.modelStreaming,
|
|
132
|
+
modelOutputTokens: normalizedProvider.modelOutputTokens,
|
|
133
|
+
defaultOutputTokens: normalizedProvider.defaultOutputTokens,
|
|
132
134
|
modelContextTokens: normalizedProvider.modelContextTokens,
|
|
133
135
|
defaultContextTokens: normalizedProvider.defaultContextTokens,
|
|
134
136
|
...(normalizedProvider.deepseek ? { deepseek: normalizedProvider.deepseek } : {}),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RouterMetadataInput } from '../../types.js';
|
|
2
2
|
import type { RoutingInstructionState } from '../../routing-instructions.js';
|
|
3
|
-
type RoutingInstructionStateStoreLike = {
|
|
3
|
+
export type RoutingInstructionStateStoreLike = {
|
|
4
4
|
loadSync: (key: string) => RoutingInstructionState | null;
|
|
5
5
|
saveAsync: (key: string, state: RoutingInstructionState | null) => void;
|
|
6
6
|
saveSync?: (key: string, state: RoutingInstructionState | null) => void;
|
|
@@ -8,4 +8,3 @@ type RoutingInstructionStateStoreLike = {
|
|
|
8
8
|
export declare function resolveStopMessageScope(metadata: RouterMetadataInput): string | undefined;
|
|
9
9
|
export declare function getRoutingInstructionState(stickyKey: string | undefined, routingInstructionState: Map<string, RoutingInstructionState>, routingStateStore: RoutingInstructionStateStoreLike): RoutingInstructionState;
|
|
10
10
|
export declare function persistRoutingInstructionState(key: string, state: RoutingInstructionState, routingStateStore: RoutingInstructionStateStoreLike): void;
|
|
11
|
-
export {};
|
|
@@ -32,7 +32,7 @@ export function resolveStopMessageScope(metadata) {
|
|
|
32
32
|
export function getRoutingInstructionState(stickyKey, routingInstructionState, routingStateStore) {
|
|
33
33
|
const key = stickyKey || 'default';
|
|
34
34
|
const existing = routingInstructionState.get(key);
|
|
35
|
-
// 对 session:/conversation: 作用域,在每次读取时尝试从磁盘刷新 stopMessage 相关字段,
|
|
35
|
+
// 对 session:/conversation:/tmux: 作用域,在每次读取时尝试从磁盘刷新 stopMessage 相关字段,
|
|
36
36
|
// 确保 servertool(如 stop_message_auto)通过 sticky-session-store 更新的使用次数
|
|
37
37
|
// 能在 VirtualRouter 日志中实时反映出来。
|
|
38
38
|
if (existing && isPersistentScopeKey(key)) {
|
|
@@ -61,7 +61,7 @@ export function getRoutingInstructionState(stickyKey, routingInstructionState, r
|
|
|
61
61
|
return existing;
|
|
62
62
|
}
|
|
63
63
|
let initial = null;
|
|
64
|
-
// 仅对 session:/conversation: 作用域的 key 尝试从磁盘恢复持久化状态
|
|
64
|
+
// 仅对 session:/conversation:/tmux: 作用域的 key 尝试从磁盘恢复持久化状态
|
|
65
65
|
if (isPersistentScopeKey(key)) {
|
|
66
66
|
initial = routingStateStore.loadSync(key);
|
|
67
67
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ProviderQuotaView } from '../types.js';
|
|
2
|
+
import type { VirtualRouterConfig, VirtualRouterHealthStore } from '../types.js';
|
|
3
|
+
import type { RoutingInstructionStateStoreLike } from '../engine/routing-state/store.js';
|
|
4
|
+
import type { VirtualRouterEngine } from '../engine-legacy.js';
|
|
5
|
+
export declare function updateDeps(engine: VirtualRouterEngine, deps: {
|
|
6
|
+
healthStore?: VirtualRouterHealthStore | null;
|
|
7
|
+
routingStateStore?: RoutingInstructionStateStoreLike | null;
|
|
8
|
+
quotaView?: ProviderQuotaView | null;
|
|
9
|
+
}): void;
|
|
10
|
+
export declare function initialize(engine: VirtualRouterEngine, config: VirtualRouterConfig): void;
|
|
11
|
+
export declare function validateConfig(engine: VirtualRouterEngine, config: VirtualRouterConfig): void;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { RouteLoadBalancer } from '../load-balancer.js';
|
|
2
|
+
import { StickySessionManager } from '../engine/sticky-session-manager.js';
|
|
3
|
+
import { RoutingClassifier } from '../classifier.js';
|
|
4
|
+
import { loadRoutingInstructionStateSync, saveRoutingInstructionStateAsync, saveRoutingInstructionStateSync } from '../sticky-session-store.js';
|
|
5
|
+
import { resolveAntigravityAliasReuseCooldownMs, hydrateAntigravityAliasLeaseStoreIfNeeded } from '../engine/antigravity/alias-lease.js';
|
|
6
|
+
import { routeHasTargets, hasPrimaryPool } from './route-utils.js';
|
|
7
|
+
import { DEFAULT_ROUTE, VirtualRouterError, VirtualRouterErrorCode } from '../types.js';
|
|
8
|
+
export function updateDeps(engine, deps) {
|
|
9
|
+
if (!deps || typeof deps !== 'object') {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if ('healthStore' in deps) {
|
|
13
|
+
engine.healthStore = deps.healthStore ?? undefined;
|
|
14
|
+
engine.cooldownManager.updateDeps({ healthStore: engine.healthStore });
|
|
15
|
+
}
|
|
16
|
+
if ('routingStateStore' in deps) {
|
|
17
|
+
engine.routingStateStore =
|
|
18
|
+
deps.routingStateStore ??
|
|
19
|
+
{
|
|
20
|
+
loadSync: loadRoutingInstructionStateSync,
|
|
21
|
+
saveAsync: saveRoutingInstructionStateAsync,
|
|
22
|
+
saveSync: saveRoutingInstructionStateSync
|
|
23
|
+
};
|
|
24
|
+
// Routing state store changes require clearing in-memory cache to avoid stale reads.
|
|
25
|
+
engine.routingInstructionState.clear();
|
|
26
|
+
}
|
|
27
|
+
if ('quotaView' in deps) {
|
|
28
|
+
const prevQuotaEnabled = Boolean(engine.quotaView);
|
|
29
|
+
engine.quotaView = deps.quotaView ?? undefined;
|
|
30
|
+
engine.cooldownManager.updateDeps({ quotaView: engine.quotaView });
|
|
31
|
+
const nextQuotaEnabled = Boolean(engine.quotaView);
|
|
32
|
+
// When quotaView is enabled, health/cooldown decisions must be driven by quotaView only.
|
|
33
|
+
// - Enabling quotaView: clear any legacy router-local cooldown TTLs immediately.
|
|
34
|
+
// - Disabling quotaView: reload legacy cooldown state from health snapshots.
|
|
35
|
+
if (!prevQuotaEnabled && nextQuotaEnabled) {
|
|
36
|
+
engine.cooldownManager.clearAllCooldowns();
|
|
37
|
+
}
|
|
38
|
+
else if (prevQuotaEnabled && !nextQuotaEnabled) {
|
|
39
|
+
engine.cooldownManager.clearAllCooldowns();
|
|
40
|
+
engine.restoreHealthFromStore();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function initialize(engine, config) {
|
|
45
|
+
validateConfig(engine, config);
|
|
46
|
+
engine.routing = config.routing;
|
|
47
|
+
engine.providerRegistry.load(config.providers);
|
|
48
|
+
engine.healthManager.configure(config.health);
|
|
49
|
+
engine.healthConfig = config.health ?? null;
|
|
50
|
+
engine.healthManager.registerProviders(Object.keys(config.providers));
|
|
51
|
+
engine.cooldownManager.clearAllCooldowns();
|
|
52
|
+
engine.restoreHealthFromStore();
|
|
53
|
+
engine.loadBalancer = new RouteLoadBalancer(config.loadBalancing);
|
|
54
|
+
const aliasReuseCooldownMs = resolveAntigravityAliasReuseCooldownMs(config);
|
|
55
|
+
engine.stickySessionManager = new StickySessionManager(aliasReuseCooldownMs);
|
|
56
|
+
hydrateAntigravityAliasLeaseStoreIfNeeded({
|
|
57
|
+
force: true,
|
|
58
|
+
leaseStore: engine.stickySessionManager.getAllStores().aliasLeaseStore,
|
|
59
|
+
persistence: engine.antigravityLeasePersistence,
|
|
60
|
+
aliasReuseCooldownMs: engine.stickySessionManager.getAliasReuseCooldownMs()
|
|
61
|
+
});
|
|
62
|
+
engine.classifier = new RoutingClassifier(config.classifier);
|
|
63
|
+
engine.contextRouting = config.contextRouting ?? { warnRatio: 0.9, hardLimit: false };
|
|
64
|
+
engine.contextAdvisor.configure(engine.contextRouting);
|
|
65
|
+
engine.webSearchForce = config.webSearch?.force === true;
|
|
66
|
+
engine.routeAnalytics.getAllRouteStats().clear();
|
|
67
|
+
for (const routeName of Object.keys(engine.routing)) {
|
|
68
|
+
engine.routeAnalytics.getRouteStats(routeName) ||
|
|
69
|
+
engine.routeAnalytics.incrementRouteStat(routeName, '', {
|
|
70
|
+
timestampMs: Date.now(),
|
|
71
|
+
stopMessage: { active: false }
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export function validateConfig(engine, config) {
|
|
76
|
+
if (!config.routing || typeof config.routing !== 'object') {
|
|
77
|
+
throw new VirtualRouterError('routing configuration is required', VirtualRouterErrorCode.CONFIG_ERROR);
|
|
78
|
+
}
|
|
79
|
+
if (!config.providers || Object.keys(config.providers).length === 0) {
|
|
80
|
+
throw new VirtualRouterError('providers configuration is required', VirtualRouterErrorCode.CONFIG_ERROR);
|
|
81
|
+
}
|
|
82
|
+
const defaultPools = config.routing[DEFAULT_ROUTE];
|
|
83
|
+
if (!routeHasTargets(engine, defaultPools)) {
|
|
84
|
+
throw new VirtualRouterError('default route must be configured with at least one provider', VirtualRouterErrorCode.CONFIG_ERROR);
|
|
85
|
+
}
|
|
86
|
+
if (!hasPrimaryPool(engine, defaultPools)) {
|
|
87
|
+
throw new VirtualRouterError('default route must define at least one non-backup pool', VirtualRouterErrorCode.CONFIG_ERROR);
|
|
88
|
+
}
|
|
89
|
+
const providerKeys = new Set(Object.keys(config.providers));
|
|
90
|
+
for (const [routeName, pools] of Object.entries(config.routing)) {
|
|
91
|
+
if (!routeHasTargets(engine, pools)) {
|
|
92
|
+
if (routeName === DEFAULT_ROUTE) {
|
|
93
|
+
throw new VirtualRouterError('default route cannot be empty', VirtualRouterErrorCode.CONFIG_ERROR);
|
|
94
|
+
}
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
for (const pool of pools) {
|
|
98
|
+
if (!Array.isArray(pool.targets) || !pool.targets.length) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
for (const providerKey of pool.targets) {
|
|
102
|
+
if (!providerKeys.has(providerKey)) {
|
|
103
|
+
throw new VirtualRouterError(`Route ${routeName} references unknown provider ${providerKey}`, VirtualRouterErrorCode.CONFIG_ERROR);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RoutingFeatures } from '../types.js';
|
|
2
|
+
import type { VirtualRouterEngine } from '../engine-legacy.js';
|
|
3
|
+
export declare function parseDirectProviderModel(engine: VirtualRouterEngine, model: string | undefined): {
|
|
4
|
+
providerId: string;
|
|
5
|
+
modelId: string;
|
|
6
|
+
} | null;
|
|
7
|
+
export declare function shouldFallbackDirectModelForMedia(engine: VirtualRouterEngine, direct: {
|
|
8
|
+
providerId: string;
|
|
9
|
+
modelId: string;
|
|
10
|
+
}, features: RoutingFeatures): boolean;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { routeHasTargets } from './route-utils.js';
|
|
2
|
+
export function parseDirectProviderModel(engine, model) {
|
|
3
|
+
const raw = typeof model === 'string' ? model.trim() : '';
|
|
4
|
+
if (!raw) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
const firstDot = raw.indexOf('.');
|
|
8
|
+
if (firstDot <= 0 || firstDot === raw.length - 1) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const providerId = raw.slice(0, firstDot).trim();
|
|
12
|
+
const modelId = raw.slice(firstDot + 1).trim();
|
|
13
|
+
if (!providerId || !modelId) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
if (engine.providerRegistry.listProviderKeys(providerId).length === 0) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return { providerId, modelId };
|
|
20
|
+
}
|
|
21
|
+
export function shouldFallbackDirectModelForMedia(engine, direct, features) {
|
|
22
|
+
if (!features.hasImageAttachment) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const providerId = direct.providerId.trim().toLowerCase();
|
|
26
|
+
const modelId = direct.modelId.trim().toLowerCase();
|
|
27
|
+
if (providerId !== 'qwen') {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const isQwen35Plus = modelId === 'qwen3.5-plus' || modelId === 'qwen3-5-plus' || modelId === 'qwen3_5-plus';
|
|
31
|
+
if (!isQwen35Plus) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
if (!(features.hasVideoAttachment === true && features.hasLocalVideoAttachment === true)) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return routeHasTargets(engine, engine.routing.vision);
|
|
38
|
+
}
|