@jsonstudio/llms 0.4.2
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/README.md +265 -0
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.js +11 -0
- package/dist/api/llmswitch-config.d.ts +15 -0
- package/dist/api/llmswitch-config.js +415 -0
- package/dist/api/llmswitch-types.d.ts +412 -0
- package/dist/api/llmswitch-types.js +60 -0
- package/dist/bridge/routecodex-adapter.d.ts +74 -0
- package/dist/bridge/routecodex-adapter.js +226 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.js +5 -0
- package/dist/config-unified/enhanced-path-resolver.d.ts +5 -0
- package/dist/config-unified/enhanced-path-resolver.js +38 -0
- package/dist/config-unified/unified-config.d.ts +26 -0
- package/dist/config-unified/unified-config.js +187 -0
- package/dist/conversion/codec-registry.d.ts +10 -0
- package/dist/conversion/codec-registry.js +25 -0
- package/dist/conversion/codecs/anthropic-openai-codec.d.ts +23 -0
- package/dist/conversion/codecs/anthropic-openai-codec.js +546 -0
- package/dist/conversion/codecs/gemini-openai-codec.d.ts +16 -0
- package/dist/conversion/codecs/gemini-openai-codec.js +437 -0
- package/dist/conversion/codecs/openai-openai-codec.d.ts +12 -0
- package/dist/conversion/codecs/openai-openai-codec.js +125 -0
- package/dist/conversion/codecs/responses-openai-codec.d.ts +12 -0
- package/dist/conversion/codecs/responses-openai-codec.js +154 -0
- package/dist/conversion/config/config-manager.d.ts +212 -0
- package/dist/conversion/config/config-manager.js +310 -0
- package/dist/conversion/conversion-v3/adapters/index.d.ts +2 -0
- package/dist/conversion/conversion-v3/adapters/index.js +1 -0
- package/dist/conversion/conversion-v3/adapters/v3-to-standard-adapter.d.ts +38 -0
- package/dist/conversion/conversion-v3/adapters/v3-to-standard-adapter.js +55 -0
- package/dist/conversion/conversion-v3/compatibility/compatibility-profiles.d.ts +22 -0
- package/dist/conversion/conversion-v3/compatibility/compatibility-profiles.js +84 -0
- package/dist/conversion/conversion-v3/compatibility/compatibility-stages.d.ts +4 -0
- package/dist/conversion/conversion-v3/compatibility/compatibility-stages.js +285 -0
- package/dist/conversion/conversion-v3/compatibility/index.d.ts +3 -0
- package/dist/conversion/conversion-v3/compatibility/index.js +2 -0
- package/dist/conversion/conversion-v3/config/default-configs.d.ts +48 -0
- package/dist/conversion/conversion-v3/config/default-configs.js +1083 -0
- package/dist/conversion/conversion-v3/config/index.d.ts +5 -0
- package/dist/conversion/conversion-v3/config/index.js +5 -0
- package/dist/conversion/conversion-v3/config/pipeline-config-manager.d.ts +49 -0
- package/dist/conversion/conversion-v3/config/pipeline-config-manager.js +65 -0
- package/dist/conversion/conversion-v3/index.d.ts +11 -0
- package/dist/conversion/conversion-v3/index.js +17 -0
- package/dist/conversion/conversion-v3/nodes/index.d.ts +56 -0
- package/dist/conversion/conversion-v3/nodes/index.js +149 -0
- package/dist/conversion/conversion-v3/nodes/input/anthropic-input-node.d.ts +25 -0
- package/dist/conversion/conversion-v3/nodes/input/anthropic-input-node.js +56 -0
- package/dist/conversion/conversion-v3/nodes/input/base-input-node.d.ts +75 -0
- package/dist/conversion/conversion-v3/nodes/input/base-input-node.js +237 -0
- package/dist/conversion/conversion-v3/nodes/input/chat-input-node.d.ts +25 -0
- package/dist/conversion/conversion-v3/nodes/input/chat-input-node.js +56 -0
- package/dist/conversion/conversion-v3/nodes/input/chat-shape-helpers.d.ts +4 -0
- package/dist/conversion/conversion-v3/nodes/input/chat-shape-helpers.js +197 -0
- package/dist/conversion/conversion-v3/nodes/input/gemini-input-node.d.ts +16 -0
- package/dist/conversion/conversion-v3/nodes/input/gemini-input-node.js +125 -0
- package/dist/conversion/conversion-v3/nodes/input/index.d.ts +8 -0
- package/dist/conversion/conversion-v3/nodes/input/index.js +8 -0
- package/dist/conversion/conversion-v3/nodes/input/input-decision.d.ts +46 -0
- package/dist/conversion/conversion-v3/nodes/input/input-decision.js +125 -0
- package/dist/conversion/conversion-v3/nodes/input/responses-input-node.d.ts +20 -0
- package/dist/conversion/conversion-v3/nodes/input/responses-input-node.js +51 -0
- package/dist/conversion/conversion-v3/nodes/output/anthropic-output-node.d.ts +71 -0
- package/dist/conversion/conversion-v3/nodes/output/anthropic-output-node.js +320 -0
- package/dist/conversion/conversion-v3/nodes/output/base-output-node.d.ts +116 -0
- package/dist/conversion/conversion-v3/nodes/output/base-output-node.js +512 -0
- package/dist/conversion/conversion-v3/nodes/output/index.d.ts +7 -0
- package/dist/conversion/conversion-v3/nodes/output/index.js +7 -0
- package/dist/conversion/conversion-v3/nodes/output/openai-output-node.d.ts +71 -0
- package/dist/conversion/conversion-v3/nodes/output/openai-output-node.js +293 -0
- package/dist/conversion/conversion-v3/nodes/output/output-decision.d.ts +68 -0
- package/dist/conversion/conversion-v3/nodes/output/output-decision.js +161 -0
- package/dist/conversion/conversion-v3/nodes/output/responses-output-node.d.ts +64 -0
- package/dist/conversion/conversion-v3/nodes/output/responses-output-node.js +323 -0
- package/dist/conversion/conversion-v3/nodes/process/base-process-node.d.ts +72 -0
- package/dist/conversion/conversion-v3/nodes/process/base-process-node.js +246 -0
- package/dist/conversion/conversion-v3/nodes/process/chat-process-node.d.ts +135 -0
- package/dist/conversion/conversion-v3/nodes/process/chat-process-node.js +854 -0
- package/dist/conversion/conversion-v3/nodes/process/compatibility-process-node.d.ts +29 -0
- package/dist/conversion/conversion-v3/nodes/process/compatibility-process-node.js +181 -0
- package/dist/conversion/conversion-v3/nodes/process/index.d.ts +10 -0
- package/dist/conversion/conversion-v3/nodes/process/index.js +10 -0
- package/dist/conversion/conversion-v3/nodes/process/passthrough-process-node.d.ts +59 -0
- package/dist/conversion/conversion-v3/nodes/process/passthrough-process-node.js +243 -0
- package/dist/conversion/conversion-v3/nodes/process/response-process-node.d.ts +17 -0
- package/dist/conversion/conversion-v3/nodes/process/response-process-node.js +213 -0
- package/dist/conversion/conversion-v3/nodes/process/tool-process-node.d.ts +26 -0
- package/dist/conversion/conversion-v3/nodes/process/tool-process-node.js +299 -0
- package/dist/conversion/conversion-v3/nodes/process/virtual-router-process-node.d.ts +40 -0
- package/dist/conversion/conversion-v3/nodes/process/virtual-router-process-node.js +430 -0
- package/dist/conversion/conversion-v3/nodes/response/anthropic-response-input-node.d.ts +12 -0
- package/dist/conversion/conversion-v3/nodes/response/anthropic-response-input-node.js +129 -0
- package/dist/conversion/conversion-v3/nodes/response/chat-to-responses-response-node.d.ts +15 -0
- package/dist/conversion/conversion-v3/nodes/response/chat-to-responses-response-node.js +57 -0
- package/dist/conversion/conversion-v3/nodes/response/index.d.ts +4 -0
- package/dist/conversion/conversion-v3/nodes/response/index.js +4 -0
- package/dist/conversion/conversion-v3/nodes/response/openai-response-input-node.d.ts +15 -0
- package/dist/conversion/conversion-v3/nodes/response/openai-response-input-node.js +87 -0
- package/dist/conversion/conversion-v3/nodes/response/response-utils.d.ts +1 -0
- package/dist/conversion/conversion-v3/nodes/response/response-utils.js +1 -0
- package/dist/conversion/conversion-v3/nodes/response/responses-response-input-node.d.ts +12 -0
- package/dist/conversion/conversion-v3/nodes/response/responses-response-input-node.js +67 -0
- package/dist/conversion/conversion-v3/nodes/sse/index.d.ts +3 -0
- package/dist/conversion/conversion-v3/nodes/sse/index.js +3 -0
- package/dist/conversion/conversion-v3/nodes/sse/sse-input-node.d.ts +27 -0
- package/dist/conversion/conversion-v3/nodes/sse/sse-input-node.js +165 -0
- package/dist/conversion/conversion-v3/nodes/sse/sse-output-node.d.ts +19 -0
- package/dist/conversion/conversion-v3/nodes/sse/sse-output-node.js +267 -0
- package/dist/conversion/conversion-v3/nodes/sse/sse-passthrough-node.d.ts +18 -0
- package/dist/conversion/conversion-v3/nodes/sse/sse-passthrough-node.js +48 -0
- package/dist/conversion/conversion-v3/pipelines/index.d.ts +6 -0
- package/dist/conversion/conversion-v3/pipelines/index.js +6 -0
- package/dist/conversion/conversion-v3/pipelines/super-pipeline.d.ts +112 -0
- package/dist/conversion/conversion-v3/pipelines/super-pipeline.js +566 -0
- package/dist/conversion/conversion-v3/response/provider-response-converter.d.ts +28 -0
- package/dist/conversion/conversion-v3/response/provider-response-converter.js +249 -0
- package/dist/conversion/conversion-v3/sse/index.d.ts +140 -0
- package/dist/conversion/conversion-v3/sse/index.js +115 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/anthropic-json-to-sse-converter.d.ts +11 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/anthropic-json-to-sse-converter.js +79 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/chat-json-to-sse-converter.d.ts +79 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/chat-json-to-sse-converter.js +296 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/chat.d.ts +55 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/chat.js +233 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/responses.d.ts +99 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/responses.js +599 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/index.d.ts +6 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/index.js +7 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/responses-json-to-sse-converter.d.ts +79 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/responses-json-to-sse-converter.js +322 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/chat-sequencer.d.ts +37 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/chat-sequencer.js +218 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/responses-sequencer.d.ts +40 -0
- package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/responses-sequencer.js +263 -0
- package/dist/conversion/conversion-v3/sse/registry/sse-codec-registry.d.ts +32 -0
- package/dist/conversion/conversion-v3/sse/registry/sse-codec-registry.js +106 -0
- package/dist/conversion/conversion-v3/sse/shared/chat-serializer.d.ts +4 -0
- package/dist/conversion/conversion-v3/sse/shared/chat-serializer.js +40 -0
- package/dist/conversion/conversion-v3/sse/shared/constants.d.ts +272 -0
- package/dist/conversion/conversion-v3/sse/shared/constants.js +321 -0
- package/dist/conversion/conversion-v3/sse/shared/serializers/base-serializer.d.ts +158 -0
- package/dist/conversion/conversion-v3/sse/shared/serializers/base-serializer.js +210 -0
- package/dist/conversion/conversion-v3/sse/shared/serializers/chat-event-serializer.d.ts +82 -0
- package/dist/conversion/conversion-v3/sse/shared/serializers/chat-event-serializer.js +275 -0
- package/dist/conversion/conversion-v3/sse/shared/serializers/index.d.ts +39 -0
- package/dist/conversion/conversion-v3/sse/shared/serializers/index.js +54 -0
- package/dist/conversion/conversion-v3/sse/shared/serializers/responses-event-serializer.d.ts +123 -0
- package/dist/conversion/conversion-v3/sse/shared/serializers/responses-event-serializer.js +356 -0
- package/dist/conversion/conversion-v3/sse/shared/serializers/types.d.ts +51 -0
- package/dist/conversion/conversion-v3/sse/shared/serializers/types.js +4 -0
- package/dist/conversion/conversion-v3/sse/shared/utils.d.ts +254 -0
- package/dist/conversion/conversion-v3/sse/shared/utils.js +543 -0
- package/dist/conversion/conversion-v3/sse/shared/writer.d.ts +111 -0
- package/dist/conversion/conversion-v3/sse/shared/writer.js +268 -0
- package/dist/conversion/conversion-v3/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +13 -0
- package/dist/conversion/conversion-v3/sse/sse-to-json/anthropic-sse-to-json-converter.js +139 -0
- package/dist/conversion/conversion-v3/sse/sse-to-json/builders/response-builder.d.ts +165 -0
- package/dist/conversion/conversion-v3/sse/sse-to-json/builders/response-builder.js +776 -0
- package/dist/conversion/conversion-v3/sse/sse-to-json/chat-sse-to-json-converter.d.ts +106 -0
- package/dist/conversion/conversion-v3/sse/sse-to-json/chat-sse-to-json-converter.js +540 -0
- package/dist/conversion/conversion-v3/sse/sse-to-json/index.d.ts +6 -0
- package/dist/conversion/conversion-v3/sse/sse-to-json/index.js +7 -0
- package/dist/conversion/conversion-v3/sse/sse-to-json/parsers/sse-parser.d.ts +73 -0
- package/dist/conversion/conversion-v3/sse/sse-to-json/parsers/sse-parser.js +332 -0
- package/dist/conversion/conversion-v3/sse/sse-to-json/responses-sse-to-json-converter.d.ts +59 -0
- package/dist/conversion/conversion-v3/sse/sse-to-json/responses-sse-to-json-converter.js +270 -0
- package/dist/conversion/conversion-v3/sse/types/anthropic-types.d.ts +87 -0
- package/dist/conversion/conversion-v3/sse/types/anthropic-types.js +5 -0
- package/dist/conversion/conversion-v3/sse/types/chat-types.d.ts +308 -0
- package/dist/conversion/conversion-v3/sse/types/chat-types.js +32 -0
- package/dist/conversion/conversion-v3/sse/types/conversion-context.d.ts +211 -0
- package/dist/conversion/conversion-v3/sse/types/conversion-context.js +20 -0
- package/dist/conversion/conversion-v3/sse/types/core-interfaces.d.ts +90 -0
- package/dist/conversion/conversion-v3/sse/types/core-interfaces.js +5 -0
- package/dist/conversion/conversion-v3/sse/types/index.d.ts +14 -0
- package/dist/conversion/conversion-v3/sse/types/index.js +7 -0
- package/dist/conversion/conversion-v3/sse/types/responses-types.d.ts +328 -0
- package/dist/conversion/conversion-v3/sse/types/responses-types.js +38 -0
- package/dist/conversion/conversion-v3/sse/types/sse-events.d.ts +180 -0
- package/dist/conversion/conversion-v3/sse/types/sse-events.js +150 -0
- package/dist/conversion/conversion-v3/sse/types/stream-state.d.ts +204 -0
- package/dist/conversion/conversion-v3/sse/types/stream-state.js +44 -0
- package/dist/conversion/conversion-v3/sse/types/utility-types.d.ts +230 -0
- package/dist/conversion/conversion-v3/sse/types/utility-types.js +49 -0
- package/dist/conversion/conversion-v3/standards/context-adapter.d.ts +146 -0
- package/dist/conversion/conversion-v3/standards/context-adapter.js +438 -0
- package/dist/conversion/conversion-v3/standards/errors.d.ts +38 -0
- package/dist/conversion/conversion-v3/standards/errors.js +27 -0
- package/dist/conversion/conversion-v3/standards/index.d.ts +15 -0
- package/dist/conversion/conversion-v3/standards/index.js +11 -0
- package/dist/conversion/conversion-v3/standards/node-capabilities.d.ts +123 -0
- package/dist/conversion/conversion-v3/standards/node-capabilities.js +330 -0
- package/dist/conversion/conversion-v3/standards/pipeline-context.d.ts +237 -0
- package/dist/conversion/conversion-v3/standards/pipeline-context.js +84 -0
- package/dist/conversion/conversion-v3/standards/pipeline-node.d.ts +196 -0
- package/dist/conversion/conversion-v3/standards/pipeline-node.js +316 -0
- package/dist/conversion/conversion-v3/standards/snapshot-handles.d.ts +24 -0
- package/dist/conversion/conversion-v3/standards/snapshot-handles.js +49 -0
- package/dist/conversion/conversion-v3/types/config-types.d.ts +242 -0
- package/dist/conversion/conversion-v3/types/config-types.js +13 -0
- package/dist/conversion/conversion-v3/types/index.d.ts +8 -0
- package/dist/conversion/conversion-v3/types/index.js +11 -0
- package/dist/conversion/conversion-v3/types/node-types.d.ts +211 -0
- package/dist/conversion/conversion-v3/types/node-types.js +20 -0
- package/dist/conversion/conversion-v3/types/pipeline-types.d.ts +246 -0
- package/dist/conversion/conversion-v3/types/pipeline-types.js +26 -0
- package/dist/conversion/conversion-v3/types/request-types.d.ts +293 -0
- package/dist/conversion/conversion-v3/types/request-types.js +26 -0
- package/dist/conversion/conversion-v3/utils/provider-payload-sanitizer.d.ts +10 -0
- package/dist/conversion/conversion-v3/utils/provider-payload-sanitizer.js +103 -0
- package/dist/conversion/conversion-v3/validations/index.d.ts +8 -0
- package/dist/conversion/conversion-v3/validations/index.js +7 -0
- package/dist/conversion/conversion-v3/validations/node-graph-validator.d.ts +116 -0
- package/dist/conversion/conversion-v3/validations/node-graph-validator.js +505 -0
- package/dist/conversion/conversion-v3/validations/tool-governance-enforcer.d.ts +139 -0
- package/dist/conversion/conversion-v3/validations/tool-governance-enforcer.js +338 -0
- package/dist/conversion/hub/config/types.d.ts +26 -0
- package/dist/conversion/hub/config/types.js +1 -0
- package/dist/conversion/hub/core/detour-registry.d.ts +9 -0
- package/dist/conversion/hub/core/detour-registry.js +23 -0
- package/dist/conversion/hub/core/hub-context.d.ts +21 -0
- package/dist/conversion/hub/core/hub-context.js +1 -0
- package/dist/conversion/hub/core/index.d.ts +3 -0
- package/dist/conversion/hub/core/index.js +3 -0
- package/dist/conversion/hub/core/stage-driver.d.ts +30 -0
- package/dist/conversion/hub/core/stage-driver.js +31 -0
- package/dist/conversion/hub/format-adapters/anthropic-format-adapter.d.ts +16 -0
- package/dist/conversion/hub/format-adapters/anthropic-format-adapter.js +23 -0
- package/dist/conversion/hub/format-adapters/chat-format-adapter.d.ts +17 -0
- package/dist/conversion/hub/format-adapters/chat-format-adapter.js +23 -0
- package/dist/conversion/hub/format-adapters/gemini-format-adapter.d.ts +16 -0
- package/dist/conversion/hub/format-adapters/gemini-format-adapter.js +23 -0
- package/dist/conversion/hub/format-adapters/index.d.ts +21 -0
- package/dist/conversion/hub/format-adapters/index.js +4 -0
- package/dist/conversion/hub/format-adapters/responses-format-adapter.d.ts +17 -0
- package/dist/conversion/hub/format-adapters/responses-format-adapter.js +23 -0
- package/dist/conversion/hub/hub-feature.d.ts +1 -0
- package/dist/conversion/hub/hub-feature.js +25 -0
- package/dist/conversion/hub/node-support.d.ts +19 -0
- package/dist/conversion/hub/node-support.js +115 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +68 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +421 -0
- package/dist/conversion/hub/pipelines/inbound.d.ts +22 -0
- package/dist/conversion/hub/pipelines/inbound.js +64 -0
- package/dist/conversion/hub/pipelines/outbound.d.ts +22 -0
- package/dist/conversion/hub/pipelines/outbound.js +57 -0
- package/dist/conversion/hub/process/chat-process.d.ts +13 -0
- package/dist/conversion/hub/process/chat-process.js +50 -0
- package/dist/conversion/hub/registry.d.ts +28 -0
- package/dist/conversion/hub/registry.js +98 -0
- package/dist/conversion/hub/response/chat-response-utils.d.ts +6 -0
- package/dist/conversion/hub/response/chat-response-utils.js +89 -0
- package/dist/conversion/hub/response/provider-response.d.ts +20 -0
- package/dist/conversion/hub/response/provider-response.js +196 -0
- package/dist/conversion/hub/response/response-mappers.d.ts +19 -0
- package/dist/conversion/hub/response/response-mappers.js +23 -0
- package/dist/conversion/hub/response/response-runtime.d.ts +3 -0
- package/dist/conversion/hub/response/response-runtime.js +206 -0
- package/dist/conversion/hub/semantic-mappers/anthropic-mapper.d.ts +7 -0
- package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +308 -0
- package/dist/conversion/hub/semantic-mappers/chat-mapper.d.ts +7 -0
- package/dist/conversion/hub/semantic-mappers/chat-mapper.js +304 -0
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.d.ts +7 -0
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +477 -0
- package/dist/conversion/hub/semantic-mappers/index.d.ts +4 -0
- package/dist/conversion/hub/semantic-mappers/index.js +4 -0
- package/dist/conversion/hub/semantic-mappers/responses-mapper.d.ts +21 -0
- package/dist/conversion/hub/semantic-mappers/responses-mapper.js +379 -0
- package/dist/conversion/hub/snapshot-recorder.d.ts +12 -0
- package/dist/conversion/hub/snapshot-recorder.js +69 -0
- package/dist/conversion/hub/standardized-bridge.d.ts +12 -0
- package/dist/conversion/hub/standardized-bridge.js +248 -0
- package/dist/conversion/hub/types/chat-envelope.d.ts +67 -0
- package/dist/conversion/hub/types/chat-envelope.js +1 -0
- package/dist/conversion/hub/types/chat-schema.d.ts +112 -0
- package/dist/conversion/hub/types/chat-schema.js +1 -0
- package/dist/conversion/hub/types/errors.d.ts +5 -0
- package/dist/conversion/hub/types/errors.js +13 -0
- package/dist/conversion/hub/types/format-envelope.d.ts +7 -0
- package/dist/conversion/hub/types/format-envelope.js +1 -0
- package/dist/conversion/hub/types/index.d.ts +6 -0
- package/dist/conversion/hub/types/index.js +6 -0
- package/dist/conversion/hub/types/json.d.ts +9 -0
- package/dist/conversion/hub/types/json.js +9 -0
- package/dist/conversion/hub/types/node.d.ts +31 -0
- package/dist/conversion/hub/types/node.js +1 -0
- package/dist/conversion/hub/types/standardized.d.ts +94 -0
- package/dist/conversion/hub/types/standardized.js +1 -0
- package/dist/conversion/index.d.ts +28 -0
- package/dist/conversion/index.js +28 -0
- package/dist/conversion/responses/responses-openai-bridge.d.ts +95 -0
- package/dist/conversion/responses/responses-openai-bridge.js +1330 -0
- package/dist/conversion/schema-validator.d.ts +7 -0
- package/dist/conversion/schema-validator.js +67 -0
- package/dist/conversion/shared/args-mapping.d.ts +18 -0
- package/dist/conversion/shared/args-mapping.js +213 -0
- package/dist/conversion/shared/chat-request-filters.d.ts +9 -0
- package/dist/conversion/shared/chat-request-filters.js +74 -0
- package/dist/conversion/shared/jsonish.d.ts +3 -0
- package/dist/conversion/shared/jsonish.js +177 -0
- package/dist/conversion/shared/mcp-injection.d.ts +2 -0
- package/dist/conversion/shared/mcp-injection.js +89 -0
- package/dist/conversion/shared/media.d.ts +1 -0
- package/dist/conversion/shared/media.js +9 -0
- package/dist/conversion/shared/openai-finalizer.d.ts +9 -0
- package/dist/conversion/shared/openai-finalizer.js +104 -0
- package/dist/conversion/shared/openai-message-normalize.d.ts +1 -0
- package/dist/conversion/shared/openai-message-normalize.js +442 -0
- package/dist/conversion/shared/payload-budget.d.ts +13 -0
- package/dist/conversion/shared/payload-budget.js +248 -0
- package/dist/conversion/shared/reasoning-mapping.d.ts +5 -0
- package/dist/conversion/shared/reasoning-mapping.js +8 -0
- package/dist/conversion/shared/responses-conversation-store.d.ts +41 -0
- package/dist/conversion/shared/responses-conversation-store.js +285 -0
- package/dist/conversion/shared/responses-id-utils.d.ts +7 -0
- package/dist/conversion/shared/responses-id-utils.js +29 -0
- package/dist/conversion/shared/responses-instructions.d.ts +1 -0
- package/dist/conversion/shared/responses-instructions.js +113 -0
- package/dist/conversion/shared/responses-metadata.d.ts +1 -0
- package/dist/conversion/shared/responses-metadata.js +1 -0
- package/dist/conversion/shared/responses-request-adapter.d.ts +66 -0
- package/dist/conversion/shared/responses-request-adapter.js +461 -0
- package/dist/conversion/shared/snapshot-hooks.d.ts +12 -0
- package/dist/conversion/shared/snapshot-hooks.js +7 -0
- package/dist/conversion/shared/streaming-text-extractor.d.ts +26 -0
- package/dist/conversion/shared/streaming-text-extractor.js +145 -0
- package/dist/conversion/shared/text-markup-normalizer.d.ts +9 -0
- package/dist/conversion/shared/text-markup-normalizer.js +319 -0
- package/dist/conversion/shared/tool-canonicalizer.d.ts +2 -0
- package/dist/conversion/shared/tool-canonicalizer.js +50 -0
- package/dist/conversion/shared/tool-filter-pipeline.d.ts +17 -0
- package/dist/conversion/shared/tool-filter-pipeline.js +79 -0
- package/dist/conversion/shared/tool-governor.d.ts +27 -0
- package/dist/conversion/shared/tool-governor.js +269 -0
- package/dist/conversion/shared/tool-harvester.d.ts +31 -0
- package/dist/conversion/shared/tool-harvester.js +321 -0
- package/dist/conversion/shared/tool-mapping.d.ts +10 -0
- package/dist/conversion/shared/tool-mapping.js +10 -0
- package/dist/conversion/shared/tooling.d.ts +26 -0
- package/dist/conversion/shared/tooling.js +143 -0
- package/dist/conversion/types.d.ts +33 -0
- package/dist/conversion/types.js +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.js +9 -0
- package/dist/core/llmswitch-engine-v2.d.ts +132 -0
- package/dist/core/llmswitch-engine-v2.js +649 -0
- package/dist/core/llmswitch-factory-v2.d.ts +123 -0
- package/dist/core/llmswitch-factory-v2.js +521 -0
- package/dist/endpoints/base-endpoint-handler.d.ts +128 -0
- package/dist/endpoints/base-endpoint-handler.js +545 -0
- package/dist/endpoints/chat-endpoint-handler.d.ts +115 -0
- package/dist/endpoints/chat-endpoint-handler.js +218 -0
- package/dist/endpoints/endpoint-router.d.ts +127 -0
- package/dist/endpoints/endpoint-router.js +438 -0
- package/dist/endpoints/index.d.ts +13 -0
- package/dist/endpoints/index.js +11 -0
- package/dist/endpoints/messages-endpoint-handler.d.ts +171 -0
- package/dist/endpoints/messages-endpoint-handler.js +238 -0
- package/dist/endpoints/responses-endpoint-handler.d.ts +147 -0
- package/dist/endpoints/responses-endpoint-handler.js +233 -0
- package/dist/filters/builtin/add-fields-filter.d.ts +8 -0
- package/dist/filters/builtin/add-fields-filter.js +16 -0
- package/dist/filters/builtin/blacklist-filter.d.ts +8 -0
- package/dist/filters/builtin/blacklist-filter.js +19 -0
- package/dist/filters/builtin/whitelist-filter.d.ts +8 -0
- package/dist/filters/builtin/whitelist-filter.js +19 -0
- package/dist/filters/engine.d.ts +16 -0
- package/dist/filters/engine.js +167 -0
- package/dist/filters/index.d.ts +19 -0
- package/dist/filters/index.js +24 -0
- package/dist/filters/special/request-streaming-to-nonstreaming.d.ts +12 -0
- package/dist/filters/special/request-streaming-to-nonstreaming.js +27 -0
- package/dist/filters/special/request-tool-choice-policy.d.ts +11 -0
- package/dist/filters/special/request-tool-choice-policy.js +27 -0
- package/dist/filters/special/request-tool-list-filter.d.ts +11 -0
- package/dist/filters/special/request-tool-list-filter.js +167 -0
- package/dist/filters/special/request-toolcalls-stringify.d.ts +10 -0
- package/dist/filters/special/request-toolcalls-stringify.js +44 -0
- package/dist/filters/special/request-tools-normalize.d.ts +12 -0
- package/dist/filters/special/request-tools-normalize.js +140 -0
- package/dist/filters/special/response-finish-invariants.d.ts +11 -0
- package/dist/filters/special/response-finish-invariants.js +30 -0
- package/dist/filters/special/response-openai-to-responses-bridge.d.ts +13 -0
- package/dist/filters/special/response-openai-to-responses-bridge.js +24 -0
- package/dist/filters/special/response-tool-arguments-blacklist.d.ts +12 -0
- package/dist/filters/special/response-tool-arguments-blacklist.js +63 -0
- package/dist/filters/special/response-tool-arguments-schema-converge.d.ts +13 -0
- package/dist/filters/special/response-tool-arguments-schema-converge.js +63 -0
- package/dist/filters/special/response-tool-arguments-stringify.d.ts +9 -0
- package/dist/filters/special/response-tool-arguments-stringify.js +134 -0
- package/dist/filters/special/response-tool-arguments-toon-decode.d.ts +10 -0
- package/dist/filters/special/response-tool-arguments-toon-decode.js +94 -0
- package/dist/filters/special/response-tool-arguments-whitelist.d.ts +11 -0
- package/dist/filters/special/response-tool-arguments-whitelist.js +56 -0
- package/dist/filters/special/response-tool-text-canonicalize.d.ts +10 -0
- package/dist/filters/special/response-tool-text-canonicalize.js +20 -0
- package/dist/filters/special/tool-filter-hooks.d.ts +19 -0
- package/dist/filters/special/tool-filter-hooks.js +341 -0
- package/dist/filters/special/tool-post-constraints.d.ts +31 -0
- package/dist/filters/special/tool-post-constraints.js +120 -0
- package/dist/filters/types.d.ts +68 -0
- package/dist/filters/types.js +3 -0
- package/dist/filters/utils/fieldmap-loader.d.ts +2 -0
- package/dist/filters/utils/fieldmap-loader.js +16 -0
- package/dist/filters/utils/snapshot-writer.d.ts +10 -0
- package/dist/filters/utils/snapshot-writer.js +47 -0
- package/dist/guidance/index.d.ts +3 -0
- package/dist/guidance/index.js +228 -0
- package/dist/hooks/hooks-integration.d.ts +161 -0
- package/dist/hooks/hooks-integration.js +519 -0
- package/dist/hooks/index.d.ts +10 -0
- package/dist/hooks/index.js +13 -0
- package/dist/html-to-markdown.d.ts +5 -0
- package/dist/html-to-markdown.js +66 -0
- package/dist/http/sse-response.d.ts +22 -0
- package/dist/http/sse-response.js +103 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/router/virtual-router/bootstrap.d.ts +6 -0
- package/dist/router/virtual-router/bootstrap.js +620 -0
- package/dist/router/virtual-router/classifier.d.ts +10 -0
- package/dist/router/virtual-router/classifier.js +99 -0
- package/dist/router/virtual-router/engine.d.ts +35 -0
- package/dist/router/virtual-router/engine.js +260 -0
- package/dist/router/virtual-router/error-center.d.ts +10 -0
- package/dist/router/virtual-router/error-center.js +39 -0
- package/dist/router/virtual-router/features.d.ts +3 -0
- package/dist/router/virtual-router/features.js +162 -0
- package/dist/router/virtual-router/health-manager.d.ts +18 -0
- package/dist/router/virtual-router/health-manager.js +98 -0
- package/dist/router/virtual-router/load-balancer.d.ts +18 -0
- package/dist/router/virtual-router/load-balancer.js +67 -0
- package/dist/router/virtual-router/provider-registry.d.ts +11 -0
- package/dist/router/virtual-router/provider-registry.js +74 -0
- package/dist/router/virtual-router/types.d.ts +206 -0
- package/dist/router/virtual-router/types.js +31 -0
- package/dist/sse/index.d.ts +140 -0
- package/dist/sse/index.js +115 -0
- package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.d.ts +11 -0
- package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.js +79 -0
- package/dist/sse/json-to-sse/chat-json-to-sse-converter.d.ts +79 -0
- package/dist/sse/json-to-sse/chat-json-to-sse-converter.js +296 -0
- package/dist/sse/json-to-sse/event-generators/chat.d.ts +55 -0
- package/dist/sse/json-to-sse/event-generators/chat.js +233 -0
- package/dist/sse/json-to-sse/event-generators/responses.d.ts +99 -0
- package/dist/sse/json-to-sse/event-generators/responses.js +599 -0
- package/dist/sse/json-to-sse/index.d.ts +6 -0
- package/dist/sse/json-to-sse/index.js +7 -0
- package/dist/sse/json-to-sse/responses-json-to-sse-converter.d.ts +79 -0
- package/dist/sse/json-to-sse/responses-json-to-sse-converter.js +322 -0
- package/dist/sse/json-to-sse/sequencers/chat-sequencer.d.ts +37 -0
- package/dist/sse/json-to-sse/sequencers/chat-sequencer.js +218 -0
- package/dist/sse/json-to-sse/sequencers/responses-sequencer.d.ts +40 -0
- package/dist/sse/json-to-sse/sequencers/responses-sequencer.js +263 -0
- package/dist/sse/registry/sse-codec-registry.d.ts +32 -0
- package/dist/sse/registry/sse-codec-registry.js +106 -0
- package/dist/sse/shared/chat-serializer.d.ts +4 -0
- package/dist/sse/shared/chat-serializer.js +40 -0
- package/dist/sse/shared/constants.d.ts +272 -0
- package/dist/sse/shared/constants.js +321 -0
- package/dist/sse/shared/serializers/base-serializer.d.ts +158 -0
- package/dist/sse/shared/serializers/base-serializer.js +210 -0
- package/dist/sse/shared/serializers/chat-event-serializer.d.ts +82 -0
- package/dist/sse/shared/serializers/chat-event-serializer.js +275 -0
- package/dist/sse/shared/serializers/index.d.ts +39 -0
- package/dist/sse/shared/serializers/index.js +54 -0
- package/dist/sse/shared/serializers/responses-event-serializer.d.ts +123 -0
- package/dist/sse/shared/serializers/responses-event-serializer.js +356 -0
- package/dist/sse/shared/serializers/types.d.ts +51 -0
- package/dist/sse/shared/serializers/types.js +4 -0
- package/dist/sse/shared/utils.d.ts +254 -0
- package/dist/sse/shared/utils.js +543 -0
- package/dist/sse/shared/writer.d.ts +111 -0
- package/dist/sse/shared/writer.js +268 -0
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +13 -0
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +139 -0
- package/dist/sse/sse-to-json/builders/response-builder.d.ts +165 -0
- package/dist/sse/sse-to-json/builders/response-builder.js +776 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +106 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +540 -0
- package/dist/sse/sse-to-json/index.d.ts +6 -0
- package/dist/sse/sse-to-json/index.js +7 -0
- package/dist/sse/sse-to-json/parsers/sse-parser.d.ts +73 -0
- package/dist/sse/sse-to-json/parsers/sse-parser.js +340 -0
- package/dist/sse/sse-to-json/responses-sse-to-json-converter.d.ts +59 -0
- package/dist/sse/sse-to-json/responses-sse-to-json-converter.js +270 -0
- package/dist/sse/types/anthropic-types.d.ts +87 -0
- package/dist/sse/types/anthropic-types.js +5 -0
- package/dist/sse/types/chat-types.d.ts +308 -0
- package/dist/sse/types/chat-types.js +32 -0
- package/dist/sse/types/conversion-context.d.ts +211 -0
- package/dist/sse/types/conversion-context.js +20 -0
- package/dist/sse/types/core-interfaces.d.ts +90 -0
- package/dist/sse/types/core-interfaces.js +5 -0
- package/dist/sse/types/index.d.ts +14 -0
- package/dist/sse/types/index.js +7 -0
- package/dist/sse/types/responses-types.d.ts +328 -0
- package/dist/sse/types/responses-types.js +38 -0
- package/dist/sse/types/sse-events.d.ts +180 -0
- package/dist/sse/types/sse-events.js +150 -0
- package/dist/sse/types/stream-state.d.ts +204 -0
- package/dist/sse/types/stream-state.js +44 -0
- package/dist/sse/types/utility-types.d.ts +230 -0
- package/dist/sse/types/utility-types.js +49 -0
- package/dist/tools/proxy/anthropic-tool-proxy.d.ts +19 -0
- package/dist/tools/proxy/anthropic-tool-proxy.js +57 -0
- package/dist/tools/proxy/executors/web-fetch.d.ts +6 -0
- package/dist/tools/proxy/executors/web-fetch.js +39 -0
- package/dist/tools/proxy/registry.d.ts +8 -0
- package/dist/tools/proxy/registry.js +14 -0
- package/dist/tools/proxy/types.d.ts +29 -0
- package/dist/tools/proxy/types.js +1 -0
- package/dist/tools/tool-registry.d.ts +8 -0
- package/dist/tools/tool-registry.js +154 -0
- package/dist/tools/web-fetch-html.d.ts +15 -0
- package/dist/tools/web-fetch-html.js +83 -0
- package/dist/utils/conversion-adapter.d.ts +65 -0
- package/dist/utils/conversion-adapter.js +183 -0
- package/dist/utils/error-factory.d.ts +88 -0
- package/dist/utils/error-factory.js +138 -0
- package/dist/utils/error-utils.d.ts +334 -0
- package/dist/utils/error-utils.js +782 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.js +13 -0
- package/dist/utils/performance-utils.d.ts +205 -0
- package/dist/utils/performance-utils.js +440 -0
- package/dist/utils/profile-mapper.d.ts +32 -0
- package/dist/utils/profile-mapper.js +269 -0
- package/dist/utils/request-processor.d.ts +52 -0
- package/dist/utils/request-processor.js +210 -0
- package/dist/utils/request-utils.d.ts +117 -0
- package/dist/utils/request-utils.js +333 -0
- package/dist/utils/response-utils.d.ts +127 -0
- package/dist/utils/response-utils.js +516 -0
- package/dist/utils/token-counter.d.ts +89 -0
- package/dist/utils/token-counter.js +541 -0
- package/package.json +65 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { DEFAULT_ROUTE, ROUTE_PRIORITY } from './types.js';
|
|
2
|
+
const DEFAULT_LONG_CONTEXT_THRESHOLD = 60000;
|
|
3
|
+
export class RoutingClassifier {
|
|
4
|
+
config;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = {
|
|
7
|
+
longContextThresholdTokens: config.longContextThresholdTokens ?? DEFAULT_LONG_CONTEXT_THRESHOLD,
|
|
8
|
+
thinkingKeywords: normalizeList(config.thinkingKeywords, ['think step', 'analysis', 'reasoning']),
|
|
9
|
+
backgroundKeywords: normalizeList(config.backgroundKeywords, ['background', 'context dump'])
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
classify(features) {
|
|
13
|
+
const evaluations = [
|
|
14
|
+
{
|
|
15
|
+
route: 'vision',
|
|
16
|
+
triggered: features.hasVisionTool && features.hasImageAttachment,
|
|
17
|
+
reason: 'vision:requires-tool+image'
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
route: 'websearch',
|
|
21
|
+
triggered: features.hasWebTool,
|
|
22
|
+
reason: 'websearch:web-tools-detected'
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
route: 'coding',
|
|
26
|
+
triggered: features.hasCodingTool,
|
|
27
|
+
reason: 'coding:coding-tools-detected'
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
route: 'tools',
|
|
31
|
+
triggered: features.hasTools || features.hasToolCallResponses,
|
|
32
|
+
reason: 'tools:tool-request-detected'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
route: 'longcontext',
|
|
36
|
+
triggered: features.estimatedTokens >= (this.config.longContextThresholdTokens ?? DEFAULT_LONG_CONTEXT_THRESHOLD),
|
|
37
|
+
reason: 'longcontext:token-threshold'
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
route: 'thinking',
|
|
41
|
+
triggered: features.hasThinkingKeyword ||
|
|
42
|
+
containsKeywords(features.userTextSample, this.config.thinkingKeywords ?? []),
|
|
43
|
+
reason: 'thinking:keywords'
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
route: 'background',
|
|
47
|
+
triggered: containsKeywords(features.userTextSample, this.config.backgroundKeywords ?? []),
|
|
48
|
+
reason: 'background:keywords'
|
|
49
|
+
}
|
|
50
|
+
];
|
|
51
|
+
const triggeredEvaluations = evaluations.filter((evaluation) => evaluation.triggered);
|
|
52
|
+
const orderedRoutes = this.orderRoutes(triggeredEvaluations.map((entry) => entry.route));
|
|
53
|
+
const chosenRoute = orderedRoutes.length ? orderedRoutes[0] : DEFAULT_ROUTE;
|
|
54
|
+
const chosenReason = triggeredEvaluations.find((entry) => entry.route === chosenRoute)?.reason || 'fallback:default';
|
|
55
|
+
const candidates = this.ensureDefaultCandidate(orderedRoutes);
|
|
56
|
+
return this.buildResult(chosenRoute, chosenReason, evaluations, candidates);
|
|
57
|
+
}
|
|
58
|
+
buildResult(routeName, chosenReason, evaluations, candidates) {
|
|
59
|
+
const diagnostics = evaluations
|
|
60
|
+
.filter((evaluation) => evaluation.triggered)
|
|
61
|
+
.map((evaluation) => evaluation.reason);
|
|
62
|
+
const reasoningParts = [chosenReason, ...diagnostics.filter((reason) => reason !== chosenReason)];
|
|
63
|
+
return {
|
|
64
|
+
routeName,
|
|
65
|
+
confidence: 0.9,
|
|
66
|
+
reasoning: reasoningParts.join('|'),
|
|
67
|
+
fallback: routeName === DEFAULT_ROUTE,
|
|
68
|
+
candidates: candidates.length ? candidates : [DEFAULT_ROUTE]
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
ensureDefaultCandidate(routes) {
|
|
72
|
+
const deduped = routes.filter(Boolean);
|
|
73
|
+
if (!deduped.includes(DEFAULT_ROUTE)) {
|
|
74
|
+
deduped.push(DEFAULT_ROUTE);
|
|
75
|
+
}
|
|
76
|
+
return deduped;
|
|
77
|
+
}
|
|
78
|
+
orderRoutes(routes) {
|
|
79
|
+
const unique = Array.from(new Set(routes.filter(Boolean)));
|
|
80
|
+
return unique.sort((a, b) => this.routeWeight(a) - this.routeWeight(b));
|
|
81
|
+
}
|
|
82
|
+
routeWeight(route) {
|
|
83
|
+
const index = ROUTE_PRIORITY.indexOf(route);
|
|
84
|
+
return index >= 0 ? index : ROUTE_PRIORITY.length;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function normalizeList(source, fallback) {
|
|
88
|
+
if (!source || source.length === 0) {
|
|
89
|
+
return fallback;
|
|
90
|
+
}
|
|
91
|
+
return source.map((item) => item.toLowerCase());
|
|
92
|
+
}
|
|
93
|
+
function containsKeywords(text, keywords) {
|
|
94
|
+
if (!text || !keywords.length) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
const normalized = text.toLowerCase();
|
|
98
|
+
return keywords.some((keyword) => normalized.includes(keyword));
|
|
99
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type RoutingDecision, type RoutingDiagnostics, type RouterMetadataInput, type VirtualRouterConfig, type TargetMetadata, type ProviderFailureEvent, type ProviderErrorEvent } from './types.js';
|
|
2
|
+
import type { ProcessedRequest, StandardizedRequest } from '../../conversion/hub/types/standardized.js';
|
|
3
|
+
export declare class VirtualRouterEngine {
|
|
4
|
+
private routing;
|
|
5
|
+
private readonly providerRegistry;
|
|
6
|
+
private readonly healthManager;
|
|
7
|
+
private loadBalancer;
|
|
8
|
+
private classifier;
|
|
9
|
+
private routeStats;
|
|
10
|
+
initialize(config: VirtualRouterConfig): void;
|
|
11
|
+
route(request: StandardizedRequest | ProcessedRequest, metadata: RouterMetadataInput): {
|
|
12
|
+
target: TargetMetadata;
|
|
13
|
+
decision: RoutingDecision;
|
|
14
|
+
diagnostics: RoutingDiagnostics;
|
|
15
|
+
};
|
|
16
|
+
handleProviderFailure(event: ProviderFailureEvent): void;
|
|
17
|
+
handleProviderError(event: ProviderErrorEvent): void;
|
|
18
|
+
getStatus(): {
|
|
19
|
+
routes: Record<string, {
|
|
20
|
+
providers: string[];
|
|
21
|
+
hits: number;
|
|
22
|
+
lastUsedProvider?: string;
|
|
23
|
+
}>;
|
|
24
|
+
health: import("./types.js").ProviderHealthState[];
|
|
25
|
+
};
|
|
26
|
+
private validateConfig;
|
|
27
|
+
private selectProvider;
|
|
28
|
+
private incrementRouteStat;
|
|
29
|
+
private mapProviderError;
|
|
30
|
+
private deriveReason;
|
|
31
|
+
private providerHealthConfig;
|
|
32
|
+
private buildRouteCandidates;
|
|
33
|
+
private sortByPriority;
|
|
34
|
+
private routeWeight;
|
|
35
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
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 { buildRoutingFeatures } from './features.js';
|
|
6
|
+
import { DEFAULT_ROUTE, ROUTE_PRIORITY, VirtualRouterError, VirtualRouterErrorCode } from './types.js';
|
|
7
|
+
export class VirtualRouterEngine {
|
|
8
|
+
routing = {};
|
|
9
|
+
providerRegistry = new ProviderRegistry();
|
|
10
|
+
healthManager = new ProviderHealthManager();
|
|
11
|
+
loadBalancer = new RouteLoadBalancer();
|
|
12
|
+
classifier = new RoutingClassifier({});
|
|
13
|
+
routeStats = new Map();
|
|
14
|
+
initialize(config) {
|
|
15
|
+
this.validateConfig(config);
|
|
16
|
+
this.routing = config.routing;
|
|
17
|
+
this.providerRegistry.load(config.providers);
|
|
18
|
+
this.healthManager.configure(config.health);
|
|
19
|
+
this.healthManager.registerProviders(Object.keys(config.providers));
|
|
20
|
+
this.loadBalancer = new RouteLoadBalancer(config.loadBalancing);
|
|
21
|
+
this.classifier = new RoutingClassifier(config.classifier);
|
|
22
|
+
this.routeStats = new Map();
|
|
23
|
+
for (const routeName of Object.keys(this.routing)) {
|
|
24
|
+
this.routeStats.set(routeName, { hits: 0 });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
route(request, metadata) {
|
|
28
|
+
const features = buildRoutingFeatures(request, metadata);
|
|
29
|
+
const classification = this.classifier.classify(features);
|
|
30
|
+
const routeName = classification.routeName || DEFAULT_ROUTE;
|
|
31
|
+
const selection = this.selectProvider(routeName, metadata, classification);
|
|
32
|
+
const target = this.providerRegistry.buildTarget(selection.providerKey);
|
|
33
|
+
this.healthManager.recordSuccess(selection.providerKey);
|
|
34
|
+
this.incrementRouteStat(selection.routeUsed, selection.providerKey);
|
|
35
|
+
const didFallback = selection.routeUsed !== routeName || classification.fallback;
|
|
36
|
+
return {
|
|
37
|
+
target,
|
|
38
|
+
decision: {
|
|
39
|
+
routeName: selection.routeUsed,
|
|
40
|
+
providerKey: selection.providerKey,
|
|
41
|
+
pool: selection.pool,
|
|
42
|
+
confidence: classification.confidence,
|
|
43
|
+
reasoning: classification.reasoning,
|
|
44
|
+
fallback: didFallback
|
|
45
|
+
},
|
|
46
|
+
diagnostics: {
|
|
47
|
+
routeName: selection.routeUsed,
|
|
48
|
+
providerKey: selection.providerKey,
|
|
49
|
+
pool: selection.pool,
|
|
50
|
+
reasoning: classification.reasoning,
|
|
51
|
+
fallback: didFallback,
|
|
52
|
+
confidence: classification.confidence
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
handleProviderFailure(event) {
|
|
57
|
+
if (!event || !event.providerKey) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (event.affectsHealth === false) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (event.fatal) {
|
|
64
|
+
this.healthManager.tripProvider(event.providerKey, event.reason, event.cooldownOverrideMs);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.healthManager.recordFailure(event.providerKey, event.reason);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
handleProviderError(event) {
|
|
71
|
+
const derived = this.mapProviderError(event);
|
|
72
|
+
if (!derived) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
this.handleProviderFailure(derived);
|
|
76
|
+
}
|
|
77
|
+
getStatus() {
|
|
78
|
+
const routes = {};
|
|
79
|
+
for (const [route, pool] of Object.entries(this.routing)) {
|
|
80
|
+
const stats = this.routeStats.get(route) ?? { hits: 0 };
|
|
81
|
+
routes[route] = {
|
|
82
|
+
providers: [...pool],
|
|
83
|
+
hits: stats.hits,
|
|
84
|
+
lastUsedProvider: stats.lastProvider
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
routes,
|
|
89
|
+
health: this.healthManager.getSnapshot()
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
validateConfig(config) {
|
|
93
|
+
if (!config.routing || typeof config.routing !== 'object') {
|
|
94
|
+
throw new VirtualRouterError('routing configuration is required', VirtualRouterErrorCode.CONFIG_ERROR);
|
|
95
|
+
}
|
|
96
|
+
if (!config.providers || Object.keys(config.providers).length === 0) {
|
|
97
|
+
throw new VirtualRouterError('providers configuration is required', VirtualRouterErrorCode.CONFIG_ERROR);
|
|
98
|
+
}
|
|
99
|
+
const defaultPool = config.routing[DEFAULT_ROUTE];
|
|
100
|
+
if (!Array.isArray(defaultPool) || defaultPool.length === 0) {
|
|
101
|
+
throw new VirtualRouterError('default route must be configured with at least one provider', VirtualRouterErrorCode.CONFIG_ERROR);
|
|
102
|
+
}
|
|
103
|
+
const providerKeys = new Set(Object.keys(config.providers));
|
|
104
|
+
for (const [routeName, pool] of Object.entries(config.routing)) {
|
|
105
|
+
if (!Array.isArray(pool) || !pool.length) {
|
|
106
|
+
if (routeName === DEFAULT_ROUTE) {
|
|
107
|
+
throw new VirtualRouterError('default route cannot be empty', VirtualRouterErrorCode.CONFIG_ERROR);
|
|
108
|
+
}
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
for (const providerKey of pool) {
|
|
112
|
+
if (!providerKeys.has(providerKey)) {
|
|
113
|
+
throw new VirtualRouterError(`Route ${routeName} references unknown provider ${providerKey}`, VirtualRouterErrorCode.CONFIG_ERROR);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
selectProvider(requestedRoute, metadata, classification) {
|
|
119
|
+
const candidates = this.buildRouteCandidates(requestedRoute, classification.candidates);
|
|
120
|
+
const stickyKey = metadata.requestId;
|
|
121
|
+
const attempted = [];
|
|
122
|
+
for (const routeName of candidates) {
|
|
123
|
+
const pool = this.routing[routeName];
|
|
124
|
+
if (!Array.isArray(pool) || pool.length === 0) {
|
|
125
|
+
attempted.push(routeName);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const providerKey = this.loadBalancer.select({
|
|
129
|
+
routeName,
|
|
130
|
+
candidates: pool,
|
|
131
|
+
stickyKey,
|
|
132
|
+
availabilityCheck: (key) => this.healthManager.isAvailable(key)
|
|
133
|
+
});
|
|
134
|
+
if (providerKey) {
|
|
135
|
+
return { providerKey, routeUsed: routeName, pool };
|
|
136
|
+
}
|
|
137
|
+
attempted.push(routeName);
|
|
138
|
+
}
|
|
139
|
+
throw new VirtualRouterError(`All providers unavailable for route ${requestedRoute}`, VirtualRouterErrorCode.PROVIDER_NOT_AVAILABLE, { routeName: requestedRoute, attempted });
|
|
140
|
+
}
|
|
141
|
+
incrementRouteStat(routeName, providerKey) {
|
|
142
|
+
if (!this.routeStats.has(routeName)) {
|
|
143
|
+
this.routeStats.set(routeName, { hits: 0, lastProvider: providerKey });
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const stats = this.routeStats.get(routeName);
|
|
147
|
+
stats.hits += 1;
|
|
148
|
+
stats.lastProvider = providerKey;
|
|
149
|
+
}
|
|
150
|
+
mapProviderError(event) {
|
|
151
|
+
if (!event || !event.runtime) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
const runtime = event.runtime;
|
|
155
|
+
const providerKey = runtime.providerKey ||
|
|
156
|
+
(runtime.target && typeof runtime.target === 'object' ? runtime.target.providerKey : undefined);
|
|
157
|
+
if (!providerKey) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
const routeName = runtime.routeName;
|
|
161
|
+
const statusCode = event.status;
|
|
162
|
+
const code = event.code?.toUpperCase() ?? 'ERR_UNKNOWN';
|
|
163
|
+
const stage = event.stage?.toLowerCase() ?? 'unknown';
|
|
164
|
+
const recoverable = event.recoverable === true;
|
|
165
|
+
let fatal = !recoverable;
|
|
166
|
+
let reason = this.deriveReason(code, stage, statusCode);
|
|
167
|
+
let cooldownOverrideMs;
|
|
168
|
+
if (statusCode === 429 || code.includes('429') || recoverable) {
|
|
169
|
+
fatal = false;
|
|
170
|
+
cooldownOverrideMs = Math.max(30_000, this.providerHealthConfig().cooldownMs);
|
|
171
|
+
reason = 'rate_limit';
|
|
172
|
+
}
|
|
173
|
+
else if (statusCode === 401 || statusCode === 403 || code.includes('AUTH')) {
|
|
174
|
+
fatal = true;
|
|
175
|
+
cooldownOverrideMs = Math.max(10 * 60_000, this.providerHealthConfig().fatalCooldownMs ?? 10 * 60_000);
|
|
176
|
+
reason = 'auth';
|
|
177
|
+
}
|
|
178
|
+
else if (statusCode && statusCode >= 500) {
|
|
179
|
+
fatal = true;
|
|
180
|
+
cooldownOverrideMs = Math.max(5 * 60_000, this.providerHealthConfig().fatalCooldownMs ?? 5 * 60_000);
|
|
181
|
+
reason = 'upstream_error';
|
|
182
|
+
}
|
|
183
|
+
else if (stage.includes('compat')) {
|
|
184
|
+
fatal = true;
|
|
185
|
+
cooldownOverrideMs = Math.max(10 * 60_000, this.providerHealthConfig().fatalCooldownMs ?? 10 * 60_000);
|
|
186
|
+
reason = 'compatibility';
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
providerKey,
|
|
190
|
+
routeName,
|
|
191
|
+
reason,
|
|
192
|
+
fatal,
|
|
193
|
+
statusCode,
|
|
194
|
+
errorCode: code,
|
|
195
|
+
retryable: recoverable,
|
|
196
|
+
affectsHealth: true,
|
|
197
|
+
cooldownOverrideMs,
|
|
198
|
+
metadata: {
|
|
199
|
+
...event.runtime,
|
|
200
|
+
stage,
|
|
201
|
+
eventCode: code,
|
|
202
|
+
originalMessage: event.message,
|
|
203
|
+
statusCode
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
deriveReason(code, stage, statusCode) {
|
|
208
|
+
if (code.includes('RATE') || code.includes('429'))
|
|
209
|
+
return 'rate_limit';
|
|
210
|
+
if (code.includes('AUTH') || statusCode === 401 || statusCode === 403)
|
|
211
|
+
return 'auth';
|
|
212
|
+
if (stage.includes('compat'))
|
|
213
|
+
return 'compatibility';
|
|
214
|
+
if (code.includes('SSE'))
|
|
215
|
+
return 'sse';
|
|
216
|
+
if (code.includes('TIMEOUT') || statusCode === 408 || statusCode === 504)
|
|
217
|
+
return 'timeout';
|
|
218
|
+
if (statusCode && statusCode >= 500)
|
|
219
|
+
return 'upstream_error';
|
|
220
|
+
if (statusCode && statusCode >= 400)
|
|
221
|
+
return 'client_error';
|
|
222
|
+
return 'unknown';
|
|
223
|
+
}
|
|
224
|
+
providerHealthConfig() {
|
|
225
|
+
return this.healthManager.getConfig();
|
|
226
|
+
}
|
|
227
|
+
buildRouteCandidates(requestedRoute, classificationCandidates) {
|
|
228
|
+
const normalized = requestedRoute || DEFAULT_ROUTE;
|
|
229
|
+
const baseList = classificationCandidates && classificationCandidates.length
|
|
230
|
+
? classificationCandidates
|
|
231
|
+
: [normalized];
|
|
232
|
+
const ordered = this.sortByPriority(baseList);
|
|
233
|
+
const deduped = [];
|
|
234
|
+
for (const routeName of ordered) {
|
|
235
|
+
if (routeName && !deduped.includes(routeName)) {
|
|
236
|
+
deduped.push(routeName);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (!deduped.includes(DEFAULT_ROUTE)) {
|
|
240
|
+
deduped.push(DEFAULT_ROUTE);
|
|
241
|
+
}
|
|
242
|
+
const filtered = deduped.filter((routeName) => {
|
|
243
|
+
const pool = this.routing[routeName];
|
|
244
|
+
return Array.isArray(pool) && pool.length > 0;
|
|
245
|
+
});
|
|
246
|
+
if (!filtered.includes(DEFAULT_ROUTE) &&
|
|
247
|
+
Array.isArray(this.routing[DEFAULT_ROUTE]) &&
|
|
248
|
+
this.routing[DEFAULT_ROUTE].length > 0) {
|
|
249
|
+
filtered.push(DEFAULT_ROUTE);
|
|
250
|
+
}
|
|
251
|
+
return filtered.length ? filtered : [DEFAULT_ROUTE];
|
|
252
|
+
}
|
|
253
|
+
sortByPriority(routeNames) {
|
|
254
|
+
return [...routeNames].sort((a, b) => this.routeWeight(a) - this.routeWeight(b));
|
|
255
|
+
}
|
|
256
|
+
routeWeight(routeName) {
|
|
257
|
+
const idx = ROUTE_PRIORITY.indexOf(routeName);
|
|
258
|
+
return idx >= 0 ? idx : ROUTE_PRIORITY.length;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ProviderErrorEvent } from './types.js';
|
|
2
|
+
type ProviderErrorListener = (event: ProviderErrorEvent) => void;
|
|
3
|
+
export declare class ProviderErrorCenter {
|
|
4
|
+
private readonly listeners;
|
|
5
|
+
subscribe(listener: ProviderErrorListener): () => void;
|
|
6
|
+
emit(event: ProviderErrorEvent): ProviderErrorEvent;
|
|
7
|
+
private normalize;
|
|
8
|
+
}
|
|
9
|
+
export declare const providerErrorCenter: ProviderErrorCenter;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class ProviderErrorCenter {
|
|
2
|
+
listeners = new Set();
|
|
3
|
+
subscribe(listener) {
|
|
4
|
+
this.listeners.add(listener);
|
|
5
|
+
return () => {
|
|
6
|
+
this.listeners.delete(listener);
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
emit(event) {
|
|
10
|
+
const enriched = this.normalize(event);
|
|
11
|
+
for (const listener of this.listeners) {
|
|
12
|
+
try {
|
|
13
|
+
listener(enriched);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// Listener failures should not break propagation
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return enriched;
|
|
20
|
+
}
|
|
21
|
+
normalize(event) {
|
|
22
|
+
const timestamp = typeof event.timestamp === 'number' ? event.timestamp : Date.now();
|
|
23
|
+
const code = event.code?.toString() || 'ERR_UNKNOWN';
|
|
24
|
+
const message = event.message || code;
|
|
25
|
+
const stage = event.stage || 'unknown';
|
|
26
|
+
const runtime = event.runtime || {};
|
|
27
|
+
return {
|
|
28
|
+
code,
|
|
29
|
+
message,
|
|
30
|
+
stage,
|
|
31
|
+
status: event.status,
|
|
32
|
+
recoverable: event.recoverable,
|
|
33
|
+
runtime,
|
|
34
|
+
timestamp,
|
|
35
|
+
details: event.details
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export const providerErrorCenter = new ProviderErrorCenter();
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ProcessedRequest, StandardizedRequest } from '../../conversion/hub/types/standardized.js';
|
|
2
|
+
import type { RouterMetadataInput, RoutingFeatures } from './types.js';
|
|
3
|
+
export declare function buildRoutingFeatures(request: StandardizedRequest | ProcessedRequest, metadata: RouterMetadataInput): RoutingFeatures;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
const THINKING_KEYWORDS = ['let me think', 'chain of thought', 'cot', 'reason step', 'deliberate'];
|
|
2
|
+
const WEB_TOOL_KEYWORDS = ['websearch', 'web_search', 'web-search', 'webfetch', 'web_fetch', 'web_request', 'search_web', 'internet_search'];
|
|
3
|
+
export function buildRoutingFeatures(request, metadata) {
|
|
4
|
+
const latestUserMessage = getLatestUserMessage(request.messages);
|
|
5
|
+
const assistantMessages = request.messages.filter((msg) => msg.role === 'assistant');
|
|
6
|
+
const latestUserText = latestUserMessage ? extractMessageText(latestUserMessage) : '';
|
|
7
|
+
const normalizedUserText = latestUserText.toLowerCase();
|
|
8
|
+
const hasTools = Array.isArray(request.tools) && request.tools.length > 0;
|
|
9
|
+
const hasToolCallResponses = assistantMessages.some((msg) => Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0);
|
|
10
|
+
const estimatedTokens = estimateTokens(latestUserText, latestUserText ? 1 : 0);
|
|
11
|
+
const hasThinking = detectKeyword(normalizedUserText, THINKING_KEYWORDS);
|
|
12
|
+
const hasVisionTool = detectVisionTool(request);
|
|
13
|
+
const hasImageAttachment = hasVisionTool && detectImageAttachment(latestUserMessage);
|
|
14
|
+
const hasCodingTool = detectCodingTool(request);
|
|
15
|
+
const hasWebTool = detectWebTool(request);
|
|
16
|
+
const hasThinkingKeyword = hasThinking || detectExtendedThinkingKeyword(normalizedUserText);
|
|
17
|
+
return {
|
|
18
|
+
requestId: metadata.requestId,
|
|
19
|
+
model: request.model,
|
|
20
|
+
totalMessages: latestUserText ? 1 : 0,
|
|
21
|
+
userTextSample: latestUserText.slice(0, 2000),
|
|
22
|
+
toolCount: request.tools?.length ?? 0,
|
|
23
|
+
hasTools,
|
|
24
|
+
hasToolCallResponses,
|
|
25
|
+
hasVisionTool,
|
|
26
|
+
hasImageAttachment,
|
|
27
|
+
hasWebTool,
|
|
28
|
+
hasCodingTool,
|
|
29
|
+
hasThinkingKeyword,
|
|
30
|
+
estimatedTokens,
|
|
31
|
+
metadata: {
|
|
32
|
+
...metadata
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function getLatestUserMessage(messages) {
|
|
37
|
+
for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
|
|
38
|
+
if (messages[idx]?.role === 'user') {
|
|
39
|
+
return messages[idx];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
function extractMessageText(message) {
|
|
45
|
+
if (typeof message.content === 'string' && message.content.trim()) {
|
|
46
|
+
return message.content;
|
|
47
|
+
}
|
|
48
|
+
return '';
|
|
49
|
+
}
|
|
50
|
+
function detectKeyword(text, keywords) {
|
|
51
|
+
if (!text)
|
|
52
|
+
return false;
|
|
53
|
+
return keywords.some((keyword) => text.includes(keyword.toLowerCase()));
|
|
54
|
+
}
|
|
55
|
+
function detectImageAttachment(message) {
|
|
56
|
+
if (!message)
|
|
57
|
+
return false;
|
|
58
|
+
if (!message.metadata || typeof message.metadata !== 'object') {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const meta = message.metadata;
|
|
62
|
+
const attachments = (meta.attachments ?? null);
|
|
63
|
+
if (Array.isArray(attachments)) {
|
|
64
|
+
return attachments.some((attachment) => {
|
|
65
|
+
const candidate = attachment;
|
|
66
|
+
const typeValue = typeof candidate.type === 'string' ? candidate.type.toLowerCase() : '';
|
|
67
|
+
const urlValue = typeof candidate.url === 'string'
|
|
68
|
+
? candidate.url
|
|
69
|
+
: typeof candidate.src === 'string'
|
|
70
|
+
? candidate.src
|
|
71
|
+
: typeof candidate.image_url === 'string'
|
|
72
|
+
? candidate.image_url
|
|
73
|
+
: typeof candidate.image_url?.url === 'string'
|
|
74
|
+
? candidate.image_url.url
|
|
75
|
+
: '';
|
|
76
|
+
return typeValue.includes('image') && urlValue.trim().length > 0;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (typeof meta.attachmentType === 'string' && meta.attachmentType.toLowerCase().includes('image')) {
|
|
80
|
+
const urlCandidate = typeof meta.attachmentUrl === 'string' ? meta.attachmentUrl : '';
|
|
81
|
+
return urlCandidate.trim().length > 0;
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
function detectVisionTool(request) {
|
|
86
|
+
if (!Array.isArray(request.tools)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
return request.tools.some((tool) => {
|
|
90
|
+
const functionName = extractToolName(tool);
|
|
91
|
+
const description = extractToolDescription(tool);
|
|
92
|
+
return /vision|image|picture|photo/i.test(functionName) || /vision|image|picture|photo/i.test(description || '');
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function detectCodingTool(request) {
|
|
96
|
+
if (!Array.isArray(request.tools)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
return request.tools.some((tool) => {
|
|
100
|
+
const functionName = extractToolName(tool);
|
|
101
|
+
const description = extractToolDescription(tool);
|
|
102
|
+
const chineseDesc = description;
|
|
103
|
+
return (/write_file|apply_patch|modify_file|edit_file|create_file|shell|terminal|bash|run_shell/i.test(functionName) ||
|
|
104
|
+
/write file|apply patch|modify file|edit file|create file|shell|terminal|bash|run shell/i.test(description || '') ||
|
|
105
|
+
/创建文件|修改文件|写入文件|执行shell|执行终端/.test(chineseDesc || ''));
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function detectWebTool(request) {
|
|
109
|
+
if (!Array.isArray(request.tools)) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
return request.tools.some((tool) => {
|
|
113
|
+
const functionName = extractToolName(tool);
|
|
114
|
+
const description = extractToolDescription(tool);
|
|
115
|
+
const normalizedName = functionName.toLowerCase();
|
|
116
|
+
const normalizedDesc = (description || '').toLowerCase();
|
|
117
|
+
return (WEB_TOOL_KEYWORDS.some((keyword) => normalizedName.includes(keyword)) ||
|
|
118
|
+
WEB_TOOL_KEYWORDS.some((keyword) => normalizedDesc.includes(keyword)));
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function detectExtendedThinkingKeyword(text) {
|
|
122
|
+
if (!text) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
const keywords = ['仔细分析', '思考', '超级思考', '深度思考', 'careful analysis', 'deep thinking', 'deliberate'];
|
|
126
|
+
return keywords.some((keyword) => text.includes(keyword));
|
|
127
|
+
}
|
|
128
|
+
function estimateTokens(text, messageCount) {
|
|
129
|
+
if (!text) {
|
|
130
|
+
return Math.max(32, messageCount * 16);
|
|
131
|
+
}
|
|
132
|
+
const rough = Math.ceil(text.length / 4);
|
|
133
|
+
return Math.max(rough, messageCount * 32);
|
|
134
|
+
}
|
|
135
|
+
function extractToolName(tool) {
|
|
136
|
+
if (!tool || typeof tool !== 'object') {
|
|
137
|
+
return '';
|
|
138
|
+
}
|
|
139
|
+
const candidate = tool;
|
|
140
|
+
const fromFunction = candidate.function;
|
|
141
|
+
if (fromFunction && typeof fromFunction.name === 'string' && fromFunction.name.trim()) {
|
|
142
|
+
return fromFunction.name;
|
|
143
|
+
}
|
|
144
|
+
if (typeof candidate.name === 'string' && candidate.name.trim()) {
|
|
145
|
+
return candidate.name;
|
|
146
|
+
}
|
|
147
|
+
return '';
|
|
148
|
+
}
|
|
149
|
+
function extractToolDescription(tool) {
|
|
150
|
+
if (!tool || typeof tool !== 'object') {
|
|
151
|
+
return '';
|
|
152
|
+
}
|
|
153
|
+
const candidate = tool;
|
|
154
|
+
const fromFunction = candidate.function;
|
|
155
|
+
if (fromFunction && typeof fromFunction.description === 'string' && fromFunction.description.trim()) {
|
|
156
|
+
return fromFunction.description;
|
|
157
|
+
}
|
|
158
|
+
if (typeof candidate.description === 'string' && candidate.description.trim()) {
|
|
159
|
+
return candidate.description;
|
|
160
|
+
}
|
|
161
|
+
return '';
|
|
162
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ProviderHealthConfig, ProviderHealthState } from './types.js';
|
|
2
|
+
interface ProviderInternalState extends ProviderHealthState {
|
|
3
|
+
lastFailureAt?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class ProviderHealthManager {
|
|
6
|
+
private readonly states;
|
|
7
|
+
private config;
|
|
8
|
+
configure(config?: ProviderHealthConfig): void;
|
|
9
|
+
registerProviders(providerKeys: string[]): void;
|
|
10
|
+
recordFailure(providerKey: string, reason?: string): ProviderInternalState;
|
|
11
|
+
recordSuccess(providerKey: string): ProviderInternalState;
|
|
12
|
+
tripProvider(providerKey: string, reason?: string, cooldownOverrideMs?: number): ProviderInternalState;
|
|
13
|
+
isAvailable(providerKey: string): boolean;
|
|
14
|
+
getSnapshot(): ProviderHealthState[];
|
|
15
|
+
getConfig(): Required<ProviderHealthConfig>;
|
|
16
|
+
private getState;
|
|
17
|
+
}
|
|
18
|
+
export {};
|