@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
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { resolveStopMessageScope, getRoutingInstructionState, persistRoutingInstructionState } from '../engine/routing-state/store.js';
|
|
2
|
+
import { hasClientInjectScopedFields, stripClientInjectScopedFields } from './helpers.js';
|
|
3
|
+
import { flattenPoolTargets } from './route-utils.js';
|
|
4
|
+
export function getStopMessageState(engine, metadata) {
|
|
5
|
+
const hasArmedStopState = (candidate) => {
|
|
6
|
+
if (!candidate) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const text = typeof candidate.stopMessageText === 'string' ? candidate.stopMessageText.trim() : '';
|
|
10
|
+
const maxRepeats = typeof candidate.stopMessageMaxRepeats === 'number' && Number.isFinite(candidate.stopMessageMaxRepeats)
|
|
11
|
+
? Math.max(1, Math.floor(candidate.stopMessageMaxRepeats))
|
|
12
|
+
: 0;
|
|
13
|
+
const mode = typeof candidate.stopMessageStageMode === 'string'
|
|
14
|
+
? candidate.stopMessageStageMode.trim().toLowerCase()
|
|
15
|
+
: '';
|
|
16
|
+
if (mode === 'off') {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return Boolean(text) && maxRepeats > 0;
|
|
20
|
+
};
|
|
21
|
+
const stopMessageScope = resolveStopMessageScope(metadata);
|
|
22
|
+
if (!stopMessageScope) {
|
|
23
|
+
const sessionScope = engine.resolveSessionScope(metadata);
|
|
24
|
+
if (sessionScope) {
|
|
25
|
+
const legacyState = getRoutingInstructionState(sessionScope, engine.routingInstructionState, engine.routingStateStore);
|
|
26
|
+
if (hasClientInjectScopedFields(legacyState)) {
|
|
27
|
+
const cleared = stripClientInjectScopedFields(legacyState);
|
|
28
|
+
engine.routingInstructionState.set(sessionScope, cleared);
|
|
29
|
+
persistRoutingInstructionState(sessionScope, cleared, engine.routingStateStore);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const effectiveState = getRoutingInstructionState(stopMessageScope, engine.routingInstructionState, engine.routingStateStore);
|
|
35
|
+
if (!hasArmedStopState(effectiveState)) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const text = typeof effectiveState.stopMessageText === 'string' ? effectiveState.stopMessageText.trim() : '';
|
|
39
|
+
const maxRepeats = typeof effectiveState.stopMessageMaxRepeats === 'number' && Number.isFinite(effectiveState.stopMessageMaxRepeats)
|
|
40
|
+
? Math.max(1, Math.floor(effectiveState.stopMessageMaxRepeats))
|
|
41
|
+
: 0;
|
|
42
|
+
const stageModeRaw = typeof effectiveState.stopMessageStageMode === 'string'
|
|
43
|
+
? effectiveState.stopMessageStageMode.trim().toLowerCase()
|
|
44
|
+
: '';
|
|
45
|
+
const stageModeNormalized = stageModeRaw === 'on' || stageModeRaw === 'off' || stageModeRaw === 'auto'
|
|
46
|
+
? stageModeRaw
|
|
47
|
+
: undefined;
|
|
48
|
+
const aiModeRaw = typeof effectiveState.stopMessageAiMode === 'string'
|
|
49
|
+
? effectiveState.stopMessageAiMode.trim().toLowerCase()
|
|
50
|
+
: '';
|
|
51
|
+
const aiModeNormalized = aiModeRaw === 'on' || aiModeRaw === 'off' ? aiModeRaw : undefined;
|
|
52
|
+
if (stageModeNormalized === 'off' || !text || maxRepeats <= 0) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
...(text ? { stopMessageText: text } : {}),
|
|
57
|
+
stopMessageMaxRepeats: maxRepeats,
|
|
58
|
+
...(typeof effectiveState.stopMessageSource === 'string' && effectiveState.stopMessageSource.trim()
|
|
59
|
+
? { stopMessageSource: effectiveState.stopMessageSource.trim() }
|
|
60
|
+
: {}),
|
|
61
|
+
...(typeof effectiveState.stopMessageUsed === 'number' && Number.isFinite(effectiveState.stopMessageUsed)
|
|
62
|
+
? { stopMessageUsed: Math.max(0, Math.floor(effectiveState.stopMessageUsed)) }
|
|
63
|
+
: {}),
|
|
64
|
+
...(typeof effectiveState.stopMessageUpdatedAt === 'number' && Number.isFinite(effectiveState.stopMessageUpdatedAt)
|
|
65
|
+
? { stopMessageUpdatedAt: effectiveState.stopMessageUpdatedAt }
|
|
66
|
+
: {}),
|
|
67
|
+
...(typeof effectiveState.stopMessageLastUsedAt === 'number' && Number.isFinite(effectiveState.stopMessageLastUsedAt)
|
|
68
|
+
? { stopMessageLastUsedAt: effectiveState.stopMessageLastUsedAt }
|
|
69
|
+
: {}),
|
|
70
|
+
...(stageModeNormalized ? { stopMessageStageMode: stageModeNormalized } : {}),
|
|
71
|
+
...(aiModeNormalized ? { stopMessageAiMode: aiModeNormalized } : {}),
|
|
72
|
+
...(typeof effectiveState.stopMessageAiSeedPrompt === 'string' && effectiveState.stopMessageAiSeedPrompt.trim()
|
|
73
|
+
? { stopMessageAiSeedPrompt: effectiveState.stopMessageAiSeedPrompt.trim() }
|
|
74
|
+
: {}),
|
|
75
|
+
...(Array.isArray(effectiveState.stopMessageAiHistory)
|
|
76
|
+
? { stopMessageAiHistory: effectiveState.stopMessageAiHistory }
|
|
77
|
+
: {})
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function getPreCommandState(engine, metadata) {
|
|
81
|
+
const stopMessageScope = resolveStopMessageScope(metadata);
|
|
82
|
+
if (!stopMessageScope) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const effectiveState = getRoutingInstructionState(stopMessageScope, engine.routingInstructionState, engine.routingStateStore);
|
|
86
|
+
if (!effectiveState) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const scriptPath = typeof effectiveState.preCommandScriptPath === 'string' ? effectiveState.preCommandScriptPath.trim() : '';
|
|
90
|
+
if (!scriptPath) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
preCommandScriptPath: scriptPath,
|
|
95
|
+
...(typeof effectiveState.preCommandSource === 'string' && effectiveState.preCommandSource.trim()
|
|
96
|
+
? { preCommandSource: effectiveState.preCommandSource.trim() }
|
|
97
|
+
: {}),
|
|
98
|
+
...(typeof effectiveState.preCommandUpdatedAt === 'number' && Number.isFinite(effectiveState.preCommandUpdatedAt)
|
|
99
|
+
? { preCommandUpdatedAt: effectiveState.preCommandUpdatedAt }
|
|
100
|
+
: {})
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export function getStatus(engine) {
|
|
104
|
+
const routes = {};
|
|
105
|
+
for (const [route, pools] of Object.entries(engine.routing)) {
|
|
106
|
+
const stats = engine.routeAnalytics.getRouteStats(route);
|
|
107
|
+
routes[route] = {
|
|
108
|
+
providers: flattenPoolTargets(engine, pools),
|
|
109
|
+
hits: stats?.hits ?? 0,
|
|
110
|
+
lastUsedProvider: stats?.lastProvider,
|
|
111
|
+
...(stats?.lastHit ? { lastHit: { ...stats.lastHit } } : {})
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
routes,
|
|
116
|
+
health: engine.healthManager.getSnapshot()
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { ProviderHealthManager } from './health-manager.js';
|
|
2
|
+
import { ProviderRegistry } from './provider-registry.js';
|
|
3
|
+
import { RouteLoadBalancer } from './load-balancer.js';
|
|
4
|
+
import { RoutingClassifier } from './classifier.js';
|
|
5
|
+
import { ContextAdvisor } from './context-advisor.js';
|
|
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';
|
|
8
|
+
import type { RoutingInstructionState } from './routing-instructions.js';
|
|
9
|
+
import type { ProviderQuotaView } from './types.js';
|
|
10
|
+
import type { RoutingInstructionStateStoreLike } from './engine/routing-state/store.js';
|
|
11
|
+
import { RouteAnalytics } from './engine/route-analytics.js';
|
|
12
|
+
import { StickySessionManager } from './engine/sticky-session-manager.js';
|
|
13
|
+
import { CooldownManager } from './engine/cooldown-manager.js';
|
|
14
|
+
import { getStatus as getStatusImpl } from './engine-legacy/state-accessors.js';
|
|
15
|
+
export declare class VirtualRouterEngine {
|
|
16
|
+
routing: RoutingPools;
|
|
17
|
+
readonly providerRegistry: ProviderRegistry;
|
|
18
|
+
readonly healthManager: ProviderHealthManager;
|
|
19
|
+
loadBalancer: RouteLoadBalancer;
|
|
20
|
+
classifier: RoutingClassifier;
|
|
21
|
+
readonly contextAdvisor: ContextAdvisor;
|
|
22
|
+
contextRouting: VirtualRouterContextRoutingConfig | undefined;
|
|
23
|
+
readonly routeAnalytics: RouteAnalytics;
|
|
24
|
+
stickySessionManager: StickySessionManager;
|
|
25
|
+
cooldownManager: CooldownManager;
|
|
26
|
+
antigravityLeasePersistence: {
|
|
27
|
+
loadedOnce: boolean;
|
|
28
|
+
loadedMtimeMs: number | null;
|
|
29
|
+
flushTimer: ReturnType<typeof setTimeout> | null;
|
|
30
|
+
};
|
|
31
|
+
readonly debug: Console;
|
|
32
|
+
healthConfig: VirtualRouterConfig['health'] | null;
|
|
33
|
+
readonly statsCenter: import("../../index.js").StatsCenter;
|
|
34
|
+
webSearchForce: boolean;
|
|
35
|
+
healthStore?: VirtualRouterHealthStore;
|
|
36
|
+
routingStateStore: RoutingInstructionStateStoreLike;
|
|
37
|
+
routingInstructionState: Map<string, RoutingInstructionState>;
|
|
38
|
+
quotaView?: ProviderQuotaView;
|
|
39
|
+
/**
|
|
40
|
+
* Backward-compatible test/debug surface used by existing regression scripts.
|
|
41
|
+
* Keep this as a read-only view over StickySessionManager storage.
|
|
42
|
+
*/
|
|
43
|
+
get antigravitySessionAliasStore(): Map<string, string>;
|
|
44
|
+
constructor(deps?: {
|
|
45
|
+
healthStore?: VirtualRouterHealthStore;
|
|
46
|
+
routingStateStore?: RoutingInstructionStateStoreLike;
|
|
47
|
+
quotaView?: ProviderQuotaView;
|
|
48
|
+
});
|
|
49
|
+
updateDeps(deps: {
|
|
50
|
+
healthStore?: VirtualRouterHealthStore | null;
|
|
51
|
+
routingStateStore?: RoutingInstructionStateStoreLike | null;
|
|
52
|
+
quotaView?: ProviderQuotaView | null;
|
|
53
|
+
}): void;
|
|
54
|
+
initialize(config: VirtualRouterConfig): void;
|
|
55
|
+
route(request: StandardizedRequest | ProcessedRequest, metadata: RouterMetadataInput): {
|
|
56
|
+
target: TargetMetadata;
|
|
57
|
+
decision: RoutingDecision;
|
|
58
|
+
diagnostics: RoutingDiagnostics;
|
|
59
|
+
};
|
|
60
|
+
getStopMessageState(metadata: RouterMetadataInput): StopMessageStateSnapshot | null;
|
|
61
|
+
getPreCommandState(metadata: RouterMetadataInput): PreCommandStateSnapshot | null;
|
|
62
|
+
handleProviderFailure(event: ProviderFailureEvent): void;
|
|
63
|
+
handleProviderError(event: ProviderErrorEvent): void;
|
|
64
|
+
handleProviderSuccess(event: ProviderSuccessEvent): void;
|
|
65
|
+
getStatus(): ReturnType<typeof getStatusImpl>;
|
|
66
|
+
normalizeRouteAlias(routeName: string | undefined): string;
|
|
67
|
+
buildRouteCandidates(requestedRoute: string, classificationCandidates: string[] | undefined, features: RoutingFeatures): string[];
|
|
68
|
+
reorderForInlineVision(routeNames: string[]): string[];
|
|
69
|
+
reorderForPreferredModel(routeNames: string[], modelId: string): string[];
|
|
70
|
+
routeSupportsModel(routeName: string, modelId: string): boolean;
|
|
71
|
+
routeSupportsInlineVision(routeName: string): boolean;
|
|
72
|
+
sortByPriority(routeNames: string[]): string[];
|
|
73
|
+
routeWeight(routeName: string): number;
|
|
74
|
+
routeHasForceFlag(routeName: string): boolean;
|
|
75
|
+
routeHasTargets(pools?: RoutePoolTier[]): boolean;
|
|
76
|
+
hasPrimaryPool(pools?: RoutePoolTier[]): boolean;
|
|
77
|
+
sortRoutePools(pools?: RoutePoolTier[]): RoutePoolTier[];
|
|
78
|
+
flattenPoolTargets(pools?: RoutePoolTier[]): string[];
|
|
79
|
+
markProviderCooldown(providerKey: string, cooldownMs: number | undefined): void;
|
|
80
|
+
clearProviderCooldown(providerKey: string): void;
|
|
81
|
+
isProviderCoolingDown(providerKey: string): boolean;
|
|
82
|
+
getProviderCooldownRemainingMs(providerKey: string): number;
|
|
83
|
+
restoreHealthFromStore(): void;
|
|
84
|
+
buildHealthSnapshot(): import("./types.js").VirtualRouterHealthSnapshot;
|
|
85
|
+
persistHealthSnapshot(): void;
|
|
86
|
+
parseDirectProviderModel(model: string | undefined): {
|
|
87
|
+
providerId: string;
|
|
88
|
+
modelId: string;
|
|
89
|
+
} | null;
|
|
90
|
+
shouldFallbackDirectModelForMedia(direct: {
|
|
91
|
+
providerId: string;
|
|
92
|
+
modelId: string;
|
|
93
|
+
}, features: RoutingFeatures): boolean;
|
|
94
|
+
selectProvider(requestedRoute: string, metadata: RouterMetadataInput, classification: any, features: RoutingFeatures, routingState?: RoutingInstructionState): {
|
|
95
|
+
providerKey: string;
|
|
96
|
+
routeUsed: string;
|
|
97
|
+
pool: string[];
|
|
98
|
+
poolId?: string;
|
|
99
|
+
};
|
|
100
|
+
selectFromCandidates(routes: string[], metadata: RouterMetadataInput, classification: any, features: RoutingFeatures, state: RoutingInstructionState, requiredProviderKeys?: Set<string>, allowAliasRotation?: boolean): {
|
|
101
|
+
providerKey: string;
|
|
102
|
+
routeUsed: string;
|
|
103
|
+
pool: string[];
|
|
104
|
+
poolId?: string;
|
|
105
|
+
};
|
|
106
|
+
selectFromStickyPool(stickyKeySet: Set<string>, metadata: RouterMetadataInput, features: RoutingFeatures, state: RoutingInstructionState, allowAliasRotation?: boolean): {
|
|
107
|
+
providerKey: string;
|
|
108
|
+
routeUsed: string;
|
|
109
|
+
pool: string[];
|
|
110
|
+
poolId?: string;
|
|
111
|
+
} | null;
|
|
112
|
+
extractExcludedProviderKeySet(metadata: RouterMetadataInput | undefined): Set<string>;
|
|
113
|
+
resolveSelectionPenalty(providerKey: string): number | undefined;
|
|
114
|
+
resolveInstructionProcessModeForSelection(providerKey: string, routingState: RoutingInstructionState): 'chat' | 'passthrough' | undefined;
|
|
115
|
+
resolveInstructionTarget(target: NonNullable<RoutingInstructionState['forcedTarget']>): {
|
|
116
|
+
mode: 'exact' | 'filter';
|
|
117
|
+
keys: string[];
|
|
118
|
+
} | null;
|
|
119
|
+
buildStickyRouteCandidatesFromFiltered(filteredCandidates: string[], stickyKeySet: Set<string>): string[];
|
|
120
|
+
filterCandidatesByRoutingState(routes: string[], state: RoutingInstructionState): string[];
|
|
121
|
+
resolveStickyKey(metadata: RouterMetadataInput): string | undefined;
|
|
122
|
+
resolveSessionScope(metadata: RouterMetadataInput): string | undefined;
|
|
123
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { ProviderHealthManager } from './health-manager.js';
|
|
2
|
+
import { ProviderRegistry } from './provider-registry.js';
|
|
3
|
+
import { RouteLoadBalancer } from './load-balancer.js';
|
|
4
|
+
import { RoutingClassifier } from './classifier.js';
|
|
5
|
+
import { ContextAdvisor } from './context-advisor.js';
|
|
6
|
+
import { getStatsCenter } from '../../telemetry/stats-center.js';
|
|
7
|
+
import { loadRoutingInstructionStateSync, saveRoutingInstructionStateAsync, saveRoutingInstructionStateSync } from './sticky-session-store.js';
|
|
8
|
+
import { resolveStickyKey as resolveStickyKeyImpl, resolveSessionScope as resolveSessionScopeImpl } from './engine/routing-state/keys.js';
|
|
9
|
+
import { RouteAnalytics } from './engine/route-analytics.js';
|
|
10
|
+
import { StickySessionManager } from './engine/sticky-session-manager.js';
|
|
11
|
+
import { CooldownManager } from './engine/cooldown-manager.js';
|
|
12
|
+
import { routeRequest } from './engine-legacy/routing.js';
|
|
13
|
+
import { updateDeps as updateDepsImpl, initialize as initializeImpl } from './engine-legacy/config.js';
|
|
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
|
+
import { selectProvider as selectProviderImpl, selectFromCandidates as selectFromCandidatesImpl, selectFromStickyPool as selectFromStickyPoolImpl, extractExcludedProviderKeySet as extractExcludedProviderKeySetImpl } from './engine-legacy/selection-core.js';
|
|
17
|
+
import { parseDirectProviderModel as parseDirectProviderModelImpl, shouldFallbackDirectModelForMedia as shouldFallbackDirectModelForMediaImpl } from './engine-legacy/direct-model.js';
|
|
18
|
+
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';
|
|
19
|
+
import { resolveSelectionPenalty as resolveSelectionPenaltyImpl, resolveInstructionProcessModeForSelection as resolveInstructionProcessModeForSelectionImpl, resolveInstructionTarget as resolveInstructionTargetImpl, filterCandidatesByRoutingState as filterCandidatesByRoutingStateImpl, buildStickyRouteCandidatesFromFiltered as buildStickyRouteCandidatesFromFilteredImpl } from './engine-legacy/selection-state.js';
|
|
20
|
+
export class VirtualRouterEngine {
|
|
21
|
+
routing = {};
|
|
22
|
+
providerRegistry = new ProviderRegistry();
|
|
23
|
+
healthManager = new ProviderHealthManager();
|
|
24
|
+
loadBalancer = new RouteLoadBalancer();
|
|
25
|
+
classifier = new RoutingClassifier({});
|
|
26
|
+
contextAdvisor = new ContextAdvisor();
|
|
27
|
+
contextRouting;
|
|
28
|
+
routeAnalytics = new RouteAnalytics();
|
|
29
|
+
stickySessionManager = new StickySessionManager();
|
|
30
|
+
cooldownManager;
|
|
31
|
+
antigravityLeasePersistence = { loadedOnce: false, loadedMtimeMs: null, flushTimer: null };
|
|
32
|
+
debug = console; // thin hook; host may monkey-patch for colored logging
|
|
33
|
+
healthConfig = null;
|
|
34
|
+
statsCenter = getStatsCenter();
|
|
35
|
+
// Derived flags from VirtualRouterConfig/routing used by process / response layers.
|
|
36
|
+
webSearchForce = false;
|
|
37
|
+
healthStore;
|
|
38
|
+
routingStateStore = {
|
|
39
|
+
loadSync: loadRoutingInstructionStateSync,
|
|
40
|
+
saveAsync: saveRoutingInstructionStateAsync,
|
|
41
|
+
saveSync: saveRoutingInstructionStateSync
|
|
42
|
+
};
|
|
43
|
+
routingInstructionState = new Map();
|
|
44
|
+
quotaView;
|
|
45
|
+
/**
|
|
46
|
+
* Backward-compatible test/debug surface used by existing regression scripts.
|
|
47
|
+
* Keep this as a read-only view over StickySessionManager storage.
|
|
48
|
+
*/
|
|
49
|
+
get antigravitySessionAliasStore() {
|
|
50
|
+
return this.stickySessionManager.getAllStores().sessionAliasStore;
|
|
51
|
+
}
|
|
52
|
+
constructor(deps) {
|
|
53
|
+
this.cooldownManager = new CooldownManager({
|
|
54
|
+
healthStore: deps?.healthStore,
|
|
55
|
+
healthConfig: this.healthConfig,
|
|
56
|
+
quotaView: deps?.quotaView
|
|
57
|
+
});
|
|
58
|
+
if (deps?.healthStore) {
|
|
59
|
+
this.healthStore = deps.healthStore;
|
|
60
|
+
}
|
|
61
|
+
if (deps?.routingStateStore) {
|
|
62
|
+
this.routingStateStore = deps.routingStateStore;
|
|
63
|
+
}
|
|
64
|
+
if (deps?.quotaView) {
|
|
65
|
+
this.quotaView = deps.quotaView;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
updateDeps(deps) {
|
|
69
|
+
updateDepsImpl(this, deps);
|
|
70
|
+
}
|
|
71
|
+
initialize(config) {
|
|
72
|
+
initializeImpl(this, config);
|
|
73
|
+
}
|
|
74
|
+
route(request, metadata) {
|
|
75
|
+
return routeRequest(this, request, metadata);
|
|
76
|
+
}
|
|
77
|
+
getStopMessageState(metadata) {
|
|
78
|
+
return getStopMessageStateImpl(this, metadata);
|
|
79
|
+
}
|
|
80
|
+
getPreCommandState(metadata) {
|
|
81
|
+
return getPreCommandStateImpl(this, metadata);
|
|
82
|
+
}
|
|
83
|
+
handleProviderFailure(event) {
|
|
84
|
+
handleProviderFailureImpl(this, event);
|
|
85
|
+
}
|
|
86
|
+
handleProviderError(event) {
|
|
87
|
+
handleProviderErrorImpl(this, event);
|
|
88
|
+
}
|
|
89
|
+
handleProviderSuccess(event) {
|
|
90
|
+
handleProviderSuccessImpl(this, event);
|
|
91
|
+
}
|
|
92
|
+
getStatus() {
|
|
93
|
+
return getStatusImpl(this);
|
|
94
|
+
}
|
|
95
|
+
normalizeRouteAlias(routeName) {
|
|
96
|
+
return normalizeRouteAliasImpl(routeName);
|
|
97
|
+
}
|
|
98
|
+
buildRouteCandidates(requestedRoute, classificationCandidates, features) {
|
|
99
|
+
return buildRouteCandidatesImpl(this, requestedRoute, classificationCandidates, features);
|
|
100
|
+
}
|
|
101
|
+
reorderForInlineVision(routeNames) {
|
|
102
|
+
return reorderForInlineVisionImpl(this, routeNames);
|
|
103
|
+
}
|
|
104
|
+
reorderForPreferredModel(routeNames, modelId) {
|
|
105
|
+
return reorderForPreferredModelImpl(this, routeNames, modelId);
|
|
106
|
+
}
|
|
107
|
+
routeSupportsModel(routeName, modelId) {
|
|
108
|
+
return routeSupportsModelImpl(this, routeName, modelId);
|
|
109
|
+
}
|
|
110
|
+
routeSupportsInlineVision(routeName) {
|
|
111
|
+
return routeSupportsInlineVisionImpl(this, routeName);
|
|
112
|
+
}
|
|
113
|
+
sortByPriority(routeNames) {
|
|
114
|
+
return sortByPriorityImpl(routeNames);
|
|
115
|
+
}
|
|
116
|
+
routeWeight(routeName) {
|
|
117
|
+
return routeWeightImpl(routeName);
|
|
118
|
+
}
|
|
119
|
+
routeHasForceFlag(routeName) {
|
|
120
|
+
return routeHasForceFlagImpl(this, routeName);
|
|
121
|
+
}
|
|
122
|
+
routeHasTargets(pools) {
|
|
123
|
+
return routeHasTargetsImpl(this, pools);
|
|
124
|
+
}
|
|
125
|
+
hasPrimaryPool(pools) {
|
|
126
|
+
return hasPrimaryPoolImpl(this, pools);
|
|
127
|
+
}
|
|
128
|
+
sortRoutePools(pools) {
|
|
129
|
+
return sortRoutePoolsImpl(this, pools);
|
|
130
|
+
}
|
|
131
|
+
flattenPoolTargets(pools) {
|
|
132
|
+
return flattenPoolTargetsImpl(this, pools);
|
|
133
|
+
}
|
|
134
|
+
markProviderCooldown(providerKey, cooldownMs) {
|
|
135
|
+
markProviderCooldownImpl(this, providerKey, cooldownMs);
|
|
136
|
+
}
|
|
137
|
+
clearProviderCooldown(providerKey) {
|
|
138
|
+
clearProviderCooldownImpl(this, providerKey);
|
|
139
|
+
}
|
|
140
|
+
isProviderCoolingDown(providerKey) {
|
|
141
|
+
return isProviderCoolingDownImpl(this, providerKey);
|
|
142
|
+
}
|
|
143
|
+
getProviderCooldownRemainingMs(providerKey) {
|
|
144
|
+
return getProviderCooldownRemainingMsImpl(this, providerKey);
|
|
145
|
+
}
|
|
146
|
+
restoreHealthFromStore() {
|
|
147
|
+
restoreHealthFromStoreImpl(this);
|
|
148
|
+
}
|
|
149
|
+
buildHealthSnapshot() {
|
|
150
|
+
return buildHealthSnapshotImpl(this);
|
|
151
|
+
}
|
|
152
|
+
persistHealthSnapshot() {
|
|
153
|
+
persistHealthSnapshotImpl(this);
|
|
154
|
+
}
|
|
155
|
+
parseDirectProviderModel(model) {
|
|
156
|
+
return parseDirectProviderModelImpl(this, model);
|
|
157
|
+
}
|
|
158
|
+
shouldFallbackDirectModelForMedia(direct, features) {
|
|
159
|
+
return shouldFallbackDirectModelForMediaImpl(this, direct, features);
|
|
160
|
+
}
|
|
161
|
+
selectProvider(requestedRoute, metadata, classification, features, routingState) {
|
|
162
|
+
return selectProviderImpl(this, requestedRoute, metadata, classification, features, routingState);
|
|
163
|
+
}
|
|
164
|
+
selectFromCandidates(routes, metadata, classification, features, state, requiredProviderKeys, allowAliasRotation) {
|
|
165
|
+
return selectFromCandidatesImpl(this, routes, metadata, classification, features, state, requiredProviderKeys, allowAliasRotation);
|
|
166
|
+
}
|
|
167
|
+
selectFromStickyPool(stickyKeySet, metadata, features, state, allowAliasRotation) {
|
|
168
|
+
return selectFromStickyPoolImpl(this, stickyKeySet, metadata, features, state, allowAliasRotation);
|
|
169
|
+
}
|
|
170
|
+
extractExcludedProviderKeySet(metadata) {
|
|
171
|
+
return extractExcludedProviderKeySetImpl(this, metadata);
|
|
172
|
+
}
|
|
173
|
+
resolveSelectionPenalty(providerKey) {
|
|
174
|
+
return resolveSelectionPenaltyImpl(this, providerKey);
|
|
175
|
+
}
|
|
176
|
+
resolveInstructionProcessModeForSelection(providerKey, routingState) {
|
|
177
|
+
return resolveInstructionProcessModeForSelectionImpl(this, providerKey, routingState);
|
|
178
|
+
}
|
|
179
|
+
resolveInstructionTarget(target) {
|
|
180
|
+
return resolveInstructionTargetImpl(this, target);
|
|
181
|
+
}
|
|
182
|
+
buildStickyRouteCandidatesFromFiltered(filteredCandidates, stickyKeySet) {
|
|
183
|
+
return buildStickyRouteCandidatesFromFilteredImpl(this, filteredCandidates, stickyKeySet);
|
|
184
|
+
}
|
|
185
|
+
filterCandidatesByRoutingState(routes, state) {
|
|
186
|
+
return filterCandidatesByRoutingStateImpl(this, routes, state);
|
|
187
|
+
}
|
|
188
|
+
resolveStickyKey(metadata) {
|
|
189
|
+
return resolveStickyKeyImpl(metadata);
|
|
190
|
+
}
|
|
191
|
+
resolveSessionScope(metadata) {
|
|
192
|
+
return resolveSessionScopeImpl(metadata);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -19,6 +19,7 @@ export type StopMessageRuntimeSummary = {
|
|
|
19
19
|
};
|
|
20
20
|
export type VirtualRouterHitRecord = {
|
|
21
21
|
timestampMs: number;
|
|
22
|
+
requestId?: string;
|
|
22
23
|
routeName: string;
|
|
23
24
|
poolId?: string;
|
|
24
25
|
providerKey: string;
|
|
@@ -34,6 +35,7 @@ export type VirtualRouterHitEventMeta = {
|
|
|
34
35
|
entryEndpoint?: string;
|
|
35
36
|
};
|
|
36
37
|
export declare function createVirtualRouterHitRecord(input: {
|
|
38
|
+
requestId?: string;
|
|
37
39
|
routeName: string;
|
|
38
40
|
poolId?: string;
|
|
39
41
|
providerKey: string;
|
|
@@ -65,6 +65,7 @@ export function createVirtualRouterHitRecord(input) {
|
|
|
65
65
|
timestampMs: typeof input.timestampMs === 'number' && Number.isFinite(input.timestampMs)
|
|
66
66
|
? input.timestampMs
|
|
67
67
|
: Date.now(),
|
|
68
|
+
...(input.requestId ? { requestId: input.requestId } : {}),
|
|
68
69
|
routeName: input.routeName,
|
|
69
70
|
...(input.poolId ? { poolId: input.poolId } : {}),
|
|
70
71
|
providerKey: input.providerKey,
|
|
@@ -249,6 +250,8 @@ export function formatVirtualRouterHit(record) {
|
|
|
249
250
|
const { providerLabel, resolvedModel } = describeTargetProvider(record.providerKey, record.modelId);
|
|
250
251
|
const routeLabel = record.poolId ? `${record.routeName}/${record.poolId}` : record.routeName;
|
|
251
252
|
const targetLabel = `${routeLabel} -> ${providerLabel}${resolvedModel ? '.' + resolvedModel : ''}`;
|
|
253
|
+
const requestId = typeof record.requestId === 'string' ? record.requestId : '';
|
|
254
|
+
const requestLabel = requestId && !requestId.includes('unknown') ? ` req=${requestId}` : '';
|
|
252
255
|
const stickyText = formatStickyScope(record.stickyScope);
|
|
253
256
|
const stickyLabel = stickyText ? ` ${stickyColor}[sticky:${stickyText}]${reset}` : '';
|
|
254
257
|
const reasonLabel = record.hitReason ? ` reason=${record.hitReason}` : '';
|
|
@@ -276,7 +279,7 @@ export function formatVirtualRouterHit(record) {
|
|
|
276
279
|
}
|
|
277
280
|
stopLabel = ` ${stopColor}[stopMessage:${parts.join(' ')}]${reset}`;
|
|
278
281
|
}
|
|
279
|
-
return `${prefix} ${timeLabel} ${routeColor}${targetLabel}${stickyLabel}${reasonLabel}${requestTokenLabel}${penaltyLabel}${stopLabel}${reset}`;
|
|
282
|
+
return `${prefix} ${timeLabel}${requestLabel} ${routeColor}${targetLabel}${stickyLabel}${reasonLabel}${requestTokenLabel}${penaltyLabel}${stopLabel}${reset}`;
|
|
280
283
|
}
|
|
281
284
|
catch {
|
|
282
285
|
const now = new Date(record.timestampMs);
|
|
@@ -284,6 +287,8 @@ export function formatVirtualRouterHit(record) {
|
|
|
284
287
|
const routeLabel = record.poolId ? `${record.routeName}/${record.poolId}` : record.routeName;
|
|
285
288
|
const stickyText = formatStickyScope(record.stickyScope);
|
|
286
289
|
const stickyLabel = stickyText ? ` [sticky:${stickyText}]` : '';
|
|
290
|
+
const requestId = typeof record.requestId === 'string' ? record.requestId : '';
|
|
291
|
+
const requestLabel = requestId && !requestId.includes('unknown') ? ` req=${requestId}` : '';
|
|
287
292
|
const requestTokenLabel = typeof record.requestTokens === 'number' && Number.isFinite(record.requestTokens)
|
|
288
293
|
? ` reqTokens=${Math.max(0, Math.round(record.requestTokens))}`
|
|
289
294
|
: '';
|
|
@@ -298,6 +303,6 @@ export function formatVirtualRouterHit(record) {
|
|
|
298
303
|
const left = stop.remaining >= 0 ? String(stop.remaining) : 'n/a';
|
|
299
304
|
stopLabel = ` [stopMessage:${safeText} mode=${stop.mode} round=${rounds} active=${stop.active ? 'yes' : 'no'} left=${left}]`;
|
|
300
305
|
}
|
|
301
|
-
return `[virtual-router-hit] ${timestamp} ${routeLabel} -> ${record.providerKey}${record.modelId ? '.' + record.modelId : ''}${stickyLabel}${record.hitReason ? ` reason=${record.hitReason}` : ''}${requestTokenLabel}${penaltyLabel}${stopLabel}`;
|
|
306
|
+
return `[virtual-router-hit] ${timestamp}${requestLabel} ${routeLabel} -> ${record.providerKey}${record.modelId ? '.' + record.modelId : ''}${stickyLabel}${record.hitReason ? ` reason=${record.hitReason}` : ''}${requestTokenLabel}${penaltyLabel}${stopLabel}`;
|
|
302
307
|
}
|
|
303
308
|
}
|
|
@@ -13,9 +13,6 @@ export function extractKeyAlias(providerKey) {
|
|
|
13
13
|
return normalizeAliasDescriptor(alias);
|
|
14
14
|
}
|
|
15
15
|
export function normalizeAliasDescriptor(alias) {
|
|
16
|
-
if (/^\d+-/.test(alias)) {
|
|
17
|
-
return alias.replace(/^\d+-/, '');
|
|
18
|
-
}
|
|
19
16
|
return alias;
|
|
20
17
|
}
|
|
21
18
|
export function extractKeyIndex(providerKey) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function buildGovernedFilterPayloadWithNativeFallback(request: unknown): Record<string, unknown>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { failNativeRequired, isNativeDisabledByEnv } from './native-router-hotpath-policy.js';
|
|
2
|
+
import { loadNativeRouterHotpathBindingForInternalUse } from './native-router-hotpath.js';
|
|
3
|
+
function readNativeFunction(name) {
|
|
4
|
+
const binding = loadNativeRouterHotpathBindingForInternalUse();
|
|
5
|
+
const fn = binding?.[name];
|
|
6
|
+
return typeof fn === 'function' ? fn : null;
|
|
7
|
+
}
|
|
8
|
+
function safeStringify(value) {
|
|
9
|
+
try {
|
|
10
|
+
return JSON.stringify(value);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function parseOutputRecord(raw) {
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse(raw);
|
|
19
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return parsed;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function buildGovernedFilterPayloadWithNativeFallback(request) {
|
|
29
|
+
const capability = 'buildGovernedFilterPayloadJson';
|
|
30
|
+
const fail = (reason) => failNativeRequired(capability, reason);
|
|
31
|
+
if (isNativeDisabledByEnv()) {
|
|
32
|
+
return fail('native disabled');
|
|
33
|
+
}
|
|
34
|
+
const fn = readNativeFunction(capability);
|
|
35
|
+
if (!fn) {
|
|
36
|
+
return fail();
|
|
37
|
+
}
|
|
38
|
+
const requestJson = safeStringify(request);
|
|
39
|
+
if (!requestJson) {
|
|
40
|
+
return fail('json stringify failed');
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const raw = fn(requestJson);
|
|
44
|
+
if (typeof raw !== 'string' || !raw) {
|
|
45
|
+
return fail('empty result');
|
|
46
|
+
}
|
|
47
|
+
const parsed = parseOutputRecord(raw);
|
|
48
|
+
return parsed ?? fail('invalid payload');
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
|
|
52
|
+
return fail(reason);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -47,6 +47,15 @@ export interface NativeProtocolSpec {
|
|
|
47
47
|
providerOutbound: NativeProviderOutboundPolicySpec;
|
|
48
48
|
toolSurface: NativeToolSurfaceSpec;
|
|
49
49
|
}
|
|
50
|
+
export interface NativeHubProtocolAllowlists {
|
|
51
|
+
openaiChatAllowedFields: string[];
|
|
52
|
+
openaiChatParametersWrapperAllowKeys: string[];
|
|
53
|
+
openaiResponsesAllowedFields: string[];
|
|
54
|
+
openaiResponsesParametersWrapperAllowKeys: string[];
|
|
55
|
+
anthropicAllowedFields: string[];
|
|
56
|
+
anthropicParametersWrapperAllowKeys: string[];
|
|
57
|
+
geminiAllowedFields: string[];
|
|
58
|
+
}
|
|
50
59
|
export declare function resolveHubProtocolSpecWithNative(input: {
|
|
51
60
|
protocol?: string;
|
|
52
61
|
allowlists: {
|
|
@@ -59,4 +68,5 @@ export declare function resolveHubProtocolSpecWithNative(input: {
|
|
|
59
68
|
geminiAllowedFields: readonly string[];
|
|
60
69
|
};
|
|
61
70
|
}): NativeProtocolSpec;
|
|
71
|
+
export declare function resolveHubProtocolAllowlistsWithNative(): NativeHubProtocolAllowlists;
|
|
62
72
|
export {};
|
|
@@ -298,6 +298,50 @@ function parseProtocolSpec(raw) {
|
|
|
298
298
|
return null;
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
|
+
function parseStringArrayValue(value) {
|
|
302
|
+
if (!Array.isArray(value)) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
const out = value.filter((entry) => typeof entry === 'string');
|
|
306
|
+
return out;
|
|
307
|
+
}
|
|
308
|
+
function parseHubProtocolAllowlists(raw) {
|
|
309
|
+
try {
|
|
310
|
+
const parsed = JSON.parse(raw);
|
|
311
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
const row = parsed;
|
|
315
|
+
const openaiChatAllowedFields = parseStringArrayValue(row.openaiChatAllowedFields);
|
|
316
|
+
const openaiChatParametersWrapperAllowKeys = parseStringArrayValue(row.openaiChatParametersWrapperAllowKeys);
|
|
317
|
+
const openaiResponsesAllowedFields = parseStringArrayValue(row.openaiResponsesAllowedFields);
|
|
318
|
+
const openaiResponsesParametersWrapperAllowKeys = parseStringArrayValue(row.openaiResponsesParametersWrapperAllowKeys);
|
|
319
|
+
const anthropicAllowedFields = parseStringArrayValue(row.anthropicAllowedFields);
|
|
320
|
+
const anthropicParametersWrapperAllowKeys = parseStringArrayValue(row.anthropicParametersWrapperAllowKeys);
|
|
321
|
+
const geminiAllowedFields = parseStringArrayValue(row.geminiAllowedFields);
|
|
322
|
+
if (!openaiChatAllowedFields ||
|
|
323
|
+
!openaiChatParametersWrapperAllowKeys ||
|
|
324
|
+
!openaiResponsesAllowedFields ||
|
|
325
|
+
!openaiResponsesParametersWrapperAllowKeys ||
|
|
326
|
+
!anthropicAllowedFields ||
|
|
327
|
+
!anthropicParametersWrapperAllowKeys ||
|
|
328
|
+
!geminiAllowedFields) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
openaiChatAllowedFields,
|
|
333
|
+
openaiChatParametersWrapperAllowKeys,
|
|
334
|
+
openaiResponsesAllowedFields,
|
|
335
|
+
openaiResponsesParametersWrapperAllowKeys,
|
|
336
|
+
anthropicAllowedFields,
|
|
337
|
+
anthropicParametersWrapperAllowKeys,
|
|
338
|
+
geminiAllowedFields
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
301
345
|
export function resolveHubProtocolSpecWithNative(input) {
|
|
302
346
|
const capability = 'resolveHubProtocolSpecJson';
|
|
303
347
|
const fail = (reason) => failNativeRequired(capability, reason);
|
|
@@ -336,3 +380,26 @@ export function resolveHubProtocolSpecWithNative(input) {
|
|
|
336
380
|
return fail(reason);
|
|
337
381
|
}
|
|
338
382
|
}
|
|
383
|
+
export function resolveHubProtocolAllowlistsWithNative() {
|
|
384
|
+
const capability = 'resolveHubProtocolAllowlistsJson';
|
|
385
|
+
const fail = (reason) => failNativeRequired(capability, reason);
|
|
386
|
+
if (isNativeDisabledByEnv()) {
|
|
387
|
+
return fail('native disabled');
|
|
388
|
+
}
|
|
389
|
+
const fn = readNativeFunction(capability);
|
|
390
|
+
if (!fn) {
|
|
391
|
+
return fail();
|
|
392
|
+
}
|
|
393
|
+
try {
|
|
394
|
+
const raw = fn();
|
|
395
|
+
if (typeof raw !== 'string' || !raw) {
|
|
396
|
+
return fail('empty result');
|
|
397
|
+
}
|
|
398
|
+
const parsed = parseHubProtocolAllowlists(raw);
|
|
399
|
+
return parsed ?? fail('invalid payload');
|
|
400
|
+
}
|
|
401
|
+
catch (error) {
|
|
402
|
+
const reason = error instanceof Error ? error.message : String(error ?? 'unknown');
|
|
403
|
+
return fail(reason);
|
|
404
|
+
}
|
|
405
|
+
}
|