@jsonstudio/rcc 0.89.168 → 0.89.524
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 +18 -15
- package/dist/build-info.js +3 -3
- package/dist/build-info.js.map +1 -1
- package/dist/cli.js +94 -0
- package/dist/cli.js.map +1 -1
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js +28 -5
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -1
- package/dist/commands/token-daemon.d.ts +2 -0
- package/dist/commands/token-daemon.js +183 -0
- package/dist/commands/token-daemon.js.map +1 -0
- package/dist/error-handling/quiet-error-handling-center.d.ts +9 -0
- package/dist/error-handling/quiet-error-handling-center.js +141 -0
- package/dist/error-handling/quiet-error-handling-center.js.map +1 -0
- package/dist/error-handling/route-error-hub.js +8 -2
- package/dist/error-handling/route-error-hub.js.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/modules/llmswitch/bridge.d.ts +1 -1
- package/dist/modules/llmswitch/bridge.js +3 -2
- package/dist/modules/llmswitch/bridge.js.map +1 -1
- package/dist/modules/pipeline/utils/colored-logger.d.ts +2 -0
- package/dist/modules/pipeline/utils/colored-logger.js +22 -3
- package/dist/modules/pipeline/utils/colored-logger.js.map +1 -1
- package/dist/providers/auth/antigravity-userinfo-helper.d.ts +10 -0
- package/dist/providers/auth/antigravity-userinfo-helper.js +140 -0
- package/dist/providers/auth/antigravity-userinfo-helper.js.map +1 -0
- package/dist/providers/auth/gemini-cli-userinfo-helper.js +12 -2
- package/dist/providers/auth/gemini-cli-userinfo-helper.js.map +1 -1
- package/dist/providers/auth/oauth-lifecycle.js +395 -24
- package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
- package/dist/providers/auth/token-scanner/index.d.ts +32 -0
- package/dist/providers/auth/token-scanner/index.js +86 -0
- package/dist/providers/auth/token-scanner/index.js.map +1 -0
- package/dist/providers/auth/tokenfile-auth.d.ts +17 -0
- package/dist/providers/auth/tokenfile-auth.js +27 -5
- package/dist/providers/auth/tokenfile-auth.js.map +1 -1
- package/dist/providers/core/api/provider-types.d.ts +10 -0
- package/dist/providers/core/config/oauth-flows.d.ts +25 -0
- package/dist/providers/core/config/oauth-flows.js +92 -5
- package/dist/providers/core/config/oauth-flows.js.map +1 -1
- package/dist/providers/core/config/provider-oauth-configs.js +93 -2
- package/dist/providers/core/config/provider-oauth-configs.js.map +1 -1
- package/dist/providers/core/config/service-profiles.js +18 -10
- package/dist/providers/core/config/service-profiles.js.map +1 -1
- package/dist/providers/core/runtime/base-provider.d.ts +2 -0
- package/dist/providers/core/runtime/base-provider.js +135 -15
- package/dist/providers/core/runtime/base-provider.js.map +1 -1
- package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +8 -3
- package/dist/providers/core/runtime/gemini-cli-http-provider.js +332 -67
- package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
- package/dist/providers/core/runtime/http-request-executor.d.ts +1 -0
- package/dist/providers/core/runtime/http-request-executor.js +41 -1
- package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
- package/dist/providers/core/runtime/http-transport-provider.d.ts +27 -0
- package/dist/providers/core/runtime/http-transport-provider.js +342 -69
- package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
- package/dist/providers/core/runtime/provider-error-classifier.d.ts +2 -2
- package/dist/providers/core/runtime/provider-error-classifier.js +14 -4
- package/dist/providers/core/runtime/provider-error-classifier.js.map +1 -1
- package/dist/providers/core/runtime/provider-factory.d.ts +1 -0
- package/dist/providers/core/runtime/provider-factory.js +37 -8
- package/dist/providers/core/runtime/provider-factory.js.map +1 -1
- package/dist/providers/core/runtime/responses-provider.d.ts +3 -3
- package/dist/providers/core/runtime/responses-provider.js +56 -117
- package/dist/providers/core/runtime/responses-provider.js.map +1 -1
- package/dist/providers/core/runtime/vision-debug-utils.d.ts +13 -0
- package/dist/providers/core/runtime/vision-debug-utils.js +114 -0
- package/dist/providers/core/runtime/vision-debug-utils.js.map +1 -0
- package/dist/providers/core/strategies/oauth-auth-code-flow.js +82 -25
- package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
- package/dist/providers/core/utils/http-client.d.ts +5 -0
- package/dist/providers/core/utils/http-client.js +31 -4
- package/dist/providers/core/utils/http-client.js.map +1 -1
- package/dist/providers/core/utils/provider-error-reporter.js +8 -2
- package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
- package/dist/providers/core/utils/snapshot-writer.d.ts +1 -1
- package/dist/providers/core/utils/snapshot-writer.js +5 -1
- package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
- package/dist/providers/profile/provider-profile-loader.js +8 -4
- package/dist/providers/profile/provider-profile-loader.js.map +1 -1
- package/dist/runtime/runtime-flags.d.ts +4 -0
- package/dist/runtime/runtime-flags.js +32 -0
- package/dist/runtime/runtime-flags.js.map +1 -0
- package/dist/server/handlers/handler-utils.js +29 -2
- package/dist/server/handlers/handler-utils.js.map +1 -1
- package/dist/server/handlers/messages-handler.js +27 -26
- package/dist/server/handlers/messages-handler.js.map +1 -1
- package/dist/server/handlers/responses-handler.js +35 -1
- package/dist/server/handlers/responses-handler.js.map +1 -1
- package/dist/server/handlers/sse-dispatcher.js +22 -2
- package/dist/server/handlers/sse-dispatcher.js.map +1 -1
- package/dist/server/runtime/http-server/index.d.ts +10 -0
- package/dist/server/runtime/http-server/index.js +551 -148
- package/dist/server/runtime/http-server/index.js.map +1 -1
- package/dist/server/runtime/http-server/request-executor.d.ts +14 -0
- package/dist/server/runtime/http-server/request-executor.js +638 -149
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/server/runtime/http-server/routes.d.ts +5 -0
- package/dist/server/runtime/http-server/routes.js +69 -0
- package/dist/server/runtime/http-server/routes.js.map +1 -1
- package/dist/server/runtime/http-server/runtime-manager.js +18 -0
- package/dist/server/runtime/http-server/runtime-manager.js.map +1 -1
- package/dist/server/utils/sse-request-parser.d.ts +1 -0
- package/dist/server/utils/sse-request-parser.js +17 -6
- package/dist/server/utils/sse-request-parser.js.map +1 -1
- package/dist/server/utils/utf8-chunk-buffer.d.ts +43 -0
- package/dist/server/utils/utf8-chunk-buffer.js +132 -0
- package/dist/server/utils/utf8-chunk-buffer.js.map +1 -0
- package/dist/server/utils/warmup-detector.d.ts +7 -0
- package/dist/server/utils/warmup-detector.js +125 -0
- package/dist/server/utils/warmup-detector.js.map +1 -0
- package/dist/server/utils/warmup-storm-tracker.d.ts +9 -0
- package/dist/server/utils/warmup-storm-tracker.js +61 -0
- package/dist/server/utils/warmup-storm-tracker.js.map +1 -0
- package/dist/token-daemon/index.d.ts +7 -0
- package/dist/token-daemon/index.js +242 -0
- package/dist/token-daemon/index.js.map +1 -0
- package/dist/token-daemon/server-utils.d.ts +33 -0
- package/dist/token-daemon/server-utils.js +155 -0
- package/dist/token-daemon/server-utils.js.map +1 -0
- package/dist/token-daemon/token-daemon.d.ts +20 -0
- package/dist/token-daemon/token-daemon.js +144 -0
- package/dist/token-daemon/token-daemon.js.map +1 -0
- package/dist/token-daemon/token-types.d.ts +44 -0
- package/dist/token-daemon/token-types.js +18 -0
- package/dist/token-daemon/token-types.js.map +1 -0
- package/dist/token-daemon/token-utils.d.ts +17 -0
- package/dist/token-daemon/token-utils.js +153 -0
- package/dist/token-daemon/token-utils.js.map +1 -0
- package/dist/tools/semantic-replay.js +7 -6
- package/dist/tools/semantic-replay.js.map +1 -1
- package/dist/utils/debug-utils.js +14 -0
- package/dist/utils/debug-utils.js.map +1 -1
- package/dist/utils/error-handler-registry.d.ts +36 -0
- package/dist/utils/error-handler-registry.js +99 -12
- package/dist/utils/error-handler-registry.js.map +1 -1
- package/dist/utils/error-handling-utils.js +4 -3
- package/dist/utils/error-handling-utils.js.map +1 -1
- package/dist/utils/log-helpers.d.ts +6 -0
- package/dist/utils/log-helpers.js +90 -0
- package/dist/utils/log-helpers.js.map +1 -0
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.js +55 -2
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/snapshot-writer.js +2 -6
- package/dist/utils/snapshot-writer.js.map +1 -1
- package/node_modules/@jsonstudio/llms/README.md +2 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/codecs/gemini-openai-codec.js +152 -6
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/auto-thinking.d.ts +6 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/auto-thinking.js +25 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/field-mapping.d.ts +14 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/field-mapping.js +155 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/gemini-web-search.d.ts +17 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/gemini-web-search.js +68 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-image-content.d.ts +2 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-image-content.js +83 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-tool-extraction.d.ts +2 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-tool-extraction.js +264 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-vision-prompt.d.ts +11 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-vision-prompt.js +177 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-web-search.d.ts +2 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-web-search.js +63 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/qwen-transform.d.ts +3 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/qwen-transform.js +209 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/request-rules.d.ts +24 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/request-rules.js +63 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-blacklist.d.ts +14 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-blacklist.js +85 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-normalize.d.ts +5 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-normalize.js +121 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-validate.d.ts +5 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-validate.js +76 -0
- package/{dist/providers/compat/utils/snapshot-writer.d.ts → node_modules/@jsonstudio/llms/dist/conversion/compat/actions/snapshot.d.ts} +2 -2
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/snapshot.js +21 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/tool-schema.d.ts +6 -0
- package/{dist/providers/compat/glm/utils/tool-schema-helpers.js → node_modules/@jsonstudio/llms/dist/conversion/compat/actions/tool-schema.js} +6 -1
- package/{dist/providers/compat/filters → node_modules/@jsonstudio/llms/dist/conversion/compat/actions}/universal-shape-filter.d.ts +17 -22
- package/{dist/providers/compat/filters → node_modules/@jsonstudio/llms/dist/conversion/compat/actions}/universal-shape-filter.js +46 -99
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-gemini.json +17 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-glm.json +196 -13
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-iflow.json +194 -26
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-lmstudio.json +43 -35
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-qwen.json +20 -16
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/responses-c4m.json +42 -42
- package/node_modules/@jsonstudio/llms/dist/conversion/config/sample-config.json +1 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.d.ts +7 -2
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.js +5 -665
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.d.ts +9 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +869 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-types.d.ts +55 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.d.ts +2 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.js +74 -5
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +2 -2
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/target-utils.js +9 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/process/chat-process.js +213 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/provider-response.d.ts +34 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/provider-response.js +84 -24
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/response-runtime.js +19 -2
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/server-side-tools.d.ts +26 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/server-side-tools.js +383 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/semantic-mappers/gemini-mapper.js +241 -14
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/semantic-mappers/responses-mapper.js +17 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/standardized-bridge.js +14 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/types/standardized.d.ts +1 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-host-policy.d.ts +6 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-host-policy.js +14 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.js +133 -5
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/anthropic-message-utils.js +98 -3
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/bridge-message-utils.js +137 -10
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-output-builder.js +43 -2
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-reasoning-registry.d.ts +4 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-reasoning-registry.js +62 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-response-utils.js +23 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/snapshot-utils.js +17 -47
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-canonicalizer.d.ts +2 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-filter-pipeline.js +12 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-mapping.js +25 -2
- package/node_modules/@jsonstudio/llms/dist/index.d.ts +1 -0
- package/node_modules/@jsonstudio/llms/dist/index.js +1 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/bootstrap.js +540 -36
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/classifier.js +12 -11
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/context-advisor.d.ts +19 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/context-advisor.js +64 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.d.ts +26 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.js +450 -54
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/features.js +23 -458
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/health-manager.js +2 -7
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/message-utils.d.ts +7 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/message-utils.js +78 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/provider-registry.js +7 -2
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-counter.js +14 -3
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-estimator.d.ts +2 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-estimator.js +16 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-file-scanner.d.ts +15 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-file-scanner.js +56 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/tool-signals.d.ts +13 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/tool-signals.js +403 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.d.ts +86 -2
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.js +3 -1
- package/node_modules/@jsonstudio/llms/dist/servertool/engine.d.ts +27 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/engine.js +60 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/flow-types.d.ts +40 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/flow-types.js +1 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/handlers/vision.d.ts +1 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/handlers/vision.js +194 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/handlers/web-search.d.ts +1 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/handlers/web-search.js +638 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/orchestration-types.d.ts +33 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/orchestration-types.js +1 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/registry.d.ts +18 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/registry.js +27 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/server-side-tools.d.ts +8 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/server-side-tools.js +208 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/types.d.ts +88 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/types.js +1 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/vision-tool.d.ts +2 -0
- package/node_modules/@jsonstudio/llms/dist/servertool/vision-tool.js +185 -0
- package/node_modules/@jsonstudio/llms/dist/sse/json-to-sse/event-generators/responses.js +15 -3
- package/node_modules/@jsonstudio/llms/dist/sse/sse-to-json/builders/response-builder.js +6 -3
- package/node_modules/@jsonstudio/llms/dist/sse/sse-to-json/gemini-sse-to-json-converter.js +27 -1
- package/node_modules/@jsonstudio/llms/dist/sse/types/gemini-types.d.ts +20 -1
- package/node_modules/@jsonstudio/llms/dist/sse/types/responses-types.js +1 -1
- package/node_modules/@jsonstudio/llms/dist/telemetry/stats-center.d.ts +73 -0
- package/node_modules/@jsonstudio/llms/dist/telemetry/stats-center.js +280 -0
- package/node_modules/@jsonstudio/llms/package.json +2 -2
- package/package.json +11 -10
- package/scripts/README.md +26 -12
- package/scripts/auth-antigravity-token.mjs +64 -0
- package/scripts/auth-gemini-cli-token.mjs +96 -0
- package/scripts/auth-iflow-manual.mjs +81 -0
- package/scripts/auth-iflow-token-direct.mjs +87 -0
- package/scripts/auth-iflow-token.mjs +77 -0
- package/scripts/copy-compat-assets.mjs +3 -15
- package/scripts/install-verify.mjs +1 -0
- package/scripts/pack-mode.mjs +2 -1
- package/scripts/publish-rcc.mjs +20 -4
- package/scripts/replay-codex-sample.mjs +13 -8
- package/scripts/tests/chat-pipeline-blackbox.mjs +1 -1
- package/scripts/tests/virtual-router-health.mjs +141 -6
- package/scripts/tools/capture-provider-goldens.mjs +8 -7
- package/scripts/verify-client-headers.mjs +224 -0
- package/dist/providers/compat/base-compatibility.d.ts +0 -27
- package/dist/providers/compat/base-compatibility.js +0 -143
- package/dist/providers/compat/base-compatibility.js.map +0 -1
- package/dist/providers/compat/compat-directory-loader.d.ts +0 -4
- package/dist/providers/compat/compat-directory-loader.js +0 -85
- package/dist/providers/compat/compat-directory-loader.js.map +0 -1
- package/dist/providers/compat/compatibility-adapter.d.ts +0 -18
- package/dist/providers/compat/compatibility-adapter.js +0 -104
- package/dist/providers/compat/compatibility-adapter.js.map +0 -1
- package/dist/providers/compat/compatibility-factory.d.ts +0 -57
- package/dist/providers/compat/compatibility-factory.js +0 -155
- package/dist/providers/compat/compatibility-factory.js.map +0 -1
- package/dist/providers/compat/compatibility-interface.d.ts +0 -35
- package/dist/providers/compat/compatibility-interface.js +0 -2
- package/dist/providers/compat/compatibility-interface.js.map +0 -1
- package/dist/providers/compat/compatibility-manager.d.ts +0 -85
- package/dist/providers/compat/compatibility-manager.js +0 -368
- package/dist/providers/compat/compatibility-manager.js.map +0 -1
- package/dist/providers/compat/config/config-compatibility.d.ts +0 -28
- package/dist/providers/compat/config/config-compatibility.js +0 -95
- package/dist/providers/compat/config/config-compatibility.js.map +0 -1
- package/dist/providers/compat/field-mapping.d.ts +0 -102
- package/dist/providers/compat/field-mapping.js +0 -447
- package/dist/providers/compat/field-mapping.js.map +0 -1
- package/dist/providers/compat/filters/blacklist-sanitizer.d.ts +0 -45
- package/dist/providers/compat/filters/blacklist-sanitizer.js +0 -133
- package/dist/providers/compat/filters/blacklist-sanitizer.js.map +0 -1
- package/dist/providers/compat/filters/response-blacklist-sanitizer.d.ts +0 -28
- package/dist/providers/compat/filters/response-blacklist-sanitizer.js +0 -138
- package/dist/providers/compat/filters/response-blacklist-sanitizer.js.map +0 -1
- package/dist/providers/compat/filters/universal-shape-filter.js.map +0 -1
- package/dist/providers/compat/glm/config/blacklist-rules.json +0 -22
- package/dist/providers/compat/glm/config/field-mappings.json +0 -92
- package/dist/providers/compat/glm/config/response-blacklist.json +0 -7
- package/dist/providers/compat/glm/config/shape-filters.json +0 -37
- package/dist/providers/compat/glm/field-mapping/field-mapping-processor.d.ts +0 -28
- package/dist/providers/compat/glm/field-mapping/field-mapping-processor.js +0 -306
- package/dist/providers/compat/glm/field-mapping/field-mapping-processor.js.map +0 -1
- package/dist/providers/compat/glm/functions/glm-processor.d.ts +0 -50
- package/dist/providers/compat/glm/functions/glm-processor.js +0 -134
- package/dist/providers/compat/glm/functions/glm-processor.js.map +0 -1
- package/dist/providers/compat/glm/glm-compatibility.d.ts +0 -34
- package/dist/providers/compat/glm/glm-compatibility.js +0 -117
- package/dist/providers/compat/glm/glm-compatibility.js.map +0 -1
- package/dist/providers/compat/glm/hooks/base-hook.d.ts +0 -21
- package/dist/providers/compat/glm/hooks/base-hook.js +0 -53
- package/dist/providers/compat/glm/hooks/base-hook.js.map +0 -1
- package/dist/providers/compat/glm/hooks/glm-request-validation-hook.d.ts +0 -24
- package/dist/providers/compat/glm/hooks/glm-request-validation-hook.js +0 -268
- package/dist/providers/compat/glm/hooks/glm-request-validation-hook.js.map +0 -1
- package/dist/providers/compat/glm/hooks/glm-response-normalization-hook.d.ts +0 -21
- package/dist/providers/compat/glm/hooks/glm-response-normalization-hook.js +0 -171
- package/dist/providers/compat/glm/hooks/glm-response-normalization-hook.js.map +0 -1
- package/dist/providers/compat/glm/hooks/glm-response-validation-hook.d.ts +0 -25
- package/dist/providers/compat/glm/hooks/glm-response-validation-hook.js +0 -236
- package/dist/providers/compat/glm/hooks/glm-response-validation-hook.js.map +0 -1
- package/dist/providers/compat/glm/hooks/glm-tool-cleaning-hook.d.ts +0 -26
- package/dist/providers/compat/glm/hooks/glm-tool-cleaning-hook.js +0 -186
- package/dist/providers/compat/glm/hooks/glm-tool-cleaning-hook.js.map +0 -1
- package/dist/providers/compat/glm/index.d.ts +0 -24
- package/dist/providers/compat/glm/index.js +0 -29
- package/dist/providers/compat/glm/index.js.map +0 -1
- package/dist/providers/compat/glm/utils/tool-schema-helpers.d.ts +0 -3
- package/dist/providers/compat/glm/utils/tool-schema-helpers.js.map +0 -1
- package/dist/providers/compat/iflow/config/field-mappings.json +0 -92
- package/dist/providers/compat/iflow/config/shape-filters.json +0 -37
- package/dist/providers/compat/iflow/field-mapping/iflow-field-mapping-processor.d.ts +0 -34
- package/dist/providers/compat/iflow/field-mapping/iflow-field-mapping-processor.js +0 -386
- package/dist/providers/compat/iflow/field-mapping/iflow-field-mapping-processor.js.map +0 -1
- package/dist/providers/compat/iflow/functions/iflow-processor.d.ts +0 -53
- package/dist/providers/compat/iflow/functions/iflow-processor.js +0 -215
- package/dist/providers/compat/iflow/functions/iflow-processor.js.map +0 -1
- package/dist/providers/compat/iflow/hooks/base-hook.d.ts +0 -23
- package/dist/providers/compat/iflow/hooks/base-hook.js +0 -59
- package/dist/providers/compat/iflow/hooks/base-hook.js.map +0 -1
- package/dist/providers/compat/iflow/hooks/iflow-request-validation-hook.d.ts +0 -23
- package/dist/providers/compat/iflow/hooks/iflow-request-validation-hook.js +0 -279
- package/dist/providers/compat/iflow/hooks/iflow-request-validation-hook.js.map +0 -1
- package/dist/providers/compat/iflow/hooks/iflow-response-normalization-hook.d.ts +0 -20
- package/dist/providers/compat/iflow/hooks/iflow-response-normalization-hook.js +0 -180
- package/dist/providers/compat/iflow/hooks/iflow-response-normalization-hook.js.map +0 -1
- package/dist/providers/compat/iflow/hooks/iflow-response-validation-hook.d.ts +0 -23
- package/dist/providers/compat/iflow/hooks/iflow-response-validation-hook.js +0 -232
- package/dist/providers/compat/iflow/hooks/iflow-response-validation-hook.js.map +0 -1
- package/dist/providers/compat/iflow/hooks/iflow-tool-cleaning-hook.d.ts +0 -25
- package/dist/providers/compat/iflow/hooks/iflow-tool-cleaning-hook.js +0 -216
- package/dist/providers/compat/iflow/hooks/iflow-tool-cleaning-hook.js.map +0 -1
- package/dist/providers/compat/iflow/iflow-compatibility.d.ts +0 -24
- package/dist/providers/compat/iflow/iflow-compatibility.js +0 -94
- package/dist/providers/compat/iflow/iflow-compatibility.js.map +0 -1
- package/dist/providers/compat/index.d.ts +0 -59
- package/dist/providers/compat/index.js +0 -83
- package/dist/providers/compat/index.js.map +0 -1
- package/dist/providers/compat/lmstudio-compatibility.d.ts +0 -44
- package/dist/providers/compat/lmstudio-compatibility.js +0 -193
- package/dist/providers/compat/lmstudio-compatibility.js.map +0 -1
- package/dist/providers/compat/passthrough-compatibility.d.ts +0 -29
- package/dist/providers/compat/passthrough-compatibility.js +0 -83
- package/dist/providers/compat/passthrough-compatibility.js.map +0 -1
- package/dist/providers/compat/profiles/chat/glm/index.d.ts +0 -6
- package/dist/providers/compat/profiles/chat/glm/index.js +0 -6
- package/dist/providers/compat/profiles/chat/glm/index.js.map +0 -1
- package/dist/providers/compat/profiles/chat/iflow/index.d.ts +0 -6
- package/dist/providers/compat/profiles/chat/iflow/index.js +0 -6
- package/dist/providers/compat/profiles/chat/iflow/index.js.map +0 -1
- package/dist/providers/compat/profiles/chat/lmstudio/index.d.ts +0 -6
- package/dist/providers/compat/profiles/chat/lmstudio/index.js +0 -6
- package/dist/providers/compat/profiles/chat/lmstudio/index.js.map +0 -1
- package/dist/providers/compat/profiles/chat/qwen/index.d.ts +0 -6
- package/dist/providers/compat/profiles/chat/qwen/index.js +0 -6
- package/dist/providers/compat/profiles/chat/qwen/index.js.map +0 -1
- package/dist/providers/compat/profiles/compat/passthrough/index.d.ts +0 -6
- package/dist/providers/compat/profiles/compat/passthrough/index.js +0 -6
- package/dist/providers/compat/profiles/compat/passthrough/index.js.map +0 -1
- package/dist/providers/compat/profiles/responses/c4m/index.d.ts +0 -6
- package/dist/providers/compat/profiles/responses/c4m/index.js +0 -6
- package/dist/providers/compat/profiles/responses/c4m/index.js.map +0 -1
- package/dist/providers/compat/profiles/responses/default/index.d.ts +0 -6
- package/dist/providers/compat/profiles/responses/default/index.js +0 -6
- package/dist/providers/compat/profiles/responses/default/index.js.map +0 -1
- package/dist/providers/compat/profiles/responses/fai/index.d.ts +0 -6
- package/dist/providers/compat/profiles/responses/fai/index.js +0 -6
- package/dist/providers/compat/profiles/responses/fai/index.js.map +0 -1
- package/dist/providers/compat/profiles/responses/fc/index.d.ts +0 -6
- package/dist/providers/compat/profiles/responses/fc/index.js +0 -6
- package/dist/providers/compat/profiles/responses/fc/index.js.map +0 -1
- package/dist/providers/compat/qwen/index.d.ts +0 -4
- package/dist/providers/compat/qwen/index.js +0 -6
- package/dist/providers/compat/qwen/index.js.map +0 -1
- package/dist/providers/compat/qwen-compatibility.d.ts +0 -52
- package/dist/providers/compat/qwen-compatibility.js +0 -330
- package/dist/providers/compat/qwen-compatibility.js.map +0 -1
- package/dist/providers/compat/register-compat-module.d.ts +0 -8
- package/dist/providers/compat/register-compat-module.js +0 -53
- package/dist/providers/compat/register-compat-module.js.map +0 -1
- package/dist/providers/compat/responses/c4m-responses-compatibility.d.ts +0 -27
- package/dist/providers/compat/responses/c4m-responses-compatibility.js +0 -197
- package/dist/providers/compat/responses/c4m-responses-compatibility.js.map +0 -1
- package/dist/providers/compat/standard-compatibility-utils.d.ts +0 -1
- package/dist/providers/compat/standard-compatibility-utils.js +0 -77
- package/dist/providers/compat/standard-compatibility-utils.js.map +0 -1
- package/dist/providers/compat/standard-compatibility.d.ts +0 -31
- package/dist/providers/compat/standard-compatibility.js +0 -118
- package/dist/providers/compat/standard-compatibility.js.map +0 -1
- package/dist/providers/compat/utils/snapshot-writer.js +0 -62
- package/dist/providers/compat/utils/snapshot-writer.js.map +0 -1
- package/dist/tools/replay-request.d.ts +0 -0
- package/dist/tools/replay-request.js +0 -2
- package/dist/tools/replay-request.js.map +0 -1
- package/scripts/check-glm-compat.mjs +0 -47
|
@@ -18,7 +18,7 @@ import { buildProviderProfiles } from '../../../providers/profile/provider-profi
|
|
|
18
18
|
import { emitProviderError } from '../../../providers/core/utils/provider-error-reporter.js';
|
|
19
19
|
import { isStageLoggingEnabled, logPipelineStage } from '../../utils/stage-logger.js';
|
|
20
20
|
import { registerDefaultMiddleware } from './middleware.js';
|
|
21
|
-
import { registerHttpRoutes } from './routes.js';
|
|
21
|
+
import { registerHttpRoutes, registerOAuthPortalRoute } from './routes.js';
|
|
22
22
|
import { mapProviderProtocol, normalizeProviderType, resolveProviderIdentity, asRecord } from './provider-utils.js';
|
|
23
23
|
import { resolveRepoRoot, loadLlmswitchModule } from './llmswitch-loader.js';
|
|
24
24
|
import { importCoreModule } from '../../../modules/llmswitch/core-loader.js';
|
|
@@ -27,6 +27,8 @@ import { rebindResponsesConversationRequestId } from '../../../modules/llmswitch
|
|
|
27
27
|
import { initializeRouteErrorHub, reportRouteError } from '../../../error-handling/route-error-hub.js';
|
|
28
28
|
import { writeClientSnapshot } from '../../../providers/core/utils/snapshot-writer.js';
|
|
29
29
|
import { createServerColoredLogger } from './colored-logger.js';
|
|
30
|
+
import { formatValueForConsole } from '../../../utils/logger.js';
|
|
31
|
+
import { QuietErrorHandlingCenter } from '../../../error-handling/quiet-error-handling-center.js';
|
|
30
32
|
let convertProviderResponseFn = null;
|
|
31
33
|
async function loadConvertProviderResponse() {
|
|
32
34
|
if (convertProviderResponseFn) {
|
|
@@ -82,7 +84,7 @@ export class RouteCodexHttpServer {
|
|
|
82
84
|
constructor(config) {
|
|
83
85
|
this.config = config;
|
|
84
86
|
this.app = express();
|
|
85
|
-
this.errorHandling = new
|
|
87
|
+
this.errorHandling = new QuietErrorHandlingCenter();
|
|
86
88
|
this.stageLoggingEnabled = isStageLoggingEnabled();
|
|
87
89
|
this.repoRoot = resolveRepoRoot(import.meta.url);
|
|
88
90
|
const envFlag = (process.env.ROUTECODEX_USE_HUB_PIPELINE || '').trim().toLowerCase();
|
|
@@ -96,6 +98,11 @@ export class RouteCodexHttpServer {
|
|
|
96
98
|
console.warn('[RouteCodexHttpServer] Failed to initialize PipelineDebugLogger; falling back to noop logger.', error);
|
|
97
99
|
this.pipelineLogger = createNoopPipelineLogger();
|
|
98
100
|
}
|
|
101
|
+
// Register critical routes early (before provider initialization)
|
|
102
|
+
// This ensures OAuth Portal is available when providers check token validity
|
|
103
|
+
registerDefaultMiddleware(this.app);
|
|
104
|
+
registerOAuthPortalRoute(this.app);
|
|
105
|
+
console.log('[RouteCodexHttpServer] OAuth Portal route registered (early initialization)');
|
|
99
106
|
console.log('[RouteCodexHttpServer] Initialized (pipeline=hub)');
|
|
100
107
|
}
|
|
101
108
|
resolveVirtualRouterInput(userConfig) {
|
|
@@ -122,6 +129,9 @@ export class RouteCodexHttpServer {
|
|
|
122
129
|
const sanitizedContext = formatErrorForErrorCenter(contextPayload);
|
|
123
130
|
await this.errorHandling.handleError({
|
|
124
131
|
error: sanitizedError,
|
|
132
|
+
source: 'pipeline',
|
|
133
|
+
severity: 'medium',
|
|
134
|
+
timestamp: Date.now(),
|
|
125
135
|
context: sanitizedContext
|
|
126
136
|
});
|
|
127
137
|
},
|
|
@@ -329,7 +339,8 @@ export class RouteCodexHttpServer {
|
|
|
329
339
|
// 初始化错误处理
|
|
330
340
|
await this.errorHandling.initialize();
|
|
331
341
|
await this.initializeRouteErrorHub();
|
|
332
|
-
registerDefaultMiddleware
|
|
342
|
+
// registerDefaultMiddleware and registerOAuthPortalRoute already called in constructor
|
|
343
|
+
// Register remaining HTTP routes
|
|
333
344
|
registerHttpRoutes({
|
|
334
345
|
app: this.app,
|
|
335
346
|
config: this.config,
|
|
@@ -434,8 +445,8 @@ export class RouteCodexHttpServer {
|
|
|
434
445
|
await reportRouteError(payload);
|
|
435
446
|
}
|
|
436
447
|
catch (handlerError) {
|
|
437
|
-
console.error('[RouteCodexHttpServer] Failed to report error via RouteErrorHub:', handlerError);
|
|
438
|
-
console.error('[RouteCodexHttpServer] Original error:', error);
|
|
448
|
+
console.error('[RouteCodexHttpServer] Failed to report error via RouteErrorHub:', formatValueForConsole(handlerError));
|
|
449
|
+
console.error('[RouteCodexHttpServer] Original error:', formatValueForConsole(error));
|
|
439
450
|
}
|
|
440
451
|
}
|
|
441
452
|
// --- V1 parity helpers and attach methods ---
|
|
@@ -619,14 +630,14 @@ export class RouteCodexHttpServer {
|
|
|
619
630
|
if (!this.isPipelineReady()) {
|
|
620
631
|
throw new Error('Hub pipeline runtime is not initialized');
|
|
621
632
|
}
|
|
622
|
-
const
|
|
633
|
+
const initialMetadata = this.buildRequestMetadata(input);
|
|
623
634
|
const providerRequestId = input.requestId;
|
|
624
|
-
const clientRequestId = typeof
|
|
625
|
-
?
|
|
635
|
+
const clientRequestId = typeof initialMetadata.clientRequestId === 'string' && initialMetadata.clientRequestId.trim()
|
|
636
|
+
? initialMetadata.clientRequestId.trim()
|
|
626
637
|
: providerRequestId;
|
|
627
638
|
this.logStage('request.received', providerRequestId, {
|
|
628
639
|
endpoint: input.entryEndpoint,
|
|
629
|
-
stream:
|
|
640
|
+
stream: initialMetadata.stream === true
|
|
630
641
|
});
|
|
631
642
|
try {
|
|
632
643
|
const headerUa = (typeof input.headers?.['user-agent'] === 'string' && input.headers['user-agent']) ||
|
|
@@ -639,7 +650,7 @@ export class RouteCodexHttpServer {
|
|
|
639
650
|
headers: asRecord(input.headers),
|
|
640
651
|
body: input.body,
|
|
641
652
|
metadata: {
|
|
642
|
-
...
|
|
653
|
+
...initialMetadata,
|
|
643
654
|
userAgent: headerUa,
|
|
644
655
|
clientOriginator: headerOriginator
|
|
645
656
|
}
|
|
@@ -649,155 +660,161 @@ export class RouteCodexHttpServer {
|
|
|
649
660
|
// snapshot failure should not block request path
|
|
650
661
|
}
|
|
651
662
|
const pipelineLabel = 'hub';
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
const pipelineMetadata = pipelineResult.metadata ?? {};
|
|
659
|
-
const mergedMetadata = { ...metadata, ...pipelineMetadata };
|
|
660
|
-
this.logStage(`${pipelineLabel}.completed`, providerRequestId, {
|
|
661
|
-
route: pipelineResult.routingDecision?.routeName,
|
|
662
|
-
target: pipelineResult.target?.providerKey
|
|
663
|
-
});
|
|
664
|
-
const providerPayload = pipelineResult.providerPayload;
|
|
665
|
-
const target = pipelineResult.target;
|
|
666
|
-
if (!providerPayload || !target?.providerKey) {
|
|
667
|
-
throw Object.assign(new Error('Virtual router did not produce a provider target'), {
|
|
668
|
-
code: 'ERR_NO_PROVIDER_TARGET',
|
|
669
|
-
requestId: input.requestId
|
|
670
|
-
});
|
|
671
|
-
}
|
|
672
|
-
const runtimeKey = target.runtimeKey || this.providerKeyToRuntimeKey.get(target.providerKey);
|
|
673
|
-
if (!runtimeKey) {
|
|
674
|
-
throw Object.assign(new Error(`Runtime for provider ${target.providerKey} not initialized`), {
|
|
675
|
-
code: 'ERR_RUNTIME_NOT_FOUND',
|
|
676
|
-
requestId: input.requestId
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
const handle = this.providerHandles.get(runtimeKey);
|
|
680
|
-
if (!handle) {
|
|
681
|
-
throw Object.assign(new Error(`Provider runtime ${runtimeKey} not found`), {
|
|
682
|
-
code: 'ERR_PROVIDER_NOT_FOUND',
|
|
683
|
-
requestId: input.requestId
|
|
663
|
+
let iterationMetadata = initialMetadata;
|
|
664
|
+
let followupTriggered = false;
|
|
665
|
+
while (true) {
|
|
666
|
+
this.logStage(`${pipelineLabel}.start`, providerRequestId, {
|
|
667
|
+
endpoint: input.entryEndpoint,
|
|
668
|
+
stream: iterationMetadata.stream
|
|
684
669
|
});
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
(typeof metadataModel === 'string' ? metadataModel : undefined);
|
|
693
|
-
const providerIdToken = target.providerKey || handle.providerId || runtimeKey;
|
|
694
|
-
if (!providerIdToken) {
|
|
695
|
-
throw Object.assign(new Error('Provider identifier missing for request'), {
|
|
696
|
-
code: 'ERR_PROVIDER_ID_MISSING',
|
|
697
|
-
requestId: providerRequestId
|
|
670
|
+
const originalRequestSnapshot = this.cloneRequestPayload(input.body);
|
|
671
|
+
const pipelineResult = await this.runHubPipeline(input, iterationMetadata);
|
|
672
|
+
const pipelineMetadata = pipelineResult.metadata ?? {};
|
|
673
|
+
const mergedMetadata = { ...iterationMetadata, ...pipelineMetadata };
|
|
674
|
+
this.logStage(`${pipelineLabel}.completed`, providerRequestId, {
|
|
675
|
+
route: pipelineResult.routingDecision?.routeName,
|
|
676
|
+
target: pipelineResult.target?.providerKey
|
|
698
677
|
});
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
try {
|
|
707
|
-
await rebindResponsesConversationRequestId(pipelineResult.requestId, enhancedRequestId);
|
|
678
|
+
const providerPayload = pipelineResult.providerPayload;
|
|
679
|
+
const target = pipelineResult.target;
|
|
680
|
+
if (!providerPayload || !target?.providerKey) {
|
|
681
|
+
throw Object.assign(new Error('Virtual router did not produce a provider target'), {
|
|
682
|
+
code: 'ERR_NO_PROVIDER_TARGET',
|
|
683
|
+
requestId: input.requestId
|
|
684
|
+
});
|
|
708
685
|
}
|
|
709
|
-
|
|
710
|
-
|
|
686
|
+
const runtimeKey = target.runtimeKey || this.providerKeyToRuntimeKey.get(target.providerKey);
|
|
687
|
+
if (!runtimeKey) {
|
|
688
|
+
throw Object.assign(new Error(`Runtime for provider ${target.providerKey} not initialized`), {
|
|
689
|
+
code: 'ERR_RUNTIME_NOT_FOUND',
|
|
690
|
+
requestId: input.requestId
|
|
691
|
+
});
|
|
711
692
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
providerProtocol,
|
|
735
|
-
pipelineId: target.providerKey,
|
|
736
|
-
routeName: pipelineResult.routingDecision?.routeName,
|
|
737
|
-
runtimeKey,
|
|
738
|
-
target,
|
|
739
|
-
metadata: mergedMetadata
|
|
740
|
-
});
|
|
741
|
-
this.logStage('provider.send.start', input.requestId, {
|
|
742
|
-
providerKey: target.providerKey,
|
|
743
|
-
runtimeKey,
|
|
744
|
-
protocol: providerProtocol,
|
|
745
|
-
providerType: handle.providerType,
|
|
746
|
-
providerFamily: handle.providerFamily,
|
|
747
|
-
model: providerModel,
|
|
748
|
-
providerLabel
|
|
749
|
-
});
|
|
750
|
-
try {
|
|
751
|
-
const providerResponse = await handle.instance.processIncoming(providerPayload);
|
|
752
|
-
const responseStatus = this.extractResponseStatus(providerResponse);
|
|
753
|
-
this.logStage('provider.send.completed', input.requestId, {
|
|
754
|
-
providerKey: target.providerKey,
|
|
755
|
-
status: responseStatus,
|
|
756
|
-
providerType: handle.providerType,
|
|
757
|
-
providerFamily: handle.providerFamily,
|
|
758
|
-
model: providerModel,
|
|
759
|
-
providerLabel
|
|
760
|
-
});
|
|
761
|
-
const normalized = this.normalizeProviderResponse(providerResponse);
|
|
762
|
-
return await this.convertProviderResponseIfNeeded({
|
|
693
|
+
const handle = this.providerHandles.get(runtimeKey);
|
|
694
|
+
if (!handle) {
|
|
695
|
+
throw Object.assign(new Error(`Provider runtime ${runtimeKey} not found`), {
|
|
696
|
+
code: 'ERR_PROVIDER_NOT_FOUND',
|
|
697
|
+
requestId: input.requestId
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
const providerProtocol = target.outboundProfile ||
|
|
701
|
+
handle.providerProtocol;
|
|
702
|
+
const metadataModel = mergedMetadata?.target && typeof mergedMetadata.target === 'object'
|
|
703
|
+
? mergedMetadata.target.clientModelId
|
|
704
|
+
: undefined;
|
|
705
|
+
const rawModel = this.extractProviderModel(providerPayload) ||
|
|
706
|
+
(typeof metadataModel === 'string' ? metadataModel : undefined);
|
|
707
|
+
const providerIdToken = target.providerKey || handle.providerId || runtimeKey;
|
|
708
|
+
if (!providerIdToken) {
|
|
709
|
+
throw Object.assign(new Error('Provider identifier missing for request'), {
|
|
710
|
+
code: 'ERR_PROVIDER_ID_MISSING',
|
|
711
|
+
requestId: providerRequestId
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
const enhancedRequestId = enhanceProviderRequestId(providerRequestId, {
|
|
763
715
|
entryEndpoint: input.entryEndpoint,
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
wantsStream: Boolean(input.metadata?.inboundStream ?? input.metadata?.stream),
|
|
767
|
-
originalRequest: originalRequestSnapshot,
|
|
768
|
-
processMode: pipelineResult.processMode,
|
|
769
|
-
response: normalized,
|
|
770
|
-
pipelineMetadata: mergedMetadata
|
|
716
|
+
providerId: providerIdToken,
|
|
717
|
+
model: rawModel
|
|
771
718
|
});
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
719
|
+
if (providerProtocol === 'openai-responses') {
|
|
720
|
+
try {
|
|
721
|
+
await rebindResponsesConversationRequestId(pipelineResult.requestId, enhancedRequestId);
|
|
722
|
+
}
|
|
723
|
+
catch {
|
|
724
|
+
/* ignore rebind failures */
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
if (enhancedRequestId !== input.requestId) {
|
|
728
|
+
input.requestId = enhancedRequestId;
|
|
729
|
+
}
|
|
730
|
+
mergedMetadata.clientRequestId = clientRequestId;
|
|
731
|
+
const providerModel = rawModel;
|
|
732
|
+
const providerLabel = this.buildProviderLabel(target.providerKey, providerModel);
|
|
733
|
+
this.logStage('provider.prepare', input.requestId, {
|
|
775
734
|
providerKey: target.providerKey,
|
|
776
|
-
|
|
735
|
+
runtimeKey,
|
|
736
|
+
protocol: providerProtocol,
|
|
777
737
|
providerType: handle.providerType,
|
|
778
738
|
providerFamily: handle.providerFamily,
|
|
779
739
|
model: providerModel,
|
|
780
740
|
providerLabel
|
|
781
741
|
});
|
|
782
|
-
|
|
742
|
+
attachProviderRuntimeMetadata(providerPayload, {
|
|
783
743
|
requestId: input.requestId,
|
|
784
|
-
providerKey: target.providerKey,
|
|
785
744
|
providerId: handle.providerId,
|
|
745
|
+
providerKey: target.providerKey,
|
|
786
746
|
providerType: handle.providerType,
|
|
747
|
+
providerFamily: handle.providerFamily,
|
|
787
748
|
providerProtocol,
|
|
788
|
-
routeName: pipelineResult.routingDecision?.routeName,
|
|
789
749
|
pipelineId: target.providerKey,
|
|
750
|
+
routeName: pipelineResult.routingDecision?.routeName,
|
|
790
751
|
runtimeKey,
|
|
791
|
-
target
|
|
792
|
-
|
|
793
|
-
runtimeMetadata.providerFamily = handle.providerFamily;
|
|
794
|
-
emitProviderError({
|
|
795
|
-
error,
|
|
796
|
-
stage: 'provider.send',
|
|
797
|
-
runtime: runtimeMetadata,
|
|
798
|
-
dependencies: this.getModuleDependencies()
|
|
752
|
+
target,
|
|
753
|
+
metadata: mergedMetadata
|
|
799
754
|
});
|
|
800
|
-
|
|
755
|
+
this.logStage('provider.send.start', input.requestId, {
|
|
756
|
+
providerKey: target.providerKey,
|
|
757
|
+
runtimeKey,
|
|
758
|
+
protocol: providerProtocol,
|
|
759
|
+
providerType: handle.providerType,
|
|
760
|
+
providerFamily: handle.providerFamily,
|
|
761
|
+
model: providerModel,
|
|
762
|
+
providerLabel
|
|
763
|
+
});
|
|
764
|
+
try {
|
|
765
|
+
const providerResponse = await handle.instance.processIncoming(providerPayload);
|
|
766
|
+
const responseStatus = this.extractResponseStatus(providerResponse);
|
|
767
|
+
this.logStage('provider.send.completed', input.requestId, {
|
|
768
|
+
providerKey: target.providerKey,
|
|
769
|
+
status: responseStatus,
|
|
770
|
+
providerType: handle.providerType,
|
|
771
|
+
providerFamily: handle.providerFamily,
|
|
772
|
+
model: providerModel,
|
|
773
|
+
providerLabel
|
|
774
|
+
});
|
|
775
|
+
const wantsStreamBase = Boolean(input.metadata?.inboundStream ?? input.metadata?.stream);
|
|
776
|
+
const normalized = this.normalizeProviderResponse(providerResponse);
|
|
777
|
+
const converted = await this.convertProviderResponseIfNeeded({
|
|
778
|
+
entryEndpoint: input.entryEndpoint,
|
|
779
|
+
providerType: handle.providerType,
|
|
780
|
+
requestId: input.requestId,
|
|
781
|
+
wantsStream: wantsStreamBase,
|
|
782
|
+
originalRequest: originalRequestSnapshot,
|
|
783
|
+
processMode: pipelineResult.processMode,
|
|
784
|
+
response: normalized,
|
|
785
|
+
pipelineMetadata: mergedMetadata
|
|
786
|
+
});
|
|
787
|
+
return converted;
|
|
788
|
+
}
|
|
789
|
+
catch (error) {
|
|
790
|
+
this.logStage('provider.send.error', input.requestId, {
|
|
791
|
+
providerKey: target.providerKey,
|
|
792
|
+
message: error instanceof Error ? error.message : String(error ?? 'Unknown error'),
|
|
793
|
+
providerType: handle.providerType,
|
|
794
|
+
providerFamily: handle.providerFamily,
|
|
795
|
+
model: providerModel,
|
|
796
|
+
providerLabel
|
|
797
|
+
});
|
|
798
|
+
const runtimeMetadata = {
|
|
799
|
+
requestId: input.requestId,
|
|
800
|
+
providerKey: target.providerKey,
|
|
801
|
+
providerId: handle.providerId,
|
|
802
|
+
providerType: handle.providerType,
|
|
803
|
+
providerProtocol,
|
|
804
|
+
routeName: pipelineResult.routingDecision?.routeName,
|
|
805
|
+
pipelineId: target.providerKey,
|
|
806
|
+
runtimeKey,
|
|
807
|
+
target
|
|
808
|
+
};
|
|
809
|
+
runtimeMetadata.providerFamily = handle.providerFamily;
|
|
810
|
+
emitProviderError({
|
|
811
|
+
error,
|
|
812
|
+
stage: 'provider.send',
|
|
813
|
+
runtime: runtimeMetadata,
|
|
814
|
+
dependencies: this.getModuleDependencies()
|
|
815
|
+
});
|
|
816
|
+
throw error;
|
|
817
|
+
}
|
|
801
818
|
}
|
|
802
819
|
}
|
|
803
820
|
async runHubPipeline(input, metadata) {
|
|
@@ -836,6 +853,15 @@ export class RouteCodexHttpServer {
|
|
|
836
853
|
}
|
|
837
854
|
buildRequestMetadata(input) {
|
|
838
855
|
const userMeta = asRecord(input.metadata);
|
|
856
|
+
const headers = asRecord(input.headers);
|
|
857
|
+
const inboundUserAgent = this.extractHeaderValue(headers, 'user-agent');
|
|
858
|
+
const inboundOriginator = this.extractHeaderValue(headers, 'originator');
|
|
859
|
+
const resolvedUserAgent = typeof userMeta.userAgent === 'string' && userMeta.userAgent.trim()
|
|
860
|
+
? userMeta.userAgent.trim()
|
|
861
|
+
: inboundUserAgent;
|
|
862
|
+
const resolvedOriginator = typeof userMeta.clientOriginator === 'string' && userMeta.clientOriginator.trim()
|
|
863
|
+
? userMeta.clientOriginator.trim()
|
|
864
|
+
: inboundOriginator;
|
|
839
865
|
const routeHint = this.extractRouteHint(input) ?? userMeta.routeHint;
|
|
840
866
|
const processMode = userMeta.processMode || 'chat';
|
|
841
867
|
return {
|
|
@@ -845,9 +871,30 @@ export class RouteCodexHttpServer {
|
|
|
845
871
|
direction: 'request',
|
|
846
872
|
stage: 'inbound',
|
|
847
873
|
routeHint,
|
|
848
|
-
stream: userMeta.stream === true
|
|
874
|
+
stream: userMeta.stream === true,
|
|
875
|
+
...(resolvedUserAgent ? { userAgent: resolvedUserAgent } : {}),
|
|
876
|
+
...(resolvedOriginator ? { clientOriginator: resolvedOriginator } : {})
|
|
849
877
|
};
|
|
850
878
|
}
|
|
879
|
+
extractHeaderValue(headers, name) {
|
|
880
|
+
if (!headers) {
|
|
881
|
+
return undefined;
|
|
882
|
+
}
|
|
883
|
+
const target = name.toLowerCase();
|
|
884
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
885
|
+
if (key.toLowerCase() !== target) {
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
if (typeof value === 'string') {
|
|
889
|
+
return value.trim() || undefined;
|
|
890
|
+
}
|
|
891
|
+
if (Array.isArray(value) && value.length) {
|
|
892
|
+
return String(value[0]).trim() || undefined;
|
|
893
|
+
}
|
|
894
|
+
return undefined;
|
|
895
|
+
}
|
|
896
|
+
return undefined;
|
|
897
|
+
}
|
|
851
898
|
extractRouteHint(input) {
|
|
852
899
|
const header = input.headers['x-route-hint'];
|
|
853
900
|
if (typeof header === 'string' && header.trim()) {
|
|
@@ -905,12 +952,28 @@ export class RouteCodexHttpServer {
|
|
|
905
952
|
const metadataBag = asRecord(options.pipelineMetadata);
|
|
906
953
|
const aliasMap = extractAnthropicToolAliasMap(metadataBag);
|
|
907
954
|
const originalModelId = this.extractClientModelId(metadataBag, options.originalRequest);
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
955
|
+
// 以 HubPipeline metadata 为基础构建 AdapterContext,确保诸如
|
|
956
|
+
// capturedChatRequest / webSearch / routeHint 等字段在响应侧可见,
|
|
957
|
+
// 便于 llmswitch-core 内部实现 servertool/web_search 的第三跳。
|
|
958
|
+
const baseContext = {
|
|
959
|
+
...(metadataBag ?? {})
|
|
913
960
|
};
|
|
961
|
+
// 将 HubPipeline metadata.routeName 映射为 AdapterContext.routeId,
|
|
962
|
+
// 便于 llmswitch-core 在第三跳中使用 routeHint 复用首次路由决策。
|
|
963
|
+
if (typeof metadataBag?.routeName === 'string') {
|
|
964
|
+
baseContext.routeId = metadataBag.routeName;
|
|
965
|
+
}
|
|
966
|
+
baseContext.requestId = options.requestId;
|
|
967
|
+
baseContext.entryEndpoint = options.entryEndpoint || entry;
|
|
968
|
+
baseContext.providerProtocol = providerProtocol;
|
|
969
|
+
baseContext.originalModelId = originalModelId;
|
|
970
|
+
const adapterContext = baseContext;
|
|
971
|
+
// 将 serverToolFollowup 等标记从 pipelineMetadata 透传到 AdapterContext,
|
|
972
|
+
// 便于 convertProviderResponse 正确识别内部二跳请求并跳过 servertool。
|
|
973
|
+
if (metadataBag && Object.prototype.hasOwnProperty.call(metadataBag, 'serverToolFollowup')) {
|
|
974
|
+
adapterContext.serverToolFollowup = metadataBag
|
|
975
|
+
.serverToolFollowup;
|
|
976
|
+
}
|
|
914
977
|
const compatProfile = metadataBag &&
|
|
915
978
|
typeof metadataBag === 'object' &&
|
|
916
979
|
metadataBag.target &&
|
|
@@ -924,18 +987,85 @@ export class RouteCodexHttpServer {
|
|
|
924
987
|
if (aliasMap) {
|
|
925
988
|
adapterContext.anthropicToolNameMap = aliasMap;
|
|
926
989
|
}
|
|
990
|
+
if (metadataBag && typeof metadataBag === 'object') {
|
|
991
|
+
const webSearchConfig = metadataBag.webSearch;
|
|
992
|
+
if (webSearchConfig && typeof webSearchConfig === 'object') {
|
|
993
|
+
adapterContext.webSearch = webSearchConfig;
|
|
994
|
+
}
|
|
995
|
+
if (metadataBag.forceWebSearch === true) {
|
|
996
|
+
adapterContext.forceWebSearch = true;
|
|
997
|
+
}
|
|
998
|
+
if (metadataBag.forceVision === true) {
|
|
999
|
+
adapterContext.forceVision = true;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
927
1002
|
const [convertProviderResponse, createSnapshotRecorder] = await Promise.all([
|
|
928
1003
|
loadConvertProviderResponse(),
|
|
929
1004
|
loadSnapshotRecorderFactory()
|
|
930
1005
|
]);
|
|
931
|
-
const stageRecorder = createSnapshotRecorder(adapterContext, adapterContext.entryEndpoint
|
|
1006
|
+
const stageRecorder = createSnapshotRecorder(adapterContext, typeof adapterContext.entryEndpoint === 'string'
|
|
1007
|
+
? adapterContext.entryEndpoint
|
|
1008
|
+
: options.entryEndpoint || entry);
|
|
1009
|
+
const providerInvoker = async (invokeOptions) => {
|
|
1010
|
+
const runtimeKey = this.providerKeyToRuntimeKey.get(invokeOptions.providerKey) || invokeOptions.providerKey;
|
|
1011
|
+
const handle = this.providerHandles.get(runtimeKey);
|
|
1012
|
+
if (!handle) {
|
|
1013
|
+
throw new Error(`Provider runtime ${runtimeKey} not found`);
|
|
1014
|
+
}
|
|
1015
|
+
const providerResponse = await handle.instance.processIncoming(invokeOptions.payload);
|
|
1016
|
+
const normalized = this.normalizeProviderResponse(providerResponse);
|
|
1017
|
+
const bodyPayload = normalized.body && typeof normalized.body === 'object'
|
|
1018
|
+
? normalized.body
|
|
1019
|
+
: normalized;
|
|
1020
|
+
return { providerResponse: bodyPayload };
|
|
1021
|
+
};
|
|
1022
|
+
const reenterPipeline = async (reenterOpts) => {
|
|
1023
|
+
const nestedEntry = reenterOpts.entryEndpoint || options.entryEndpoint || entry;
|
|
1024
|
+
const nestedExtra = asRecord(reenterOpts.metadata) ?? {};
|
|
1025
|
+
const nestedEntryLower = nestedEntry.toLowerCase();
|
|
1026
|
+
// 基于首次 HubPipeline metadata + 调用方注入的 metadata 构建新的请求 metadata。
|
|
1027
|
+
// 不在 Host 层编码 servertool/web_search 等语义,由 llmswitch-core 负责。
|
|
1028
|
+
const nestedMetadata = {
|
|
1029
|
+
...(metadataBag ?? {}),
|
|
1030
|
+
...nestedExtra,
|
|
1031
|
+
entryEndpoint: nestedEntry,
|
|
1032
|
+
direction: 'request',
|
|
1033
|
+
stage: 'inbound'
|
|
1034
|
+
};
|
|
1035
|
+
// 针对 reenterPipeline 的入口端点,纠正 providerProtocol,避免沿用外层协议。
|
|
1036
|
+
if (nestedEntryLower.includes('/v1/chat/completions')) {
|
|
1037
|
+
nestedMetadata.providerProtocol = 'openai-chat';
|
|
1038
|
+
}
|
|
1039
|
+
else if (nestedEntryLower.includes('/v1/responses')) {
|
|
1040
|
+
nestedMetadata.providerProtocol = 'openai-responses';
|
|
1041
|
+
}
|
|
1042
|
+
else if (nestedEntryLower.includes('/v1/messages')) {
|
|
1043
|
+
nestedMetadata.providerProtocol = 'anthropic-messages';
|
|
1044
|
+
}
|
|
1045
|
+
const nestedInput = {
|
|
1046
|
+
entryEndpoint: nestedEntry,
|
|
1047
|
+
method: 'POST',
|
|
1048
|
+
requestId: reenterOpts.requestId,
|
|
1049
|
+
headers: {},
|
|
1050
|
+
query: {},
|
|
1051
|
+
body: reenterOpts.body,
|
|
1052
|
+
metadata: nestedMetadata
|
|
1053
|
+
};
|
|
1054
|
+
const nestedResult = await this.executePipeline(nestedInput);
|
|
1055
|
+
const nestedBody = nestedResult.body && typeof nestedResult.body === 'object'
|
|
1056
|
+
? nestedResult.body
|
|
1057
|
+
: undefined;
|
|
1058
|
+
return { body: nestedBody };
|
|
1059
|
+
};
|
|
932
1060
|
const converted = await convertProviderResponse({
|
|
933
1061
|
providerProtocol,
|
|
934
1062
|
providerResponse: body,
|
|
935
1063
|
context: adapterContext,
|
|
936
1064
|
entryEndpoint: options.entryEndpoint || entry,
|
|
937
1065
|
wantsStream: options.wantsStream,
|
|
938
|
-
|
|
1066
|
+
providerInvoker,
|
|
1067
|
+
stageRecorder,
|
|
1068
|
+
reenterPipeline
|
|
939
1069
|
});
|
|
940
1070
|
if (converted.__sse_responses) {
|
|
941
1071
|
return {
|
|
@@ -985,6 +1115,279 @@ export class RouteCodexHttpServer {
|
|
|
985
1115
|
return undefined;
|
|
986
1116
|
}
|
|
987
1117
|
}
|
|
1118
|
+
buildVisionFollowupPayload(options) {
|
|
1119
|
+
const { originalPayload, visionResponse } = options;
|
|
1120
|
+
if (!originalPayload || typeof originalPayload !== 'object') {
|
|
1121
|
+
return null;
|
|
1122
|
+
}
|
|
1123
|
+
const clone = this.cloneRequestPayload(originalPayload) ?? { ...originalPayload };
|
|
1124
|
+
if (!clone) {
|
|
1125
|
+
return null;
|
|
1126
|
+
}
|
|
1127
|
+
const visionText = this.extractVisionDescription(visionResponse?.body);
|
|
1128
|
+
if (!visionText) {
|
|
1129
|
+
return null;
|
|
1130
|
+
}
|
|
1131
|
+
if (this.rewriteResponsesInput(clone, visionText)) {
|
|
1132
|
+
return clone;
|
|
1133
|
+
}
|
|
1134
|
+
if (this.rewriteChatMessages(clone, visionText)) {
|
|
1135
|
+
return clone;
|
|
1136
|
+
}
|
|
1137
|
+
return null;
|
|
1138
|
+
}
|
|
1139
|
+
rewriteResponsesInput(payload, visionText) {
|
|
1140
|
+
const inputList = payload.input;
|
|
1141
|
+
if (!Array.isArray(inputList)) {
|
|
1142
|
+
return false;
|
|
1143
|
+
}
|
|
1144
|
+
for (let i = inputList.length - 1; i >= 0; i -= 1) {
|
|
1145
|
+
const item = inputList[i];
|
|
1146
|
+
if (!item || typeof item !== 'object') {
|
|
1147
|
+
continue;
|
|
1148
|
+
}
|
|
1149
|
+
const role = typeof item.role === 'string'
|
|
1150
|
+
? item.role
|
|
1151
|
+
: '';
|
|
1152
|
+
if (role !== 'user') {
|
|
1153
|
+
continue;
|
|
1154
|
+
}
|
|
1155
|
+
const contentBlocks = Array.isArray(item.content)
|
|
1156
|
+
? [...item.content]
|
|
1157
|
+
: [];
|
|
1158
|
+
const originalText = this.extractTextFromContentBlocks(contentBlocks, ['input_text', 'text']);
|
|
1159
|
+
const textType = this.detectContentTextType(contentBlocks, 'input_text');
|
|
1160
|
+
const composed = this.composeVisionUserText(visionText, originalText);
|
|
1161
|
+
item.content = [
|
|
1162
|
+
{
|
|
1163
|
+
type: textType,
|
|
1164
|
+
text: composed
|
|
1165
|
+
}
|
|
1166
|
+
];
|
|
1167
|
+
inputList[i] = item;
|
|
1168
|
+
return true;
|
|
1169
|
+
}
|
|
1170
|
+
return false;
|
|
1171
|
+
}
|
|
1172
|
+
rewriteChatMessages(payload, visionText) {
|
|
1173
|
+
const messages = payload.messages;
|
|
1174
|
+
if (!Array.isArray(messages)) {
|
|
1175
|
+
return false;
|
|
1176
|
+
}
|
|
1177
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
1178
|
+
const message = messages[i];
|
|
1179
|
+
if (!message || typeof message !== 'object') {
|
|
1180
|
+
continue;
|
|
1181
|
+
}
|
|
1182
|
+
const role = typeof message.role === 'string'
|
|
1183
|
+
? message.role
|
|
1184
|
+
: '';
|
|
1185
|
+
if (role !== 'user') {
|
|
1186
|
+
continue;
|
|
1187
|
+
}
|
|
1188
|
+
const contentBlocks = Array.isArray(message.content)
|
|
1189
|
+
? [...message.content]
|
|
1190
|
+
: [];
|
|
1191
|
+
const originalText = this.extractTextFromContentBlocks(contentBlocks, ['text']);
|
|
1192
|
+
const textType = this.detectContentTextType(contentBlocks, 'text');
|
|
1193
|
+
const composed = this.composeVisionUserText(visionText, originalText);
|
|
1194
|
+
message.content = [
|
|
1195
|
+
{
|
|
1196
|
+
type: textType,
|
|
1197
|
+
text: composed
|
|
1198
|
+
}
|
|
1199
|
+
];
|
|
1200
|
+
messages[i] = message;
|
|
1201
|
+
return true;
|
|
1202
|
+
}
|
|
1203
|
+
return false;
|
|
1204
|
+
}
|
|
1205
|
+
extractTextFromContentBlocks(content, allowedTypes) {
|
|
1206
|
+
if (typeof content === 'string') {
|
|
1207
|
+
return content;
|
|
1208
|
+
}
|
|
1209
|
+
if (!Array.isArray(content)) {
|
|
1210
|
+
return '';
|
|
1211
|
+
}
|
|
1212
|
+
const collected = [];
|
|
1213
|
+
for (const block of content) {
|
|
1214
|
+
if (!block || typeof block !== 'object') {
|
|
1215
|
+
continue;
|
|
1216
|
+
}
|
|
1217
|
+
const typeValue = typeof block.type === 'string'
|
|
1218
|
+
? block.type
|
|
1219
|
+
: '';
|
|
1220
|
+
if (allowedTypes.length && !allowedTypes.includes(typeValue)) {
|
|
1221
|
+
continue;
|
|
1222
|
+
}
|
|
1223
|
+
const textValue = block.text;
|
|
1224
|
+
if (typeof textValue === 'string' && textValue.trim()) {
|
|
1225
|
+
collected.push(textValue.trim());
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
return collected.join('\n');
|
|
1229
|
+
}
|
|
1230
|
+
detectContentTextType(content, fallback) {
|
|
1231
|
+
if (Array.isArray(content)) {
|
|
1232
|
+
for (const block of content) {
|
|
1233
|
+
if (!block || typeof block !== 'object') {
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
const typeValue = block.type;
|
|
1237
|
+
if (typeof typeValue === 'string' && (typeValue === 'text' || typeValue === 'input_text')) {
|
|
1238
|
+
return typeValue;
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
return fallback;
|
|
1243
|
+
}
|
|
1244
|
+
composeVisionUserText(visionText, originalText) {
|
|
1245
|
+
const sections = [];
|
|
1246
|
+
const cleanedVision = (visionText || '').trim();
|
|
1247
|
+
if (cleanedVision) {
|
|
1248
|
+
sections.push(`【图片分析】\n${cleanedVision}`);
|
|
1249
|
+
}
|
|
1250
|
+
const cleanedOriginal = (originalText || '').trim();
|
|
1251
|
+
if (cleanedOriginal) {
|
|
1252
|
+
sections.push(`【用户原始请求】\n${cleanedOriginal}`);
|
|
1253
|
+
}
|
|
1254
|
+
return sections.join('\n\n');
|
|
1255
|
+
}
|
|
1256
|
+
extractVisionDescription(body) {
|
|
1257
|
+
if (!body) {
|
|
1258
|
+
return null;
|
|
1259
|
+
}
|
|
1260
|
+
if (typeof body === 'string') {
|
|
1261
|
+
const trimmed = body.trim();
|
|
1262
|
+
return trimmed.length ? trimmed : null;
|
|
1263
|
+
}
|
|
1264
|
+
if (typeof body !== 'object') {
|
|
1265
|
+
return null;
|
|
1266
|
+
}
|
|
1267
|
+
const record = body;
|
|
1268
|
+
const direct = this.extractTextCandidate(record);
|
|
1269
|
+
if (direct) {
|
|
1270
|
+
return direct;
|
|
1271
|
+
}
|
|
1272
|
+
if (record.response && typeof record.response === 'object') {
|
|
1273
|
+
const responseNode = record.response;
|
|
1274
|
+
const nested = this.extractTextCandidate(responseNode);
|
|
1275
|
+
if (nested) {
|
|
1276
|
+
return nested;
|
|
1277
|
+
}
|
|
1278
|
+
const output = responseNode.output;
|
|
1279
|
+
if (Array.isArray(output)) {
|
|
1280
|
+
for (const entry of output) {
|
|
1281
|
+
if (entry && typeof entry === 'object') {
|
|
1282
|
+
const nestedText = this.extractTextCandidate(entry);
|
|
1283
|
+
if (nestedText) {
|
|
1284
|
+
return nestedText;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
if (Array.isArray(record.output)) {
|
|
1291
|
+
for (const entry of record.output) {
|
|
1292
|
+
if (entry && typeof entry === 'object') {
|
|
1293
|
+
const nested = this.extractTextCandidate(entry);
|
|
1294
|
+
if (nested) {
|
|
1295
|
+
return nested;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
const choices = record.choices;
|
|
1301
|
+
if (Array.isArray(choices)) {
|
|
1302
|
+
for (const choice of choices) {
|
|
1303
|
+
if (!choice || typeof choice !== 'object') {
|
|
1304
|
+
continue;
|
|
1305
|
+
}
|
|
1306
|
+
const message = choice.message;
|
|
1307
|
+
if (message && typeof message === 'object') {
|
|
1308
|
+
const msg = message;
|
|
1309
|
+
const content = msg.content;
|
|
1310
|
+
if (typeof content === 'string' && content.trim()) {
|
|
1311
|
+
return content.trim();
|
|
1312
|
+
}
|
|
1313
|
+
if (Array.isArray(content)) {
|
|
1314
|
+
for (const part of content) {
|
|
1315
|
+
if (part && typeof part === 'object' && typeof part.text === 'string') {
|
|
1316
|
+
const textValue = part.text.trim();
|
|
1317
|
+
if (textValue) {
|
|
1318
|
+
return textValue;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
return null;
|
|
1327
|
+
}
|
|
1328
|
+
extractTextCandidate(record) {
|
|
1329
|
+
const candidates = [
|
|
1330
|
+
{ key: 'output_text', allowJson: true },
|
|
1331
|
+
{ key: 'text' },
|
|
1332
|
+
{ key: 'content' }
|
|
1333
|
+
];
|
|
1334
|
+
for (const candidate of candidates) {
|
|
1335
|
+
if (!(candidate.key in record)) {
|
|
1336
|
+
continue;
|
|
1337
|
+
}
|
|
1338
|
+
const text = this.normalizeTextCandidateValue(record[candidate.key], candidate.allowJson === true);
|
|
1339
|
+
if (text) {
|
|
1340
|
+
return text;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
return null;
|
|
1344
|
+
}
|
|
1345
|
+
normalizeTextCandidateValue(value, allowJsonStringify = false) {
|
|
1346
|
+
if (!value) {
|
|
1347
|
+
return null;
|
|
1348
|
+
}
|
|
1349
|
+
if (typeof value === 'string') {
|
|
1350
|
+
const trimmed = value.trim();
|
|
1351
|
+
return trimmed.length ? trimmed : null;
|
|
1352
|
+
}
|
|
1353
|
+
if (Array.isArray(value)) {
|
|
1354
|
+
const collected = [];
|
|
1355
|
+
for (const entry of value) {
|
|
1356
|
+
const nested = this.normalizeTextCandidateValue(entry, allowJsonStringify);
|
|
1357
|
+
if (nested) {
|
|
1358
|
+
collected.push(nested);
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
return collected.length ? collected.join('\n') : null;
|
|
1362
|
+
}
|
|
1363
|
+
if (typeof value === 'object') {
|
|
1364
|
+
const bag = value;
|
|
1365
|
+
const textField = bag.text;
|
|
1366
|
+
if (typeof textField === 'string' && textField.trim()) {
|
|
1367
|
+
return textField.trim();
|
|
1368
|
+
}
|
|
1369
|
+
const summaryField = bag.summary;
|
|
1370
|
+
if (typeof summaryField === 'string' && summaryField.trim()) {
|
|
1371
|
+
return summaryField.trim();
|
|
1372
|
+
}
|
|
1373
|
+
if ('content' in bag) {
|
|
1374
|
+
const nested = this.normalizeTextCandidateValue(bag.content, allowJsonStringify);
|
|
1375
|
+
if (nested) {
|
|
1376
|
+
return nested;
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
if (allowJsonStringify) {
|
|
1380
|
+
try {
|
|
1381
|
+
const serialized = JSON.stringify(value, null, 2);
|
|
1382
|
+
return serialized.trim() || null;
|
|
1383
|
+
}
|
|
1384
|
+
catch {
|
|
1385
|
+
return null;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
return null;
|
|
1390
|
+
}
|
|
988
1391
|
async initializeRouteErrorHub() {
|
|
989
1392
|
try {
|
|
990
1393
|
this.routeErrorHub = initializeRouteErrorHub({ errorHandlingCenter: this.errorHandling });
|