@jsonstudio/llms 0.6.1892 → 0.6.2172
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/conversion/compat/actions/deepseek-web-request.js +16 -2
- package/dist/conversion/compat/actions/deepseek-web-response.d.ts +7 -1
- package/dist/conversion/compat/actions/deepseek-web-response.js +302 -40
- package/dist/conversion/compat/actions/harvest-tool-calls-from-text.d.ts +5 -0
- package/dist/conversion/compat/actions/harvest-tool-calls-from-text.js +7 -4
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.d.ts +1 -0
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.js +12 -0
- package/dist/conversion/compat/actions/strip-orphan-function-calls-tag.js +1 -1
- package/dist/conversion/compat/actions/tool-text-request-guidance.d.ts +9 -0
- package/dist/conversion/compat/actions/tool-text-request-guidance.js +177 -0
- package/dist/conversion/compat/antigravity-session-signature.d.ts +6 -0
- package/dist/conversion/compat/antigravity-session-signature.js +15 -0
- package/dist/conversion/compat/profiles/chat-deepseek-web.json +52 -1
- package/dist/conversion/compat/profiles/chat-glm.json +22 -0
- package/dist/conversion/compat/profiles/chat-iflow.json +4 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +13 -27
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +10 -1
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +13 -4
- package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.js +1 -53
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +8 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +8 -4
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +191 -9
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +118 -15
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +65 -2
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.d.ts +34 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.js +75 -0
- package/dist/conversion/hub/process/chat-process.js +85 -18
- package/dist/conversion/hub/response/provider-response.js +21 -50
- package/dist/conversion/hub/response/response-runtime.js +71 -10
- package/dist/conversion/responses/responses-openai-bridge/response-payload.d.ts +3 -0
- package/dist/conversion/responses/responses-openai-bridge/response-payload.js +576 -0
- package/dist/conversion/responses/responses-openai-bridge/types.d.ts +42 -0
- package/dist/conversion/responses/responses-openai-bridge/types.js +1 -0
- package/dist/conversion/responses/responses-openai-bridge.d.ts +3 -44
- package/dist/conversion/responses/responses-openai-bridge.js +193 -504
- package/dist/conversion/shared/anthropic-message-utils.js +82 -2
- package/dist/conversion/shared/bridge-message-utils.js +92 -39
- package/dist/conversion/shared/snapshot-hooks.js +8 -13
- package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.d.ts +2 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.js +129 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-json.d.ts +4 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-json.js +637 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-shared.d.ts +21 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-shared.js +177 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.d.ts +5 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.js +385 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-xml.d.ts +10 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors-xml.js +602 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors.d.ts +5 -0
- package/dist/conversion/shared/text-markup-normalizer/extractors.js +4 -0
- package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +2 -0
- package/dist/conversion/shared/text-markup-normalizer/normalize.js +76 -0
- package/dist/conversion/shared/text-markup-normalizer.d.ts +3 -25
- package/dist/conversion/shared/text-markup-normalizer.js +2 -1386
- package/dist/conversion/shared/tool-governor.js +136 -10
- package/dist/filters/utils/snapshot-writer.js +3 -3
- package/dist/router/virtual-router/bootstrap/auth-utils.d.ts +6 -0
- package/dist/router/virtual-router/bootstrap/auth-utils.js +288 -0
- package/dist/router/virtual-router/bootstrap/claude-code-helpers.d.ts +11 -0
- package/dist/router/virtual-router/bootstrap/claude-code-helpers.js +18 -0
- package/dist/router/virtual-router/bootstrap/config-defaults.d.ts +5 -0
- package/dist/router/virtual-router/bootstrap/config-defaults.js +13 -0
- package/dist/router/virtual-router/bootstrap/config-normalizers.d.ts +4 -0
- package/dist/router/virtual-router/bootstrap/config-normalizers.js +106 -0
- package/dist/router/virtual-router/bootstrap/profile-builder.d.ts +7 -0
- package/dist/router/virtual-router/bootstrap/profile-builder.js +68 -0
- package/dist/router/virtual-router/bootstrap/provider-normalization.d.ts +40 -0
- package/dist/router/virtual-router/bootstrap/provider-normalization.js +212 -0
- package/dist/router/virtual-router/bootstrap/responses-helpers.d.ts +15 -0
- package/dist/router/virtual-router/bootstrap/responses-helpers.js +65 -0
- package/dist/router/virtual-router/bootstrap/routing-config.d.ts +23 -0
- package/dist/router/virtual-router/bootstrap/routing-config.js +293 -0
- package/dist/router/virtual-router/bootstrap/streaming-helpers.d.ts +12 -0
- package/dist/router/virtual-router/bootstrap/streaming-helpers.js +128 -0
- package/dist/router/virtual-router/bootstrap/utils.d.ts +5 -0
- package/dist/router/virtual-router/bootstrap/utils.js +41 -0
- package/dist/router/virtual-router/bootstrap/web-search-config.d.ts +4 -0
- package/dist/router/virtual-router/bootstrap/web-search-config.js +131 -0
- package/dist/router/virtual-router/bootstrap.d.ts +0 -4
- package/dist/router/virtual-router/bootstrap.js +31 -1275
- package/dist/router/virtual-router/classifier.js +32 -14
- package/dist/router/virtual-router/engine/antigravity/alias-lease.js +2 -2
- package/dist/router/virtual-router/engine/cooldown-manager.d.ts +34 -0
- package/dist/router/virtual-router/engine/cooldown-manager.js +118 -0
- package/dist/router/virtual-router/engine/route-analytics.d.ts +28 -0
- package/dist/router/virtual-router/engine/route-analytics.js +44 -0
- package/dist/router/virtual-router/engine/routing-pools/index.js +165 -4
- package/dist/router/virtual-router/engine/sticky-session-manager.d.ts +29 -0
- package/dist/router/virtual-router/engine/sticky-session-manager.js +55 -0
- package/dist/router/virtual-router/engine-logging.d.ts +42 -1
- package/dist/router/virtual-router/engine-logging.js +82 -15
- package/dist/router/virtual-router/engine-selection/multimodal-capability.d.ts +3 -0
- package/dist/router/virtual-router/engine-selection/multimodal-capability.js +26 -0
- package/dist/router/virtual-router/engine-selection/route-utils.js +6 -2
- package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +1 -0
- package/dist/router/virtual-router/engine-selection/tier-selection.js +31 -1
- package/dist/router/virtual-router/engine.d.ts +21 -7
- package/dist/router/virtual-router/engine.js +198 -194
- package/dist/router/virtual-router/features.js +12 -4
- package/dist/router/virtual-router/message-utils.d.ts +8 -0
- package/dist/router/virtual-router/message-utils.js +170 -45
- package/dist/router/virtual-router/pre-command-file-resolver.js +40 -2
- package/dist/router/virtual-router/routing-instructions.d.ts +8 -0
- package/dist/router/virtual-router/routing-instructions.js +18 -2
- package/dist/router/virtual-router/routing-stop-message-actions.js +34 -10
- package/dist/router/virtual-router/routing-stop-message-state-codec.d.ts +2 -0
- package/dist/router/virtual-router/routing-stop-message-state-codec.js +50 -1
- package/dist/router/virtual-router/stop-message-state-sync.d.ts +1 -1
- package/dist/router/virtual-router/stop-message-state-sync.js +3 -0
- package/dist/router/virtual-router/token-counter.js +51 -10
- package/dist/router/virtual-router/tool-signals.js +4 -0
- package/dist/router/virtual-router/types.d.ts +15 -0
- package/dist/servertool/clock/session-scope.d.ts +3 -0
- package/dist/servertool/clock/session-scope.js +52 -0
- package/dist/servertool/clock/state.js +9 -0
- package/dist/servertool/clock/tasks.js +12 -1
- package/dist/servertool/clock/types.d.ts +3 -0
- package/dist/servertool/engine.js +177 -31
- package/dist/servertool/handlers/clock-auto.js +2 -8
- package/dist/servertool/handlers/clock.js +6 -9
- package/dist/servertool/handlers/recursive-detection-guard.js +53 -14
- package/dist/servertool/handlers/stop-message-auto/blocked-report.d.ts +16 -0
- package/dist/servertool/handlers/stop-message-auto/blocked-report.js +349 -0
- package/dist/servertool/handlers/stop-message-auto/iflow-followup.d.ts +23 -0
- package/dist/servertool/handlers/stop-message-auto/iflow-followup.js +503 -0
- package/dist/servertool/handlers/stop-message-auto/routing-state.d.ts +38 -0
- package/dist/servertool/handlers/stop-message-auto/routing-state.js +149 -0
- package/dist/servertool/handlers/stop-message-auto/runtime-utils.d.ts +67 -0
- package/dist/servertool/handlers/stop-message-auto/runtime-utils.js +387 -0
- package/dist/servertool/handlers/stop-message-auto.d.ts +1 -1
- package/dist/servertool/handlers/stop-message-auto.js +80 -556
- package/dist/servertool/handlers/stop-message-stage-policy/bd-runtime.d.ts +18 -0
- package/dist/servertool/handlers/stop-message-stage-policy/bd-runtime.js +398 -0
- package/dist/servertool/handlers/stop-message-stage-policy/decision.d.ts +9 -0
- package/dist/servertool/handlers/stop-message-stage-policy/decision.js +127 -0
- package/dist/servertool/handlers/stop-message-stage-policy/observation.d.ts +2 -0
- package/dist/servertool/handlers/stop-message-stage-policy/observation.js +179 -0
- package/dist/servertool/handlers/stop-message-stage-policy/templates.d.ts +4 -0
- package/dist/servertool/handlers/stop-message-stage-policy/templates.js +96 -0
- package/dist/servertool/handlers/stop-message-stage-policy/text-utils.d.ts +9 -0
- package/dist/servertool/handlers/stop-message-stage-policy/text-utils.js +89 -0
- package/dist/servertool/handlers/stop-message-stage-policy/types.d.ts +59 -0
- package/dist/servertool/handlers/stop-message-stage-policy/types.js +1 -0
- package/dist/servertool/handlers/stop-message-stage-policy.d.ts +3 -43
- package/dist/servertool/handlers/stop-message-stage-policy.js +2 -684
- package/dist/servertool/handlers/web-search.js +117 -0
- package/dist/servertool/server-side-tools.d.ts +0 -1
- package/dist/servertool/server-side-tools.js +4 -3
- package/dist/sse/sse-to-json/builders/response-builder.js +16 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +1 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +110 -37
- package/dist/telemetry/stats-center.d.ts +9 -0
- package/dist/telemetry/stats-center.js +29 -1
- package/dist/tools/apply-patch/structured/coercion.js +3 -11
- package/dist/tools/exec-command/validator.d.ts +1 -0
- package/dist/tools/exec-command/validator.js +132 -0
- package/dist/tools/tool-registry.d.ts +1 -0
- package/dist/tools/tool-registry.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { DEFAULT_MODEL_CONTEXT_TOKENS, VirtualRouterError, VirtualRouterErrorCode } from '../types.js';
|
|
2
|
+
import { buildRuntimeKey, parseTargetKey } from './routing-config.js';
|
|
3
|
+
export function buildProviderProfiles(targetKeys, runtimeEntries) {
|
|
4
|
+
const profiles = {};
|
|
5
|
+
const targetRuntime = {};
|
|
6
|
+
for (const targetKey of targetKeys) {
|
|
7
|
+
const parsed = parseTargetKey(targetKey);
|
|
8
|
+
if (!parsed)
|
|
9
|
+
continue;
|
|
10
|
+
const runtimeKey = buildRuntimeKey(parsed.providerId, parsed.keyAlias);
|
|
11
|
+
const runtime = runtimeEntries[runtimeKey];
|
|
12
|
+
if (!runtime) {
|
|
13
|
+
throw new VirtualRouterError(`Routing target ${targetKey} references unknown runtime key ${runtimeKey}`, VirtualRouterErrorCode.CONFIG_ERROR);
|
|
14
|
+
}
|
|
15
|
+
const streamingPref = runtime.modelStreaming?.[parsed.modelId] !== undefined
|
|
16
|
+
? runtime.modelStreaming?.[parsed.modelId]
|
|
17
|
+
: runtime.streaming;
|
|
18
|
+
const contextTokens = resolveContextTokens(runtime, parsed.modelId);
|
|
19
|
+
profiles[targetKey] = {
|
|
20
|
+
providerKey: targetKey,
|
|
21
|
+
providerType: runtime.providerType,
|
|
22
|
+
endpoint: runtime.endpoint,
|
|
23
|
+
auth: { ...runtime.auth },
|
|
24
|
+
outboundProfile: runtime.outboundProfile,
|
|
25
|
+
compatibilityProfile: runtime.compatibilityProfile,
|
|
26
|
+
runtimeKey,
|
|
27
|
+
modelId: parsed.modelId,
|
|
28
|
+
processMode: runtime.processMode || 'chat',
|
|
29
|
+
responsesConfig: runtime.responsesConfig,
|
|
30
|
+
streaming: streamingPref,
|
|
31
|
+
maxContextTokens: contextTokens,
|
|
32
|
+
...(runtime.deepseek ? { deepseek: runtime.deepseek } : {}),
|
|
33
|
+
...(runtime.serverToolsDisabled ? { serverToolsDisabled: true } : {})
|
|
34
|
+
};
|
|
35
|
+
targetRuntime[targetKey] = {
|
|
36
|
+
...runtime,
|
|
37
|
+
modelId: parsed.modelId,
|
|
38
|
+
streaming: streamingPref,
|
|
39
|
+
maxContextTokens: contextTokens
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return { profiles, targetRuntime };
|
|
43
|
+
}
|
|
44
|
+
export function resolveContextTokens(runtime, modelId) {
|
|
45
|
+
const specific = runtime.modelContextTokens?.[modelId];
|
|
46
|
+
if (typeof specific === 'number' && Number.isFinite(specific) && specific > 0) {
|
|
47
|
+
return Math.floor(specific);
|
|
48
|
+
}
|
|
49
|
+
const fallback = runtime.defaultContextTokens ?? runtime.maxContextTokens;
|
|
50
|
+
if (typeof fallback === 'number' && Number.isFinite(fallback) && fallback > 0) {
|
|
51
|
+
return Math.floor(fallback);
|
|
52
|
+
}
|
|
53
|
+
return DEFAULT_MODEL_CONTEXT_TOKENS;
|
|
54
|
+
}
|
|
55
|
+
export function normalizeHealth(input) {
|
|
56
|
+
if (!input || typeof input !== 'object')
|
|
57
|
+
return undefined;
|
|
58
|
+
const record = input;
|
|
59
|
+
const failureThreshold = typeof record.failureThreshold === 'number' ? record.failureThreshold : undefined;
|
|
60
|
+
const cooldownMs = typeof record.cooldownMs === 'number' ? record.cooldownMs : undefined;
|
|
61
|
+
const fatalCooldownMs = typeof record.fatalCooldownMs === 'number' ? record.fatalCooldownMs : undefined;
|
|
62
|
+
if (typeof failureThreshold !== 'number' || typeof cooldownMs !== 'number') {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return fatalCooldownMs !== undefined
|
|
66
|
+
? { failureThreshold, cooldownMs, fatalCooldownMs }
|
|
67
|
+
: { failureThreshold, cooldownMs };
|
|
68
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider normalization logic for Virtual Router bootstrap.
|
|
3
|
+
* Extracted from bootstrap.ts to improve modularity and testability.
|
|
4
|
+
*/
|
|
5
|
+
import { type ProviderAuthConfig, type ProviderRuntimeProfile, type DeepSeekCompatRuntimeOptions, type ResponsesProviderConfig } from '../types.js';
|
|
6
|
+
export interface ProviderAuthEntry {
|
|
7
|
+
keyAlias: string;
|
|
8
|
+
auth: ProviderAuthConfig;
|
|
9
|
+
}
|
|
10
|
+
export interface NormalizedProvider {
|
|
11
|
+
providerId: string;
|
|
12
|
+
providerType: string;
|
|
13
|
+
endpoint: string;
|
|
14
|
+
headers?: Record<string, string>;
|
|
15
|
+
outboundProfile: string;
|
|
16
|
+
compatibilityProfile: string;
|
|
17
|
+
processMode: 'chat' | 'passthrough';
|
|
18
|
+
responsesConfig?: ResponsesProviderConfig;
|
|
19
|
+
streaming?: 'always' | 'auto' | 'never';
|
|
20
|
+
modelStreaming?: Record<string, 'always' | 'auto' | 'never'>;
|
|
21
|
+
modelContextTokens?: Record<string, number>;
|
|
22
|
+
defaultContextTokens?: number;
|
|
23
|
+
deepseek?: DeepSeekCompatRuntimeOptions;
|
|
24
|
+
serverToolsDisabled?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface ProviderRuntimeBuildResult {
|
|
27
|
+
runtimeEntries: Record<string, ProviderRuntimeProfile>;
|
|
28
|
+
aliasIndex: Map<string, string[]>;
|
|
29
|
+
modelIndex: Map<string, {
|
|
30
|
+
declared: boolean;
|
|
31
|
+
models: string[];
|
|
32
|
+
}>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Normalize a raw provider configuration into a NormalizedProvider.
|
|
36
|
+
*/
|
|
37
|
+
export declare function normalizeProvider(providerId: string, raw: unknown): NormalizedProvider;
|
|
38
|
+
export declare function detectProviderType(provider: Record<string, unknown>): string;
|
|
39
|
+
export declare function mapOutboundProfile(providerType: string): string;
|
|
40
|
+
export declare function normalizeHeaders(input: unknown): Record<string, string> | undefined;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider normalization logic for Virtual Router bootstrap.
|
|
3
|
+
* Extracted from bootstrap.ts to improve modularity and testability.
|
|
4
|
+
*/
|
|
5
|
+
import { VirtualRouterError, VirtualRouterErrorCode } from '../types.js';
|
|
6
|
+
import { CLAUDE_CODE_DEFAULT_USER_AGENT, CLAUDE_CODE_DEFAULT_X_APP, CLAUDE_CODE_DEFAULT_ANTHROPIC_BETA, parseClaudeCodeAppVersionFromUserAgent } from './claude-code-helpers.js';
|
|
7
|
+
import { normalizeResponsesConfig, resolveProviderStreamingPreference } from './responses-helpers.js';
|
|
8
|
+
import { normalizeModelStreaming, normalizeModelContextTokens } from './streaming-helpers.js';
|
|
9
|
+
/**
|
|
10
|
+
* Normalize a raw provider configuration into a NormalizedProvider.
|
|
11
|
+
*/
|
|
12
|
+
export function normalizeProvider(providerId, raw) {
|
|
13
|
+
const provider = asRecord(raw);
|
|
14
|
+
const providerType = detectProviderType(provider);
|
|
15
|
+
const endpoint = typeof provider.endpoint === 'string' && provider.endpoint.trim()
|
|
16
|
+
? provider.endpoint.trim()
|
|
17
|
+
: typeof provider.baseURL === 'string' && provider.baseURL.trim()
|
|
18
|
+
? provider.baseURL.trim()
|
|
19
|
+
: typeof provider.baseUrl === 'string' && provider.baseUrl.trim()
|
|
20
|
+
? provider.baseUrl.trim()
|
|
21
|
+
: '';
|
|
22
|
+
const compatibilityProfile = resolveCompatibilityProfile(providerId, provider);
|
|
23
|
+
const headers = maybeInjectClaudeCodeHeaders(providerId, providerType, compatibilityProfile, normalizeHeaders(provider.headers));
|
|
24
|
+
const responsesNode = asRecord(provider.responses);
|
|
25
|
+
const responsesConfig = normalizeResponsesConfig({
|
|
26
|
+
providerId,
|
|
27
|
+
providerType,
|
|
28
|
+
compatibilityProfile,
|
|
29
|
+
provider,
|
|
30
|
+
node: responsesNode
|
|
31
|
+
});
|
|
32
|
+
const processMode = normalizeProcessMode(provider.process);
|
|
33
|
+
const streaming = resolveProviderStreamingPreference(provider, responsesNode);
|
|
34
|
+
const modelStreaming = normalizeModelStreaming(provider);
|
|
35
|
+
const { modelContextTokens, defaultContextTokens } = normalizeModelContextTokens(provider);
|
|
36
|
+
const deepseek = normalizeDeepSeekOptions(provider);
|
|
37
|
+
const serverToolsDisabled = provider.serverToolsDisabled === true ||
|
|
38
|
+
(typeof provider.serverToolsDisabled === 'string' &&
|
|
39
|
+
provider.serverToolsDisabled.trim().toLowerCase() === 'true') ||
|
|
40
|
+
(provider.serverTools &&
|
|
41
|
+
typeof provider.serverTools === 'object' &&
|
|
42
|
+
provider.serverTools.enabled === false);
|
|
43
|
+
return {
|
|
44
|
+
providerId,
|
|
45
|
+
providerType,
|
|
46
|
+
endpoint,
|
|
47
|
+
headers,
|
|
48
|
+
outboundProfile: mapOutboundProfile(providerType),
|
|
49
|
+
compatibilityProfile,
|
|
50
|
+
processMode,
|
|
51
|
+
responsesConfig,
|
|
52
|
+
streaming,
|
|
53
|
+
modelStreaming,
|
|
54
|
+
modelContextTokens,
|
|
55
|
+
defaultContextTokens,
|
|
56
|
+
...(deepseek ? { deepseek } : {}),
|
|
57
|
+
...(serverToolsDisabled ? { serverToolsDisabled: true } : {})
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function hasHeader(headers, name) {
|
|
61
|
+
if (!headers) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
const lowered = name.trim().toLowerCase();
|
|
65
|
+
if (!lowered) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
for (const key of Object.keys(headers)) {
|
|
69
|
+
if (key.trim().toLowerCase() === lowered) {
|
|
70
|
+
const value = headers[key];
|
|
71
|
+
if (typeof value === 'string' && value.trim()) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
function maybeInjectClaudeCodeHeaders(_providerId, providerType, compatibilityProfile, headers) {
|
|
79
|
+
const profile = typeof compatibilityProfile === 'string' ? compatibilityProfile.trim().toLowerCase() : '';
|
|
80
|
+
if (!profile || (profile !== 'anthropic:claude-code' && profile !== 'chat:claude-code')) {
|
|
81
|
+
return headers;
|
|
82
|
+
}
|
|
83
|
+
if (!String(providerType).toLowerCase().includes('anthropic')) {
|
|
84
|
+
return headers;
|
|
85
|
+
}
|
|
86
|
+
const base = { ...(headers ?? {}) };
|
|
87
|
+
if (!hasHeader(base, 'User-Agent')) {
|
|
88
|
+
base['User-Agent'] = CLAUDE_CODE_DEFAULT_USER_AGENT;
|
|
89
|
+
}
|
|
90
|
+
if (!hasHeader(base, 'X-App')) {
|
|
91
|
+
base['X-App'] = CLAUDE_CODE_DEFAULT_X_APP;
|
|
92
|
+
}
|
|
93
|
+
if (!hasHeader(base, 'X-App-Version')) {
|
|
94
|
+
const version = parseClaudeCodeAppVersionFromUserAgent(base['User-Agent'] ?? '');
|
|
95
|
+
if (version) {
|
|
96
|
+
base['X-App-Version'] = version;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (!hasHeader(base, 'anthropic-beta')) {
|
|
100
|
+
base['anthropic-beta'] = CLAUDE_CODE_DEFAULT_ANTHROPIC_BETA;
|
|
101
|
+
}
|
|
102
|
+
return base;
|
|
103
|
+
}
|
|
104
|
+
function normalizeDeepSeekOptions(provider) {
|
|
105
|
+
const direct = asRecord(provider.deepseek);
|
|
106
|
+
const ext = asRecord(asRecord(provider.extensions)?.deepseek);
|
|
107
|
+
const source = Object.keys(direct).length ? direct : ext;
|
|
108
|
+
if (!source || !Object.keys(source).length) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
const strictToolRequired = typeof source.strictToolRequired === 'boolean'
|
|
112
|
+
? source.strictToolRequired
|
|
113
|
+
: typeof source.strictToolRequired === 'string'
|
|
114
|
+
? source.strictToolRequired.trim().toLowerCase() === 'true'
|
|
115
|
+
: undefined;
|
|
116
|
+
const textToolFallback = typeof source.textToolFallback === 'boolean'
|
|
117
|
+
? source.textToolFallback
|
|
118
|
+
: typeof source.textToolFallback === 'string'
|
|
119
|
+
? source.textToolFallback.trim().toLowerCase() === 'true'
|
|
120
|
+
: undefined;
|
|
121
|
+
if (strictToolRequired === undefined && textToolFallback === undefined) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
...(strictToolRequired !== undefined ? { strictToolRequired } : {}),
|
|
126
|
+
...(textToolFallback !== undefined ? { textToolFallback } : {})
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function resolveCompatibilityProfile(providerId, provider) {
|
|
130
|
+
if (typeof provider.compatibilityProfile === 'string' && provider.compatibilityProfile.trim()) {
|
|
131
|
+
return provider.compatibilityProfile.trim();
|
|
132
|
+
}
|
|
133
|
+
const legacyFields = [];
|
|
134
|
+
if (typeof provider.compat === 'string') {
|
|
135
|
+
legacyFields.push('compat');
|
|
136
|
+
}
|
|
137
|
+
if (typeof provider.compatibility_profile === 'string') {
|
|
138
|
+
legacyFields.push('compatibility_profile');
|
|
139
|
+
}
|
|
140
|
+
if (legacyFields.length > 0) {
|
|
141
|
+
throw new VirtualRouterError(`Provider "${providerId}" uses legacy compatibility field(s): ${legacyFields.join(', ')}. Rename to "compatibilityProfile".`, VirtualRouterErrorCode.CONFIG_ERROR);
|
|
142
|
+
}
|
|
143
|
+
const normalizedId = providerId.trim().toLowerCase();
|
|
144
|
+
const providerType = String(provider.providerType ?? provider.type ?? provider.protocol ?? '').toLowerCase();
|
|
145
|
+
if (normalizedId === 'antigravity' ||
|
|
146
|
+
normalizedId === 'gemini-cli' ||
|
|
147
|
+
providerType.includes('antigravity') ||
|
|
148
|
+
providerType.includes('gemini-cli')) {
|
|
149
|
+
return 'chat:gemini-cli';
|
|
150
|
+
}
|
|
151
|
+
return 'compat:passthrough';
|
|
152
|
+
}
|
|
153
|
+
function normalizeProcessMode(value) {
|
|
154
|
+
if (typeof value !== 'string') {
|
|
155
|
+
return 'chat';
|
|
156
|
+
}
|
|
157
|
+
const normalized = value.trim().toLowerCase();
|
|
158
|
+
if (normalized === 'passthrough') {
|
|
159
|
+
return 'passthrough';
|
|
160
|
+
}
|
|
161
|
+
return 'chat';
|
|
162
|
+
}
|
|
163
|
+
export function detectProviderType(provider) {
|
|
164
|
+
const raw = (provider.providerType || provider.protocol || provider.type || '').toString().toLowerCase();
|
|
165
|
+
const id = (provider.providerId || provider.id || '').toString().toLowerCase();
|
|
166
|
+
const match = (value, keyword) => value.includes(keyword);
|
|
167
|
+
const source = `${raw}|${id}`;
|
|
168
|
+
const normalized = (src) => (src && src.trim() ? src.trim() : '');
|
|
169
|
+
const lexicon = normalized(source);
|
|
170
|
+
if (!lexicon)
|
|
171
|
+
return 'openai';
|
|
172
|
+
if (match(lexicon, 'anthropic') || match(lexicon, 'claude'))
|
|
173
|
+
return 'anthropic';
|
|
174
|
+
if (match(lexicon, 'responses'))
|
|
175
|
+
return 'responses';
|
|
176
|
+
if (match(lexicon, 'gemini'))
|
|
177
|
+
return 'gemini';
|
|
178
|
+
if (match(lexicon, 'iflow'))
|
|
179
|
+
return 'iflow';
|
|
180
|
+
if (match(lexicon, 'qwen'))
|
|
181
|
+
return 'qwen';
|
|
182
|
+
if (match(lexicon, 'glm'))
|
|
183
|
+
return 'glm';
|
|
184
|
+
if (match(lexicon, 'lmstudio'))
|
|
185
|
+
return 'lmstudio';
|
|
186
|
+
return raw || 'openai';
|
|
187
|
+
}
|
|
188
|
+
export function mapOutboundProfile(providerType) {
|
|
189
|
+
const value = providerType.toLowerCase();
|
|
190
|
+
if (value === 'anthropic')
|
|
191
|
+
return 'anthropic-messages';
|
|
192
|
+
if (value === 'responses')
|
|
193
|
+
return 'openai-responses';
|
|
194
|
+
if (value === 'gemini')
|
|
195
|
+
return 'gemini-chat';
|
|
196
|
+
return 'openai-chat';
|
|
197
|
+
}
|
|
198
|
+
export function normalizeHeaders(input) {
|
|
199
|
+
if (!input || typeof input !== 'object') {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
const entries = {};
|
|
203
|
+
for (const [key, value] of Object.entries(input)) {
|
|
204
|
+
if (typeof value === 'string') {
|
|
205
|
+
entries[key] = value;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return Object.keys(entries).length ? entries : undefined;
|
|
209
|
+
}
|
|
210
|
+
function asRecord(value) {
|
|
211
|
+
return (value && typeof value === 'object' ? value : {});
|
|
212
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ResponsesProviderConfig, type StreamingPreference } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Normalize responses provider config.
|
|
4
|
+
*/
|
|
5
|
+
export declare function normalizeResponsesConfig(options: {
|
|
6
|
+
providerId: string;
|
|
7
|
+
providerType: string;
|
|
8
|
+
compatibilityProfile: string;
|
|
9
|
+
provider: Record<string, unknown>;
|
|
10
|
+
node?: Record<string, unknown>;
|
|
11
|
+
}): ResponsesProviderConfig | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Resolve provider-level streaming preference.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveProviderStreamingPreference(provider: Record<string, unknown>, responsesNode?: Record<string, unknown>): StreamingPreference | undefined;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { asRecord } from './utils.js';
|
|
2
|
+
/**
|
|
3
|
+
* Normalize responses provider config.
|
|
4
|
+
*/
|
|
5
|
+
export function normalizeResponsesConfig(options) {
|
|
6
|
+
const source = options.node ?? asRecord(options.provider.responses);
|
|
7
|
+
const rawStyle = typeof source.toolCallIdStyle === 'string' ? source.toolCallIdStyle.trim().toLowerCase() : undefined;
|
|
8
|
+
if (rawStyle === 'fc' || rawStyle === 'preserve') {
|
|
9
|
+
return { toolCallIdStyle: rawStyle };
|
|
10
|
+
}
|
|
11
|
+
const providerType = typeof options.providerType === 'string' ? options.providerType.trim().toLowerCase() : '';
|
|
12
|
+
if (!providerType.includes('responses')) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
const providerId = typeof options.providerId === 'string' ? options.providerId.trim().toLowerCase() : '';
|
|
16
|
+
const compat = typeof options.compatibilityProfile === 'string' ? options.compatibilityProfile.trim().toLowerCase() : '';
|
|
17
|
+
// Default tool-call id style:
|
|
18
|
+
// - Standard OpenAI /v1/responses requires function_call ids to start with "fc_".
|
|
19
|
+
// - LM Studio (OpenAI-compatible) often emits `call_*` ids and expects them to be preserved.
|
|
20
|
+
const isLmstudio = providerId === 'lmstudio' || compat === 'chat:lmstudio';
|
|
21
|
+
return { toolCallIdStyle: isLmstudio ? 'preserve' : 'fc' };
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolve provider-level streaming preference.
|
|
25
|
+
*/
|
|
26
|
+
export function resolveProviderStreamingPreference(provider, responsesNode) {
|
|
27
|
+
const configNode = asRecord(provider.config);
|
|
28
|
+
const configResponses = configNode ? asRecord(configNode.responses) : undefined;
|
|
29
|
+
return (coerceStreamingPreference(provider.streaming ?? provider.stream ?? provider.supportsStreaming ?? provider.streamingPreference) ??
|
|
30
|
+
coerceStreamingPreference(responsesNode?.streaming ?? responsesNode?.stream ?? responsesNode?.supportsStreaming) ??
|
|
31
|
+
coerceStreamingPreference(configResponses?.streaming ?? configResponses?.stream));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Coerce various value types to StreamingPreference.
|
|
35
|
+
*/
|
|
36
|
+
function coerceStreamingPreference(value) {
|
|
37
|
+
if (typeof value === 'string') {
|
|
38
|
+
const normalized = value.trim().toLowerCase();
|
|
39
|
+
if (normalized === 'always' || normalized === 'auto' || normalized === 'never') {
|
|
40
|
+
return normalized;
|
|
41
|
+
}
|
|
42
|
+
if (normalized === 'true') {
|
|
43
|
+
return 'always';
|
|
44
|
+
}
|
|
45
|
+
if (normalized === 'false') {
|
|
46
|
+
return 'never';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (typeof value === 'boolean') {
|
|
50
|
+
return value ? 'always' : 'never';
|
|
51
|
+
}
|
|
52
|
+
if (value && typeof value === 'object') {
|
|
53
|
+
const record = value;
|
|
54
|
+
if (record.mode !== undefined) {
|
|
55
|
+
return coerceStreamingPreference(record.mode);
|
|
56
|
+
}
|
|
57
|
+
if (record.value !== undefined) {
|
|
58
|
+
return coerceStreamingPreference(record.value);
|
|
59
|
+
}
|
|
60
|
+
if (record.enabled !== undefined) {
|
|
61
|
+
return coerceStreamingPreference(record.enabled);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type RoutingPools } from '../types.js';
|
|
2
|
+
export interface NormalizedRoutePoolConfig {
|
|
3
|
+
id: string;
|
|
4
|
+
priority: number;
|
|
5
|
+
backup: boolean;
|
|
6
|
+
targets: string[];
|
|
7
|
+
mode?: 'round-robin' | 'priority';
|
|
8
|
+
force?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function normalizeRouting(source: Record<string, unknown>): Record<string, NormalizedRoutePoolConfig[]>;
|
|
11
|
+
export declare function expandRoutingTable(routingSource: Record<string, NormalizedRoutePoolConfig[]>, aliasIndex: Map<string, string[]>, modelIndex: Map<string, {
|
|
12
|
+
declared: boolean;
|
|
13
|
+
models: string[];
|
|
14
|
+
}>): {
|
|
15
|
+
routing: RoutingPools;
|
|
16
|
+
targetKeys: Set<string>;
|
|
17
|
+
};
|
|
18
|
+
export declare function parseTargetKey(targetKey: string): {
|
|
19
|
+
providerId: string;
|
|
20
|
+
keyAlias: string;
|
|
21
|
+
modelId: string;
|
|
22
|
+
} | null;
|
|
23
|
+
export declare function buildRuntimeKey(providerId: string, keyAlias: string): string;
|