@jsonstudio/rcc 0.89.1205 → 0.89.1457
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 +53 -1412
- package/configsamples/config.json +426 -0
- package/configsamples/config.reference.json +58 -0
- package/configsamples/provider/crs/config.v1.json +46 -0
- package/configsamples/provider/glm/config.v1.json +81 -0
- package/configsamples/provider/glm-anthropic/config.v1.json +45 -0
- package/configsamples/provider/iflow/config.v1.json +74 -0
- package/configsamples/provider/kimi/config.v1.json +41 -0
- package/configsamples/provider/lmstudio/config.v1.json +101 -0
- package/configsamples/provider/mimo/config.v1.json +35 -0
- package/configsamples/provider/modelscope/config.v1.json +96 -0
- package/configsamples/provider/qwen/config.v1.json +38 -0
- package/configsamples/provider/tab/config.v1.json +50 -0
- package/configsamples/provider/tabglm/config.v1.json +49 -0
- package/dist/build-info.js +2 -2
- package/dist/cli/commands/code.js +12 -6
- package/dist/cli/commands/code.js.map +1 -1
- package/dist/cli/commands/config.d.ts +2 -1
- package/dist/cli/commands/config.js +77 -103
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/examples.js +6 -6
- package/dist/cli/commands/examples.js.map +1 -1
- package/dist/cli/commands/init.d.ts +28 -0
- package/dist/cli/commands/init.js +94 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/port.js +10 -2
- package/dist/cli/commands/port.js.map +1 -1
- package/dist/cli/commands/restart.js +5 -2
- package/dist/cli/commands/restart.js.map +1 -1
- package/dist/cli/commands/start.js +25 -22
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/status.js +1 -0
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/stop.js +1 -0
- package/dist/cli/commands/stop.js.map +1 -1
- package/dist/cli/config/bundled-docs.d.ts +20 -0
- package/dist/cli/config/bundled-docs.js +91 -0
- package/dist/cli/config/bundled-docs.js.map +1 -0
- package/dist/cli/config/init-config.d.ts +37 -0
- package/dist/cli/config/init-config.js +212 -0
- package/dist/cli/config/init-config.js.map +1 -0
- package/dist/cli/config/init-provider-catalog.d.ts +8 -0
- package/dist/cli/config/init-provider-catalog.js +187 -0
- package/dist/cli/config/init-provider-catalog.js.map +1 -0
- package/dist/cli/register/init-command.d.ts +3 -0
- package/dist/cli/register/init-command.js +5 -0
- package/dist/cli/register/init-command.js.map +1 -0
- package/dist/cli.js +28 -3
- package/dist/cli.js.map +1 -1
- package/dist/client/gemini/gemini-protocol-client.js +2 -1
- package/dist/client/gemini/gemini-protocol-client.js.map +1 -1
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js +40 -16
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -1
- package/dist/client/openai/chat-protocol-client.js +2 -1
- package/dist/client/openai/chat-protocol-client.js.map +1 -1
- package/dist/client/responses/responses-protocol-client.js +2 -1
- package/dist/client/responses/responses-protocol-client.js.map +1 -1
- package/dist/config/risk-control-config.d.ts +94 -0
- package/dist/config/risk-control-config.js +196 -0
- package/dist/config/risk-control-config.js.map +1 -0
- package/dist/constants/index.d.ts +6 -0
- package/dist/constants/index.js +13 -0
- package/dist/constants/index.js.map +1 -1
- package/dist/docs/daemon-admin-ui.html +2113 -190
- package/dist/error-handling/quiet-error-handling-center.js +46 -8
- package/dist/error-handling/quiet-error-handling-center.js.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/manager/modules/health/index.d.ts +1 -1
- package/dist/manager/modules/quota/antigravity-quota-manager.d.ts +70 -0
- package/dist/manager/modules/quota/antigravity-quota-manager.js +442 -0
- package/dist/manager/modules/quota/antigravity-quota-manager.js.map +1 -0
- package/dist/manager/modules/quota/index.d.ts +3 -127
- package/dist/manager/modules/quota/index.js +2 -1093
- package/dist/manager/modules/quota/index.js.map +1 -1
- package/dist/manager/modules/quota/provider-key-normalization.d.ts +3 -0
- package/dist/manager/modules/quota/provider-key-normalization.js +155 -0
- package/dist/manager/modules/quota/provider-key-normalization.js.map +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.cooldown.d.ts +9 -0
- package/dist/manager/modules/quota/provider-quota-daemon.cooldown.js +115 -0
- package/dist/manager/modules/quota/provider-quota-daemon.cooldown.js.map +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.d.ts +77 -0
- package/dist/manager/modules/quota/provider-quota-daemon.events.d.ts +12 -0
- package/dist/manager/modules/quota/provider-quota-daemon.events.js +239 -0
- package/dist/manager/modules/quota/provider-quota-daemon.events.js.map +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.js +404 -0
- package/dist/manager/modules/quota/provider-quota-daemon.js.map +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.d.ts +11 -0
- package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js +192 -0
- package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js.map +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.snapshot.d.ts +8 -0
- package/dist/manager/modules/quota/provider-quota-daemon.snapshot.js +96 -0
- package/dist/manager/modules/quota/provider-quota-daemon.snapshot.js.map +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.view.d.ts +19 -0
- package/dist/manager/modules/quota/provider-quota-daemon.view.js +37 -0
- package/dist/manager/modules/quota/provider-quota-daemon.view.js.map +1 -0
- package/dist/manager/modules/routing/index.d.ts +1 -0
- package/dist/manager/modules/routing/index.js +11 -25
- package/dist/manager/modules/routing/index.js.map +1 -1
- package/dist/manager/quota/provider-quota-center.d.ts +2 -0
- package/dist/manager/quota/provider-quota-center.js +80 -82
- package/dist/manager/quota/provider-quota-center.js.map +1 -1
- package/dist/modules/llmswitch/bridge.d.ts +16 -18
- package/dist/modules/llmswitch/bridge.js +293 -94
- package/dist/modules/llmswitch/bridge.js.map +1 -1
- package/dist/modules/llmswitch/core-loader.d.ts +4 -2
- package/dist/modules/llmswitch/core-loader.js +32 -20
- package/dist/modules/llmswitch/core-loader.js.map +1 -1
- package/dist/modules/pipeline/utils/colored-logger.js +3 -2
- package/dist/modules/pipeline/utils/colored-logger.js.map +1 -1
- package/dist/modules/pipeline/utils/debug-logger.js +1 -1
- package/dist/modules/pipeline/utils/debug-logger.js.map +1 -1
- package/dist/providers/auth/antigravity-userinfo-helper.d.ts +2 -1
- package/dist/providers/auth/antigravity-userinfo-helper.js +25 -4
- package/dist/providers/auth/antigravity-userinfo-helper.js.map +1 -1
- package/dist/providers/auth/iflow-cookie-auth.js +0 -2
- package/dist/providers/auth/iflow-cookie-auth.js.map +1 -1
- package/dist/providers/auth/oauth-lifecycle.js +2 -23
- package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
- package/dist/providers/auth/tokenfile-auth.d.ts +2 -0
- package/dist/providers/auth/tokenfile-auth.js +33 -1
- package/dist/providers/auth/tokenfile-auth.js.map +1 -1
- package/dist/providers/core/config/camoufox-launcher.d.ts +5 -0
- package/dist/providers/core/config/camoufox-launcher.js +40 -4
- package/dist/providers/core/config/camoufox-launcher.js.map +1 -1
- package/dist/providers/core/config/service-profiles.js +7 -18
- package/dist/providers/core/config/service-profiles.js.map +1 -1
- package/dist/providers/core/runtime/antigravity-quota-client.js +6 -3
- package/dist/providers/core/runtime/antigravity-quota-client.js.map +1 -1
- package/dist/providers/core/runtime/base-provider.d.ts +2 -7
- package/dist/providers/core/runtime/base-provider.js +84 -165
- package/dist/providers/core/runtime/base-provider.js.map +1 -1
- package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +7 -0
- package/dist/providers/core/runtime/gemini-cli-http-provider.js +368 -97
- package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
- package/dist/providers/core/runtime/http-request-executor.d.ts +3 -0
- package/dist/providers/core/runtime/http-request-executor.js +110 -38
- package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
- package/dist/providers/core/runtime/http-transport-provider.d.ts +17 -0
- package/dist/providers/core/runtime/http-transport-provider.js +165 -16
- package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
- package/dist/providers/core/runtime/provider-error-classifier.js +10 -0
- package/dist/providers/core/runtime/provider-error-classifier.js.map +1 -1
- package/dist/providers/core/runtime/provider-factory.js +7 -5
- package/dist/providers/core/runtime/provider-factory.js.map +1 -1
- package/dist/providers/core/runtime/provider-runtime-metadata.d.ts +6 -0
- package/dist/providers/core/runtime/provider-runtime-metadata.js.map +1 -1
- package/dist/providers/core/runtime/rate-limit-manager.d.ts +1 -12
- package/dist/providers/core/runtime/rate-limit-manager.js +4 -77
- package/dist/providers/core/runtime/rate-limit-manager.js.map +1 -1
- package/dist/providers/core/runtime/responses-provider.d.ts +1 -7
- package/dist/providers/core/runtime/responses-provider.js +12 -93
- package/dist/providers/core/runtime/responses-provider.js.map +1 -1
- package/dist/providers/core/strategies/oauth-auth-code-flow.js +12 -8
- package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
- package/dist/providers/core/utils/http-client.js +36 -46
- package/dist/providers/core/utils/http-client.js.map +1 -1
- package/dist/providers/core/utils/provider-error-logger.d.ts +1 -1
- package/dist/providers/core/utils/provider-error-reporter.d.ts +3 -1
- package/dist/providers/core/utils/provider-error-reporter.js +3 -0
- package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
- package/dist/providers/core/utils/snapshot-writer.js +1 -4
- package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
- package/dist/providers/mock/mock-provider-runtime.js +57 -27
- package/dist/providers/mock/mock-provider-runtime.js.map +1 -1
- package/dist/scripts/camoufox/launch-auth.mjs +193 -58
- package/dist/server/handlers/handler-utils.js +8 -3
- package/dist/server/handlers/handler-utils.js.map +1 -1
- package/dist/server/handlers/responses-handler.js +1 -1
- package/dist/server/handlers/responses-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/auth-handler.d.ts +2 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-handler.js +103 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-handler.js.map +1 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-session.d.ts +5 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-session.js +77 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-session.js.map +1 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-store.d.ts +18 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-store.js +89 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-store.js.map +1 -0
- package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js +1 -2
- package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.js +226 -24
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/quota-handler.js +47 -8
- package/dist/server/runtime/http-server/daemon-admin/quota-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/restart-handler.js +1 -1
- package/dist/server/runtime/http-server/daemon-admin/restart-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/stats-handler.js +1 -1
- package/dist/server/runtime/http-server/daemon-admin/stats-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/status-handler.js +68 -4
- package/dist/server/runtime/http-server/daemon-admin/status-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin-routes.d.ts +3 -4
- package/dist/server/runtime/http-server/daemon-admin-routes.js +9 -14
- package/dist/server/runtime/http-server/daemon-admin-routes.js.map +1 -1
- package/dist/server/runtime/http-server/executor-metadata.js +1 -1
- package/dist/server/runtime/http-server/executor-metadata.js.map +1 -1
- package/dist/server/runtime/http-server/executor-response.js +0 -16
- package/dist/server/runtime/http-server/executor-response.js.map +1 -1
- package/dist/server/runtime/http-server/hub-shadow-compare.js +110 -34
- package/dist/server/runtime/http-server/hub-shadow-compare.js.map +1 -1
- package/dist/server/runtime/http-server/index.d.ts +5 -3
- package/dist/server/runtime/http-server/index.js +281 -136
- package/dist/server/runtime/http-server/index.js.map +1 -1
- package/dist/server/runtime/http-server/middleware.js +19 -1
- package/dist/server/runtime/http-server/middleware.js.map +1 -1
- package/dist/server/runtime/http-server/request-executor.js +59 -24
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/server/runtime/http-server/routes.js +12 -3
- package/dist/server/runtime/http-server/routes.js.map +1 -1
- package/dist/server/runtime/http-server/session-dir.d.ts +2 -0
- package/dist/server/runtime/http-server/session-dir.js +59 -0
- package/dist/server/runtime/http-server/session-dir.js.map +1 -0
- package/dist/server/runtime/http-server/types.d.ts +0 -4
- package/dist/server/utils/utf8-chunk-buffer.js +6 -3
- package/dist/server/utils/utf8-chunk-buffer.js.map +1 -1
- package/dist/server/utils/warmup-storm-tracker.js +1 -1
- package/dist/server/utils/warmup-storm-tracker.js.map +1 -1
- package/dist/server-factory.d.ts +6 -28
- package/dist/server-factory.js +8 -93
- package/dist/server-factory.js.map +1 -1
- package/dist/token-daemon/index.js +2 -2
- package/dist/token-daemon/index.js.map +1 -1
- package/dist/token-daemon/provider-registry.js +0 -1
- package/dist/token-daemon/provider-registry.js.map +1 -1
- package/dist/token-daemon/server-utils.js +8 -9
- package/dist/token-daemon/server-utils.js.map +1 -1
- package/dist/token-daemon/token-utils.js +1 -1
- package/dist/token-daemon/token-utils.js.map +1 -1
- package/dist/tools/semantic-replay.js +2 -2
- package/dist/tools/semantic-replay.js.map +1 -1
- package/dist/tools/stats-request-events.d.ts +1 -1
- package/dist/tools/stats-usage.js +6 -3
- package/dist/tools/stats-usage.js.map +1 -1
- package/dist/utils/llms-engine-shadow.d.ts +19 -0
- package/dist/utils/llms-engine-shadow.js +209 -0
- package/dist/utils/llms-engine-shadow.js.map +1 -0
- package/dist/utils/runtime-versions.js +2 -1
- package/dist/utils/runtime-versions.js.map +1 -1
- package/dist/utils/strip-internal-keys.d.ts +12 -0
- package/dist/utils/strip-internal-keys.js +28 -0
- package/dist/utils/strip-internal-keys.js.map +1 -0
- package/docs/ARCHITECTURE.md +402 -0
- package/docs/CHAT_PROCESS_PROTOCOL_AND_PIPELINE.md +221 -0
- package/docs/CODEX_AND_CLAUDE_CODE.md +69 -0
- package/docs/CONFIG_ARCHITECTURE.md +517 -0
- package/docs/ERROR_HANDLING_AUDIT.md +0 -0
- package/docs/GCLI2API_PARITY_GAPS.md +98 -0
- package/docs/INSTALLATION_AND_QUICKSTART.md +74 -0
- package/docs/INSTRUCTION_MARKUP.md +89 -0
- package/docs/MODULE_ENHANCEMENT_SYSTEM.md +666 -0
- package/docs/PORTS.md +36 -0
- package/docs/PROVIDERS_BUILTIN.md +111 -0
- package/docs/PROVIDER_TYPES.md +55 -0
- package/docs/SERVERTOOL_CLOCK_DESIGN.md +233 -0
- package/docs/USAGE_HANDLING_ANALYSIS.md +335 -0
- package/docs/USER_CONFIG_PARSER_CHANGES.md +175 -0
- package/docs/V3_INBOUND_OUTBOUND_DESIGN.md +86 -0
- package/docs/VIRTUAL_ROUTER_PRIORITY_AND_HEALTH.md +125 -0
- package/docs/anthropic-request-golden-samples.md +50 -0
- package/docs/antigravity-gemini-format-cleanup.md +102 -0
- package/docs/antigravity-routing-contract.md +31 -0
- package/docs/ccr-alignment-enhancetool.md +105 -0
- package/docs/chat-glm-500-analysis.md +79 -0
- package/docs/chat-request-golden-samples.md +42 -0
- package/docs/chat-semantic-expansion-plan.md +84 -0
- package/docs/cli-command-inventory.md +76 -0
- package/docs/codex-samples-replay.md +50 -0
- package/docs/daemon-admin-api-design.md +350 -0
- package/docs/daemon-admin-module-structure.md +169 -0
- package/docs/daemon-admin-ui.html +3394 -0
- package/docs/debug-system-design.md +734 -0
- package/docs/debugging/gemini-sse-root-cause.md +52 -0
- package/docs/debugging/sse_encoding_failure_analysis.md +53 -0
- package/docs/dry-run/README.md +721 -0
- package/docs/error-handling-v2.md +92 -0
- package/docs/exec-command-guard-policy.example.v1.json +42 -0
- package/docs/fixes/gemini-protocol-mapping.md +57 -0
- package/docs/fixes/oauth-portal-timing-fix.md +202 -0
- package/docs/fixes/web-search-hop3-fix.md +265 -0
- package/docs/glm-api-reference.md +390 -0
- package/docs/glm-chat-completions.md +1779 -0
- package/docs/glm-history-inline-images.md +44 -0
- package/docs/golden-ci-library.md +66 -0
- package/docs/lmstudio-dry-run-summary.md +203 -0
- package/docs/lmstudio-tool-calling.md +214 -0
- package/docs/mapping-tables/anthropic-to-openai.json +290 -0
- package/docs/mapping-tables/iflow-to-openai.json +215 -0
- package/docs/mapping-tables/openai-passthrough.json +190 -0
- package/docs/mapping-tables/openai-to-iflow.json +227 -0
- package/docs/monitoring/Design.md +61 -0
- package/docs/multi-token-auth-guide.md +66 -0
- package/docs/oauth-authentication-guide.md +168 -0
- package/docs/oauth-iflow-implementation.md +153 -0
- package/docs/pipeline-routing-report.md +209 -0
- package/docs/plans/manager-daemon/PLAN.md +86 -0
- package/docs/plans/provider-config-v2-plan.md +176 -0
- package/docs/plans/provider-runtime-manager-plan.md +209 -0
- package/docs/plans/transparent-429-failover.md +89 -0
- package/docs/plans/unified-hub-framework-v1.md +245 -0
- package/docs/provider-config-v2-ui-design.md +181 -0
- package/docs/provider-quota-design.md +129 -0
- package/docs/providers/gemini-provider.md +62 -0
- package/docs/providers/lmstudio-v2-migration-report.md +102 -0
- package/docs/providers/provider-composite-design.md +142 -0
- package/docs/providers/provider-composite-testing.md +98 -0
- package/docs/providers/provider-type-only-migration.md +111 -0
- package/docs/rccx-wasm-migration.md +74 -0
- package/docs/refactoring/architecture-comparison-diagram.md +140 -0
- package/docs/refactoring/compatibility-v2-architecture-design.md +738 -0
- package/docs/refactoring/workflow-compatibility-refactoring-design.md +361 -0
- package/docs/reports/routing-classification-report.json +24 -0
- package/docs/reports/routing-classification-report.md +18 -0
- package/docs/reports/thinking-keywords-report.json +19 -0
- package/docs/responses/README.md +156 -0
- package/docs/responses-generic-provider.md +86 -0
- package/docs/responses-passthrough-provider-design.md +202 -0
- package/docs/routing-awrr-health-weighted-round-robin.md +179 -0
- package/docs/routing-instructions.md +393 -0
- package/docs/servertool-framework.md +65 -0
- package/docs/stop-message-auto.md +225 -0
- package/docs/streaming-flow.html +30 -0
- package/docs/streaming-flow.md +182 -0
- package/docs/token-daemon-preview.html +490 -0
- package/docs/token-refresh-daemon-plan.md +269 -0
- package/docs/transformation-tables/Gemini-FinishReason/345/256/214/346/225/264/350/275/254/346/215/242/350/241/250.json +233 -0
- package/docs/transformation-tables/README.md +225 -0
- package/docs/transformation-tables/claude-code-router-anthropic-to-gemini.json +283 -0
- package/docs/transformation-tables/claude-code-router-anthropic-to-openai.json +208 -0
- package/docs/transformation-tables/claude-code-router-openai-to-anthropic.json +261 -0
- package/docs/transformation-tables/claude-code-router-openai-to-gemini.json +208 -0
- package/docs/transformation-tables/claude-code-router-openai-to-lmstudio.json +182 -0
- package/docs/transformation-tables/claude-code-router-openai-to-ollama.json +250 -0
- package/docs/transformation-tables/claude-code-router-openai-to-textgenwebui.json +295 -0
- package/docs/transformation-tables/claude-code-router-provider-conversions.json +193 -0
- package/docs/transformation-tables//345/256/214/346/225/264/347/232/204/345/267/245/345/205/267/346/211/247/350/241/214/346/265/201/347/250/213/350/275/254/346/215/242/350/241/250.json +299 -0
- package/docs/transformation-tables//345/257/271/350/257/235/345/216/206/345/217/262/347/273/264/346/212/244/345/210/206/346/236/220.md +134 -0
- package/docs/transformation-tables//345/267/245/345/205/267/350/260/203/347/224/250/346/250/241/345/274/217/345/210/206/346/236/220.md +158 -0
- package/docs/transformation-tables//347/212/266/346/200/201/347/256/241/347/220/206/351/234/200/346/261/202/345/210/206/346/236/220.md +175 -0
- package/docs/transformation-tables//351/235/231/346/200/201/350/241/250vs/345/212/250/346/200/201/345/210/206/346/236/220.md +189 -0
- package/docs/transformation-tables//351/235/231/346/200/201/350/241/250/345/207/206/347/241/256/346/200/247/350/257/204/344/274/260.md +179 -0
- package/docs/transformation-tables//351/235/236/346/265/201/345/274/217/345/234/272/346/231/257/345/210/206/346/236/220.md +189 -0
- package/docs/v2-architecture/IMPLEMENTATION-ROADMAP.md +367 -0
- package/docs/v2-architecture/OPTIMIZED-DESIGN.md +827 -0
- package/docs/v2-architecture/PRERUN-CONNECTION-DESIGN.md +716 -0
- package/docs/v2-architecture/README.md +549 -0
- package/docs/verification/modelscope-verify.md +59 -0
- package/docs/verified-configs/README.md +60 -0
- package/docs/verified-configs/v0.45.0/README.md +244 -0
- package/docs/verified-configs/v0.45.0/lmstudio-5521-gpt-oss-20b-mlx.json +135 -0
- package/docs/verified-configs/v0.45.0/merged-config.5521.json +1205 -0
- package/docs/verified-configs/v0.45.0/merged-config.qwen-5522.json +1559 -0
- package/docs/verified-configs/v0.45.0/qwen-5522-qwen3-coder-plus-final.json +221 -0
- package/docs/verified-configs/v0.45.0/qwen-5522-qwen3-coder-plus-fixed.json +242 -0
- package/docs/verified-configs/v0.45.0/qwen-5522-qwen3-coder-plus.json +242 -0
- package/docs/web-search-service-design.md +322 -0
- package/package.json +26 -15
- package/scripts/build-core.mjs +3 -1
- package/scripts/camoufox/launch-auth.mjs +193 -58
- package/scripts/ci/repo-sanity.mjs +138 -0
- package/scripts/mock-provider/run-regressions.mjs +157 -1
- package/scripts/monitor-diff.mjs +126 -0
- package/scripts/pack-mode.mjs +19 -1
- package/scripts/pack-rcc.mjs +63 -0
- package/scripts/run-bg.sh +0 -14
- package/scripts/tests/ci-jest.mjs +119 -0
- package/scripts/tools-dev/responses-debug-client/README.md +23 -0
- package/scripts/tools-dev/responses-debug-client/payloads/poem.json +13 -0
- package/scripts/tools-dev/responses-debug-client/payloads/sample-no-tools.json +98 -0
- package/scripts/tools-dev/responses-debug-client/payloads/text.json +13 -0
- package/scripts/tools-dev/responses-debug-client/payloads/tool.json +27 -0
- package/scripts/tools-dev/responses-debug-client/run.mjs +65 -0
- package/scripts/tools-dev/responses-debug-client/src/index.ts +281 -0
- package/scripts/tools-dev/run-llmswitch-chat.mjs +53 -0
- package/scripts/tools-dev/server-tools-dev/run-web-fetch.mjs +65 -0
- package/scripts/unified-hub-shadow-compare.mjs +33 -13
- package/scripts/vendor-core.mjs +13 -3
- package/scripts/verify-e2e-toolcall.mjs +115 -26
- package/dist/modules/llmswitch/pipeline-registry.d.ts +0 -57
- package/dist/modules/llmswitch/pipeline-registry.js +0 -229
- package/dist/modules/llmswitch/pipeline-registry.js.map +0 -1
- package/dist/server/RouteCodexServer.d.ts +0 -13
- package/dist/server/RouteCodexServer.js +0 -25
- package/dist/server/RouteCodexServer.js.map +0 -1
- package/dist/v2/conversion/hub/snapshot-recorder.d.ts +0 -12
- package/dist/v2/conversion/hub/snapshot-recorder.js +0 -22
- package/dist/v2/conversion/hub/snapshot-recorder.js.map +0 -1
- package/scripts/test-fc-responses.mjs +0 -66
- package/scripts/test-guidance.mjs +0 -100
- package/scripts/test-iflow-web-search.mjs +0 -141
- package/scripts/test-iflow.mjs +0 -379
- package/scripts/test-tool-exec.mjs +0 -26
|
@@ -12,7 +12,6 @@ import { ErrorHandlingCenter } from 'rcc-errorhandling';
|
|
|
12
12
|
import { ProviderFactory } from '../../../providers/core/runtime/provider-factory.js';
|
|
13
13
|
import { PipelineDebugLogger as PipelineDebugLoggerImpl } from '../../../modules/pipeline/utils/debug-logger.js';
|
|
14
14
|
import { attachProviderRuntimeMetadata } from '../../../providers/core/runtime/provider-runtime-metadata.js';
|
|
15
|
-
import { extractAnthropicToolAliasMap } from './anthropic-tool-alias.js';
|
|
16
15
|
import { AuthFileResolver } from '../../../config/auth-file-resolver.js';
|
|
17
16
|
import { buildProviderProfiles } from '../../../providers/profile/provider-profile-loader.js';
|
|
18
17
|
import { isStageLoggingEnabled, logPipelineStage } from '../../utils/stage-logger.js';
|
|
@@ -21,7 +20,7 @@ import { registerHttpRoutes, registerOAuthPortalRoute } from './routes.js';
|
|
|
21
20
|
import { mapProviderProtocol, normalizeProviderType, resolveProviderIdentity, asRecord } from './provider-utils.js';
|
|
22
21
|
import { resolveRepoRoot } from './llmswitch-loader.js';
|
|
23
22
|
import { enhanceProviderRequestId } from '../../utils/request-id-manager.js';
|
|
24
|
-
import { convertProviderResponse as bridgeConvertProviderResponse, createSnapshotRecorder as bridgeCreateSnapshotRecorder, rebindResponsesConversationRequestId, bootstrapVirtualRouterConfig, getHubPipelineCtor } from '../../../modules/llmswitch/bridge.js';
|
|
23
|
+
import { convertProviderResponse as bridgeConvertProviderResponse, createSnapshotRecorder as bridgeCreateSnapshotRecorder, rebindResponsesConversationRequestId, extractSessionIdentifiersFromMetadata, bootstrapVirtualRouterConfig, getHubPipelineCtor } from '../../../modules/llmswitch/bridge.js';
|
|
25
24
|
import { initializeRouteErrorHub, reportRouteError } from '../../../error-handling/route-error-hub.js';
|
|
26
25
|
import { writeClientSnapshot } from '../../../providers/core/utils/snapshot-writer.js';
|
|
27
26
|
import { createServerColoredLogger } from './colored-logger.js';
|
|
@@ -32,11 +31,45 @@ import { ManagerDaemon } from '../../../manager/index.js';
|
|
|
32
31
|
import { HealthManagerModule } from '../../../manager/modules/health/index.js';
|
|
33
32
|
import { RoutingStateManagerModule } from '../../../manager/modules/routing/index.js';
|
|
34
33
|
import { TokenManagerModule } from '../../../manager/modules/token/index.js';
|
|
34
|
+
import { ensureServerScopedSessionDir } from './session-dir.js';
|
|
35
35
|
import { StatsManager } from './stats-manager.js';
|
|
36
36
|
import { loadRouteCodexConfig } from '../../../config/routecodex-config-loader.js';
|
|
37
37
|
import { buildInfo } from '../../../build-info.js';
|
|
38
38
|
import { recordHubShadowCompareDiff, resolveHubShadowCompareConfig, shouldRunHubShadowCompare } from './hub-shadow-compare.js';
|
|
39
|
+
import { recordLlmsEngineShadowDiff, isLlmsEngineShadowEnabledForSubpath, resolveLlmsEngineShadowConfig, shouldRunLlmsEngineShadowForSubpath } from '../../../utils/llms-engine-shadow.js';
|
|
39
40
|
import { resolveLlmswitchCoreVersion } from '../../../utils/runtime-versions.js';
|
|
41
|
+
const DEFAULT_MAX_PROVIDER_ATTEMPTS = 6;
|
|
42
|
+
const DEFAULT_ANTIGRAVITY_MAX_PROVIDER_ATTEMPTS = 20;
|
|
43
|
+
function resolveMaxProviderAttempts() {
|
|
44
|
+
const raw = String(process.env.ROUTECODEX_MAX_PROVIDER_ATTEMPTS || process.env.RCC_MAX_PROVIDER_ATTEMPTS || '')
|
|
45
|
+
.trim()
|
|
46
|
+
.toLowerCase();
|
|
47
|
+
const parsed = raw ? Number.parseInt(raw, 10) : NaN;
|
|
48
|
+
const candidate = Number.isFinite(parsed) ? parsed : DEFAULT_MAX_PROVIDER_ATTEMPTS;
|
|
49
|
+
return Math.max(1, Math.min(20, candidate));
|
|
50
|
+
}
|
|
51
|
+
function resolveAntigravityMaxProviderAttempts() {
|
|
52
|
+
const raw = String(process.env.ROUTECODEX_ANTIGRAVITY_MAX_PROVIDER_ATTEMPTS || process.env.RCC_ANTIGRAVITY_MAX_PROVIDER_ATTEMPTS || '')
|
|
53
|
+
.trim()
|
|
54
|
+
.toLowerCase();
|
|
55
|
+
const parsed = raw ? Number.parseInt(raw, 10) : NaN;
|
|
56
|
+
const candidate = Number.isFinite(parsed) ? parsed : DEFAULT_ANTIGRAVITY_MAX_PROVIDER_ATTEMPTS;
|
|
57
|
+
return Math.max(1, Math.min(60, candidate));
|
|
58
|
+
}
|
|
59
|
+
function isAntigravityProviderKey(providerKey) {
|
|
60
|
+
return typeof providerKey === 'string' && providerKey.startsWith('antigravity.');
|
|
61
|
+
}
|
|
62
|
+
function extractStatusCodeFromError(err) {
|
|
63
|
+
if (!err || typeof err !== 'object')
|
|
64
|
+
return undefined;
|
|
65
|
+
const direct = err.statusCode;
|
|
66
|
+
if (typeof direct === 'number')
|
|
67
|
+
return direct;
|
|
68
|
+
const nested = err.status;
|
|
69
|
+
if (typeof nested === 'number')
|
|
70
|
+
return nested;
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
40
73
|
/**
|
|
41
74
|
* RouteCodex Server V2
|
|
42
75
|
*
|
|
@@ -52,7 +85,6 @@ export class RouteCodexHttpServer {
|
|
|
52
85
|
_isRunning = false;
|
|
53
86
|
// Runtime state
|
|
54
87
|
hubPipeline = null;
|
|
55
|
-
hubShadowComparePipeline = null;
|
|
56
88
|
providerHandles = new Map();
|
|
57
89
|
providerKeyToRuntimeKey = new Map();
|
|
58
90
|
pipelineLogger = createNoopPipelineLogger();
|
|
@@ -71,17 +103,18 @@ export class RouteCodexHttpServer {
|
|
|
71
103
|
stats = new StatsManager();
|
|
72
104
|
restartChain = Promise.resolve();
|
|
73
105
|
hubShadowCompareConfig = resolveHubShadowCompareConfig();
|
|
106
|
+
llmsEngineShadowConfig = resolveLlmsEngineShadowConfig();
|
|
74
107
|
hubPolicyMode = null;
|
|
108
|
+
hubPipelineEngineShadow = null;
|
|
109
|
+
hubPipelineConfigForShadow = null;
|
|
75
110
|
constructor(config) {
|
|
76
111
|
this.config = config;
|
|
77
112
|
this.app = express();
|
|
78
113
|
this.errorHandling = new QuietErrorHandlingCenter();
|
|
79
114
|
this.stageLoggingEnabled = isStageLoggingEnabled();
|
|
80
115
|
this.repoRoot = resolveRepoRoot(import.meta.url);
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
console.warn('[RouteCodexHttpServer] Super pipeline has been removed; falling back to Hub pipeline.');
|
|
84
|
-
}
|
|
116
|
+
// Ensure session-scoped routing state does not leak across server instances.
|
|
117
|
+
ensureServerScopedSessionDir(`${this.config.server.host}:${this.config.server.port}`);
|
|
85
118
|
try {
|
|
86
119
|
this.pipelineLogger = new PipelineDebugLoggerImpl({ colored: this.coloredLogger }, { enableConsoleLogging: true });
|
|
87
120
|
}
|
|
@@ -117,20 +150,11 @@ export class RouteCodexHttpServer {
|
|
|
117
150
|
/**
|
|
118
151
|
* Register Daemon Admin UI route.
|
|
119
152
|
* Serves docs/daemon-admin-ui.html as a static page.
|
|
120
|
-
* -
|
|
121
|
-
* - If `httpserver.apikey` is configured: allow remote UI access (API calls still require apikey).
|
|
153
|
+
* Note: daemon-admin UI/API now uses password login (stored at ~/.routecodex/login) instead of httpserver.apikey.
|
|
122
154
|
*/
|
|
123
155
|
registerDaemonAdminUiRoute() {
|
|
124
156
|
this.app.get('/daemon/admin', async (req, res) => {
|
|
125
157
|
try {
|
|
126
|
-
const ip = req.socket?.remoteAddress || '';
|
|
127
|
-
const isLocal = ip === '127.0.0.1' || ip === '::1' || ip === '::ffff:127.0.0.1';
|
|
128
|
-
const expectedKey = typeof this.config?.server?.apikey === 'string' ? this.config.server.apikey.trim() : '';
|
|
129
|
-
const hasConfiguredKey = Boolean(expectedKey);
|
|
130
|
-
if (!isLocal && !hasConfiguredKey) {
|
|
131
|
-
res.status(403).json({ error: { message: 'forbidden', code: 'forbidden' } });
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
158
|
const fs = await import('node:fs/promises');
|
|
135
159
|
let html = '';
|
|
136
160
|
try {
|
|
@@ -359,6 +383,46 @@ export class RouteCodexHttpServer {
|
|
|
359
383
|
this.hubPipelineCtor = ctorFactory;
|
|
360
384
|
return this.hubPipelineCtor;
|
|
361
385
|
}
|
|
386
|
+
async ensureHubPipelineEngineShadow() {
|
|
387
|
+
if (this.hubPipelineEngineShadow) {
|
|
388
|
+
return this.hubPipelineEngineShadow;
|
|
389
|
+
}
|
|
390
|
+
if (!this.hubPipelineConfigForShadow) {
|
|
391
|
+
throw new Error('Hub pipeline shadow config is not initialized');
|
|
392
|
+
}
|
|
393
|
+
const baseConfig = this.hubPipelineConfigForShadow;
|
|
394
|
+
const shadowConfig = { ...baseConfig };
|
|
395
|
+
// Avoid double side effects when shadow-running the pipeline: keep reads, drop writes.
|
|
396
|
+
const routingStateStore = baseConfig.routingStateStore;
|
|
397
|
+
if (routingStateStore && typeof routingStateStore.loadSync === 'function') {
|
|
398
|
+
shadowConfig.routingStateStore = {
|
|
399
|
+
loadSync: routingStateStore.loadSync.bind(routingStateStore),
|
|
400
|
+
saveAsync: () => { }
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
const healthStore = baseConfig.healthStore;
|
|
404
|
+
if (healthStore && typeof healthStore.loadInitialSnapshot === 'function') {
|
|
405
|
+
shadowConfig.healthStore = {
|
|
406
|
+
loadInitialSnapshot: healthStore.loadInitialSnapshot.bind(healthStore)
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
const quotaViewReadOnly = baseConfig.quotaViewReadOnly;
|
|
410
|
+
if (typeof quotaViewReadOnly === 'function') {
|
|
411
|
+
shadowConfig.quotaView = quotaViewReadOnly;
|
|
412
|
+
}
|
|
413
|
+
const bridge = (await import('../../../modules/llmswitch/bridge.js'));
|
|
414
|
+
const getCtor = bridge.getHubPipelineCtorForImpl;
|
|
415
|
+
if (typeof getCtor !== 'function') {
|
|
416
|
+
throw new Error('llmswitch bridge does not expose getHubPipelineCtorForImpl');
|
|
417
|
+
}
|
|
418
|
+
const ctorFactory = await getCtor('engine');
|
|
419
|
+
const hubCtor = ctorFactory;
|
|
420
|
+
if (!('virtualRouter' in shadowConfig)) {
|
|
421
|
+
throw new Error('HubPipeline shadow config missing virtualRouter');
|
|
422
|
+
}
|
|
423
|
+
this.hubPipelineEngineShadow = new hubCtor(shadowConfig);
|
|
424
|
+
return this.hubPipelineEngineShadow;
|
|
425
|
+
}
|
|
362
426
|
isPipelineReady() {
|
|
363
427
|
return Boolean(this.hubPipeline);
|
|
364
428
|
}
|
|
@@ -671,6 +735,40 @@ export class RouteCodexHttpServer {
|
|
|
671
735
|
...(Number.isFinite(sampleRate) ? { sampleRate } : {})
|
|
672
736
|
};
|
|
673
737
|
}
|
|
738
|
+
// Unified Hub Framework V1: tool surface rollout toggle (enforce by default in dev).
|
|
739
|
+
// - Disable via env: ROUTECODEX_HUB_TOOL_SURFACE_MODE=off
|
|
740
|
+
// - Observe via env: ROUTECODEX_HUB_TOOL_SURFACE_MODE=observe
|
|
741
|
+
// - Shadow (diff-only, no rewrites) via env: ROUTECODEX_HUB_TOOL_SURFACE_MODE=shadow
|
|
742
|
+
// - Enforce (rewrite outbound payload) via env: ROUTECODEX_HUB_TOOL_SURFACE_MODE=enforce
|
|
743
|
+
const toolSurfaceModeRaw = String(process.env.ROUTECODEX_HUB_TOOL_SURFACE_MODE || '').trim().toLowerCase();
|
|
744
|
+
const toolSurfaceMode = toolSurfaceModeRaw === 'off' || toolSurfaceModeRaw === '0' || toolSurfaceModeRaw === 'false'
|
|
745
|
+
? null
|
|
746
|
+
: toolSurfaceModeRaw === 'observe' || toolSurfaceModeRaw === 'shadow' || toolSurfaceModeRaw === 'enforce'
|
|
747
|
+
? toolSurfaceModeRaw
|
|
748
|
+
: buildInfo.mode === 'dev'
|
|
749
|
+
? 'enforce'
|
|
750
|
+
: null;
|
|
751
|
+
if (toolSurfaceMode) {
|
|
752
|
+
const sampleRateRaw = String(process.env.ROUTECODEX_HUB_TOOL_SURFACE_SAMPLE_RATE || '').trim();
|
|
753
|
+
const sampleRate = sampleRateRaw ? Number(sampleRateRaw) : undefined;
|
|
754
|
+
hubConfig.toolSurface = {
|
|
755
|
+
mode: toolSurfaceMode,
|
|
756
|
+
...(Number.isFinite(sampleRate) ? { sampleRate } : {})
|
|
757
|
+
};
|
|
758
|
+
// Also export the resolved mode to env so llmswitch-core response conversion
|
|
759
|
+
// (convertProviderResponse) can observe tool surface mismatches consistently.
|
|
760
|
+
if (!process.env.ROUTECODEX_HUB_TOOL_SURFACE_MODE) {
|
|
761
|
+
process.env.ROUTECODEX_HUB_TOOL_SURFACE_MODE = toolSurfaceMode;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
// Unified Hub Framework V1: followup (servertool) shadow compare toggle.
|
|
765
|
+
// Implemented in llmswitch-core servertool engine; controlled by env for progressive rollout.
|
|
766
|
+
// Default: shadow in dev builds; off in release builds.
|
|
767
|
+
if (!process.env.ROUTECODEX_HUB_FOLLOWUP_MODE) {
|
|
768
|
+
if (buildInfo.mode === 'dev') {
|
|
769
|
+
process.env.ROUTECODEX_HUB_FOLLOWUP_MODE = 'shadow';
|
|
770
|
+
}
|
|
771
|
+
}
|
|
674
772
|
const healthModule = this.managerDaemon?.getModule('health');
|
|
675
773
|
const healthStore = healthModule?.getHealthStore();
|
|
676
774
|
if (healthStore) {
|
|
@@ -684,6 +782,9 @@ export class RouteCodexHttpServer {
|
|
|
684
782
|
const quotaModule = this.managerDaemon?.getModule('provider-quota');
|
|
685
783
|
if (this.isQuotaRoutingEnabled() && quotaModule && typeof quotaModule.getQuotaView === 'function') {
|
|
686
784
|
hubConfig.quotaView = quotaModule.getQuotaView();
|
|
785
|
+
if (typeof quotaModule.getQuotaViewReadOnly === 'function') {
|
|
786
|
+
hubConfig.quotaViewReadOnly = quotaModule.getQuotaViewReadOnly();
|
|
787
|
+
}
|
|
687
788
|
}
|
|
688
789
|
if (!this.hubPipeline) {
|
|
689
790
|
this.hubPipeline = new hubCtor(hubConfig);
|
|
@@ -702,37 +803,9 @@ export class RouteCodexHttpServer {
|
|
|
702
803
|
}
|
|
703
804
|
this.hubPipeline.updateVirtualRouterConfig(bootstrapArtifacts.config);
|
|
704
805
|
}
|
|
705
|
-
//
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
if (!this.hubShadowComparePipeline) {
|
|
709
|
-
this.hubShadowComparePipeline = new hubCtor(hubConfig);
|
|
710
|
-
}
|
|
711
|
-
else {
|
|
712
|
-
const existingShadow = this.hubShadowComparePipeline;
|
|
713
|
-
try {
|
|
714
|
-
existingShadow.updateRuntimeDeps?.({
|
|
715
|
-
...(healthStore ? { healthStore } : {}),
|
|
716
|
-
...(routingStateStore ? { routingStateStore } : {}),
|
|
717
|
-
...('quotaView' in hubConfig ? { quotaView: hubConfig.quotaView } : {})
|
|
718
|
-
});
|
|
719
|
-
}
|
|
720
|
-
catch {
|
|
721
|
-
// best-effort: runtime deps updates must never block reload
|
|
722
|
-
}
|
|
723
|
-
this.hubShadowComparePipeline.updateVirtualRouterConfig(bootstrapArtifacts.config);
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
else if (this.hubShadowComparePipeline) {
|
|
727
|
-
try {
|
|
728
|
-
const shadow = this.hubShadowComparePipeline;
|
|
729
|
-
shadow.dispose?.();
|
|
730
|
-
}
|
|
731
|
-
catch {
|
|
732
|
-
// ignore dispose failures
|
|
733
|
-
}
|
|
734
|
-
this.hubShadowComparePipeline = null;
|
|
735
|
-
}
|
|
806
|
+
// llms-engine shadow: capture the latest hub config and reset shadow pipeline to avoid stale deps.
|
|
807
|
+
this.hubPipelineConfigForShadow = hubConfig;
|
|
808
|
+
this.hubPipelineEngineShadow = null;
|
|
736
809
|
await this.initializeProviderRuntimes(bootstrapArtifacts);
|
|
737
810
|
}
|
|
738
811
|
buildHandlerContext() {
|
|
@@ -962,11 +1035,12 @@ export class RouteCodexHttpServer {
|
|
|
962
1035
|
}
|
|
963
1036
|
const pipelineLabel = 'hub';
|
|
964
1037
|
const iterationMetadata = initialMetadata;
|
|
965
|
-
|
|
966
|
-
// 单次 HTTP
|
|
1038
|
+
// _followupTriggered = false;
|
|
1039
|
+
// 单次 HTTP 请求内允许多次 failover(不在 Provider 层做重试):
|
|
967
1040
|
// - 让 VirtualRouter 根据 excludedProviderKeys 跳过失败目标
|
|
968
1041
|
// - 避免客户端“一次就断”导致对话破裂(尤其是 429 / prompt too long 等可恢复错误)
|
|
969
|
-
|
|
1042
|
+
// - 通过 env 允许按部署/客户端调整:ROUTECODEX_MAX_PROVIDER_ATTEMPTS / RCC_MAX_PROVIDER_ATTEMPTS
|
|
1043
|
+
let maxAttempts = resolveMaxProviderAttempts();
|
|
970
1044
|
let attempt = 0;
|
|
971
1045
|
let firstError = null;
|
|
972
1046
|
const originalBodySnapshot = this.cloneRequestPayload(input.body);
|
|
@@ -1039,9 +1113,14 @@ export class RouteCodexHttpServer {
|
|
|
1039
1113
|
providerId: providerIdToken,
|
|
1040
1114
|
model: rawModel
|
|
1041
1115
|
});
|
|
1042
|
-
|
|
1116
|
+
// /v1/responses tool loop depends on a stable requestId mapping between:
|
|
1117
|
+
// - inbound conversion capture (uses the initial requestId), and
|
|
1118
|
+
// - outbound response record (may run after requestId enhancement).
|
|
1119
|
+
// Enhancement happens for all providers, so rebind must be keyed off the client endpoint,
|
|
1120
|
+
// not the providerProtocol (which can be gemini-chat/anthropic-messages/etc.).
|
|
1121
|
+
if (String(input.entryEndpoint || '').startsWith('/v1/responses')) {
|
|
1043
1122
|
try {
|
|
1044
|
-
await rebindResponsesConversationRequestId(
|
|
1123
|
+
await rebindResponsesConversationRequestId(providerRequestId, enhancedRequestId);
|
|
1045
1124
|
}
|
|
1046
1125
|
catch {
|
|
1047
1126
|
/* ignore rebind failures */
|
|
@@ -1102,12 +1181,22 @@ export class RouteCodexHttpServer {
|
|
|
1102
1181
|
});
|
|
1103
1182
|
const wantsStreamBase = Boolean(input.metadata?.inboundStream ?? input.metadata?.stream);
|
|
1104
1183
|
const normalized = this.normalizeProviderResponse(providerResponse);
|
|
1184
|
+
const pipelineResultAny = pipelineResult;
|
|
1105
1185
|
const converted = await this.convertProviderResponseIfNeeded({
|
|
1106
1186
|
entryEndpoint: input.entryEndpoint,
|
|
1107
1187
|
providerType: handle.providerType,
|
|
1108
1188
|
requestId: input.requestId,
|
|
1109
1189
|
wantsStream: wantsStreamBase,
|
|
1110
1190
|
originalRequest: originalRequestSnapshot,
|
|
1191
|
+
requestSemantics: (pipelineResultAny?.processedRequest &&
|
|
1192
|
+
pipelineResultAny.processedRequest.semantics &&
|
|
1193
|
+
typeof pipelineResultAny.processedRequest.semantics === 'object')
|
|
1194
|
+
? pipelineResultAny.processedRequest.semantics
|
|
1195
|
+
: (pipelineResultAny?.standardizedRequest &&
|
|
1196
|
+
pipelineResultAny.standardizedRequest.semantics &&
|
|
1197
|
+
typeof pipelineResultAny.standardizedRequest.semantics === 'object')
|
|
1198
|
+
? pipelineResultAny.standardizedRequest.semantics
|
|
1199
|
+
: undefined,
|
|
1111
1200
|
processMode: pipelineResult.processMode,
|
|
1112
1201
|
response: normalized,
|
|
1113
1202
|
pipelineMetadata: mergedMetadata
|
|
@@ -1140,9 +1229,13 @@ export class RouteCodexHttpServer {
|
|
|
1140
1229
|
const sessionId = typeof mergedMetadata.sessionId === "string" && mergedMetadata.sessionId.trim()
|
|
1141
1230
|
? mergedMetadata.sessionId.trim()
|
|
1142
1231
|
: undefined;
|
|
1143
|
-
|
|
1232
|
+
let conversationId = typeof mergedMetadata.conversationId === "string" && mergedMetadata.conversationId.trim()
|
|
1144
1233
|
? mergedMetadata.conversationId.trim()
|
|
1145
1234
|
: undefined;
|
|
1235
|
+
// 对称补齐:如果只有 session_id,则回传 conversation_id=session_id
|
|
1236
|
+
if (!conversationId && sessionId) {
|
|
1237
|
+
conversationId = sessionId;
|
|
1238
|
+
}
|
|
1146
1239
|
if (sessionId || conversationId) {
|
|
1147
1240
|
if (!converted.headers) {
|
|
1148
1241
|
converted.headers = {};
|
|
@@ -1165,6 +1258,9 @@ export class RouteCodexHttpServer {
|
|
|
1165
1258
|
model: providerModel,
|
|
1166
1259
|
providerLabel
|
|
1167
1260
|
});
|
|
1261
|
+
if (isAntigravityProviderKey(target.providerKey) && extractStatusCodeFromError(error) === 429) {
|
|
1262
|
+
maxAttempts = Math.max(maxAttempts, resolveAntigravityMaxProviderAttempts());
|
|
1263
|
+
}
|
|
1168
1264
|
const quotaModule = this.managerDaemon?.getModule('provider-quota');
|
|
1169
1265
|
if (this.isQuotaRoutingEnabled() && quotaModule) {
|
|
1170
1266
|
try {
|
|
@@ -1205,11 +1301,18 @@ export class RouteCodexHttpServer {
|
|
|
1205
1301
|
throw new Error('Hub pipeline runtime is not initialized');
|
|
1206
1302
|
}
|
|
1207
1303
|
const payload = asRecord(input.body);
|
|
1304
|
+
const isInternalFollowup = asRecord(metadata.__rt)?.serverToolFollowup === true;
|
|
1305
|
+
const wantsShadowCompare = !isInternalFollowup && shouldRunHubShadowCompare(this.hubShadowCompareConfig);
|
|
1208
1306
|
const pipelineInput = {
|
|
1209
1307
|
...input,
|
|
1308
|
+
id: input.requestId,
|
|
1309
|
+
endpoint: input.entryEndpoint,
|
|
1210
1310
|
metadata: {
|
|
1211
1311
|
...metadata,
|
|
1212
|
-
logger: this.coloredLogger
|
|
1312
|
+
logger: this.coloredLogger,
|
|
1313
|
+
...(wantsShadowCompare
|
|
1314
|
+
? { __hubShadowCompare: { baselineMode: this.hubShadowCompareConfig.baselineMode } }
|
|
1315
|
+
: {})
|
|
1213
1316
|
},
|
|
1214
1317
|
payload
|
|
1215
1318
|
};
|
|
@@ -1225,13 +1328,23 @@ export class RouteCodexHttpServer {
|
|
|
1225
1328
|
const derivedRequestId = typeof resultRecord.requestId === 'string'
|
|
1226
1329
|
? resultRecord.requestId
|
|
1227
1330
|
: input.requestId;
|
|
1331
|
+
const llmsEngineShadowEnabled = !isInternalFollowup &&
|
|
1332
|
+
isLlmsEngineShadowEnabledForSubpath(this.llmsEngineShadowConfig, 'conversion/hub/pipeline');
|
|
1333
|
+
if (llmsEngineShadowEnabled) {
|
|
1334
|
+
// Fail fast: if shadow is enabled for this module, engine core must be available.
|
|
1335
|
+
await this.ensureHubPipelineEngineShadow();
|
|
1336
|
+
}
|
|
1337
|
+
const wantsLlmsEngineShadow = llmsEngineShadowEnabled &&
|
|
1338
|
+
shouldRunLlmsEngineShadowForSubpath(this.llmsEngineShadowConfig, 'conversion/hub/pipeline');
|
|
1228
1339
|
// Unified Hub Framework V1: runtime black-box shadow compare (baseline policy vs current policy).
|
|
1229
|
-
// - baseline
|
|
1340
|
+
// - baseline payload is computed in the SAME hub pipeline execution (single-pass)
|
|
1230
1341
|
// - only writes errorsample when diff exists
|
|
1231
|
-
// - baseline run disables hub snapshots to avoid polluting codex-samples
|
|
1232
1342
|
try {
|
|
1233
|
-
const
|
|
1234
|
-
|
|
1343
|
+
const shadow = result.metadata?.hubShadowCompare;
|
|
1344
|
+
const baselineProviderPayload = shadow && typeof shadow === 'object' && !Array.isArray(shadow)
|
|
1345
|
+
? shadow.baselineProviderPayload
|
|
1346
|
+
: undefined;
|
|
1347
|
+
if (wantsShadowCompare && baselineProviderPayload && typeof baselineProviderPayload === 'object') {
|
|
1235
1348
|
const entryEndpoint = String(input.entryEndpoint || '/v1/chat/completions');
|
|
1236
1349
|
const routeHint = typeof metadata.routeHint === 'string'
|
|
1237
1350
|
? String(metadata.routeHint)
|
|
@@ -1260,31 +1373,17 @@ export class RouteCodexHttpServer {
|
|
|
1260
1373
|
};
|
|
1261
1374
|
void (async () => {
|
|
1262
1375
|
try {
|
|
1263
|
-
const baselineMeta = {
|
|
1264
|
-
...(pipelineInput.metadata ?? {}),
|
|
1265
|
-
__hubPolicyOverride: { mode: this.hubShadowCompareConfig.baselineMode },
|
|
1266
|
-
__disableHubSnapshots: true
|
|
1267
|
-
};
|
|
1268
|
-
const baselineInput = {
|
|
1269
|
-
...pipelineInput,
|
|
1270
|
-
// Ensure baseline run uses the exact same HubPipeline requestId as the candidate run.
|
|
1271
|
-
// Otherwise internal requestId fields (e.g. responsesContext.requestId) will differ and
|
|
1272
|
-
// produce noisy diffs even when providerPayload is otherwise identical.
|
|
1273
|
-
id: derivedRequestId,
|
|
1274
|
-
endpoint: entryEndpoint,
|
|
1275
|
-
metadata: baselineMeta
|
|
1276
|
-
};
|
|
1277
|
-
const baselinePipeline = this.hubShadowComparePipeline || this.hubPipeline;
|
|
1278
|
-
const baseline = await baselinePipeline.execute(baselineInput);
|
|
1279
1376
|
const baselineOut = {
|
|
1280
|
-
providerPayload: cloneJsonSafe(
|
|
1281
|
-
target:
|
|
1377
|
+
providerPayload: cloneJsonSafe(baselineProviderPayload),
|
|
1378
|
+
target: shadow && typeof shadow === 'object' && !Array.isArray(shadow) && shadow.baselineTarget
|
|
1379
|
+
? cloneJsonSafe(shadow.baselineTarget)
|
|
1380
|
+
: cloneJsonSafe(result.target),
|
|
1282
1381
|
metadata: {
|
|
1283
|
-
entryEndpoint:
|
|
1284
|
-
providerProtocol:
|
|
1285
|
-
processMode:
|
|
1286
|
-
stream:
|
|
1287
|
-
routeHint:
|
|
1382
|
+
entryEndpoint: result.metadata?.entryEndpoint,
|
|
1383
|
+
providerProtocol: result.metadata?.providerProtocol,
|
|
1384
|
+
processMode: result.metadata?.processMode,
|
|
1385
|
+
stream: result.metadata?.stream,
|
|
1386
|
+
routeHint: result.metadata?.routeHint
|
|
1288
1387
|
}
|
|
1289
1388
|
};
|
|
1290
1389
|
await recordHubShadowCompareDiff({
|
|
@@ -1293,7 +1392,7 @@ export class RouteCodexHttpServer {
|
|
|
1293
1392
|
routeHint,
|
|
1294
1393
|
excludedProviderKeys,
|
|
1295
1394
|
baselineMode: this.hubShadowCompareConfig.baselineMode,
|
|
1296
|
-
candidateMode: this.hubPolicyMode ?? undefined,
|
|
1395
|
+
candidateMode: typeof shadow?.candidateMode === 'string' ? shadow.candidateMode : (this.hubPolicyMode ?? undefined),
|
|
1297
1396
|
baselineOut,
|
|
1298
1397
|
candidateOut
|
|
1299
1398
|
});
|
|
@@ -1308,6 +1407,77 @@ export class RouteCodexHttpServer {
|
|
|
1308
1407
|
catch {
|
|
1309
1408
|
// best-effort only
|
|
1310
1409
|
}
|
|
1410
|
+
// llms-engine: runtime black-box shadow compare (TS vs engine) for hub pipeline.
|
|
1411
|
+
if (wantsLlmsEngineShadow) {
|
|
1412
|
+
const cloneJsonSafe = (value) => {
|
|
1413
|
+
try {
|
|
1414
|
+
return JSON.parse(JSON.stringify(value));
|
|
1415
|
+
}
|
|
1416
|
+
catch {
|
|
1417
|
+
return value;
|
|
1418
|
+
}
|
|
1419
|
+
};
|
|
1420
|
+
const entryEndpoint = String(input.entryEndpoint || '/v1/chat/completions');
|
|
1421
|
+
const routeHint = typeof metadata.routeHint === 'string'
|
|
1422
|
+
? String(metadata.routeHint)
|
|
1423
|
+
: undefined;
|
|
1424
|
+
const baselineOut = {
|
|
1425
|
+
providerPayload: cloneJsonSafe(result.providerPayload),
|
|
1426
|
+
target: cloneJsonSafe(result.target),
|
|
1427
|
+
metadata: {
|
|
1428
|
+
entryEndpoint: result.metadata?.entryEndpoint,
|
|
1429
|
+
providerProtocol: result.metadata?.providerProtocol,
|
|
1430
|
+
processMode: result.metadata?.processMode,
|
|
1431
|
+
stream: result.metadata?.stream,
|
|
1432
|
+
routeHint: result.metadata?.routeHint
|
|
1433
|
+
}
|
|
1434
|
+
};
|
|
1435
|
+
void (async () => {
|
|
1436
|
+
try {
|
|
1437
|
+
const shadowPipeline = await this.ensureHubPipelineEngineShadow();
|
|
1438
|
+
const shadowRequestId = `${input.requestId}__llms_engine_shadow`;
|
|
1439
|
+
const baseMeta = pipelineInput.metadata;
|
|
1440
|
+
const shadowInput = {
|
|
1441
|
+
...pipelineInput,
|
|
1442
|
+
id: shadowRequestId,
|
|
1443
|
+
endpoint: input.entryEndpoint,
|
|
1444
|
+
metadata: {
|
|
1445
|
+
...(baseMeta && typeof baseMeta === 'object' ? baseMeta : {}),
|
|
1446
|
+
__llmsEngineShadow: { baselineRequestId: derivedRequestId, entryEndpoint, routeHint }
|
|
1447
|
+
},
|
|
1448
|
+
payload: cloneJsonSafe(payload)
|
|
1449
|
+
};
|
|
1450
|
+
const shadowResult = await shadowPipeline.execute(shadowInput);
|
|
1451
|
+
if (!shadowResult?.providerPayload || !shadowResult?.target) {
|
|
1452
|
+
return;
|
|
1453
|
+
}
|
|
1454
|
+
const candidateOut = {
|
|
1455
|
+
providerPayload: cloneJsonSafe(shadowResult.providerPayload),
|
|
1456
|
+
target: cloneJsonSafe(shadowResult.target),
|
|
1457
|
+
metadata: {
|
|
1458
|
+
entryEndpoint: shadowResult.metadata?.entryEndpoint,
|
|
1459
|
+
providerProtocol: shadowResult.metadata?.providerProtocol,
|
|
1460
|
+
processMode: shadowResult.metadata?.processMode,
|
|
1461
|
+
stream: shadowResult.metadata?.stream,
|
|
1462
|
+
routeHint: shadowResult.metadata?.routeHint
|
|
1463
|
+
}
|
|
1464
|
+
};
|
|
1465
|
+
await recordLlmsEngineShadowDiff({
|
|
1466
|
+
group: 'hub-pipeline',
|
|
1467
|
+
requestId: derivedRequestId,
|
|
1468
|
+
subpath: 'conversion/hub/pipeline',
|
|
1469
|
+
baselineImpl: 'ts',
|
|
1470
|
+
candidateImpl: 'engine',
|
|
1471
|
+
baselineOut,
|
|
1472
|
+
candidateOut
|
|
1473
|
+
});
|
|
1474
|
+
}
|
|
1475
|
+
catch (error) {
|
|
1476
|
+
// eslint-disable-next-line no-console
|
|
1477
|
+
console.error('[llms-engine-shadow] hub pipeline shadow failed:', error);
|
|
1478
|
+
}
|
|
1479
|
+
})();
|
|
1480
|
+
}
|
|
1311
1481
|
return {
|
|
1312
1482
|
requestId: derivedRequestId,
|
|
1313
1483
|
providerPayload: result.providerPayload,
|
|
@@ -1376,19 +1546,12 @@ export class RouteCodexHttpServer {
|
|
|
1376
1546
|
}
|
|
1377
1547
|
// 在 Host 入口统一解析会话标识,后续 HubPipeline / servertool 等模块仅依赖
|
|
1378
1548
|
// sessionId / conversationId 字段,不再重复解析 clientHeaders。
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
const identifiers = extractSessionIdentifiersFromMetadata(metadata);
|
|
1383
|
-
if (identifiers.sessionId) {
|
|
1384
|
-
metadata.sessionId = identifiers.sessionId;
|
|
1385
|
-
}
|
|
1386
|
-
if (identifiers.conversationId) {
|
|
1387
|
-
metadata.conversationId = identifiers.conversationId;
|
|
1388
|
-
}
|
|
1549
|
+
const identifiers = extractSessionIdentifiersFromMetadata(metadata);
|
|
1550
|
+
if (identifiers.sessionId) {
|
|
1551
|
+
metadata.sessionId = identifiers.sessionId;
|
|
1389
1552
|
}
|
|
1390
|
-
|
|
1391
|
-
|
|
1553
|
+
if (identifiers.conversationId) {
|
|
1554
|
+
metadata.conversationId = identifiers.conversationId;
|
|
1392
1555
|
}
|
|
1393
1556
|
return metadata;
|
|
1394
1557
|
}
|
|
@@ -1532,7 +1695,6 @@ export class RouteCodexHttpServer {
|
|
|
1532
1695
|
try {
|
|
1533
1696
|
const providerProtocol = mapProviderProtocol(options.providerType);
|
|
1534
1697
|
const metadataBag = asRecord(options.pipelineMetadata);
|
|
1535
|
-
const aliasMap = extractAnthropicToolAliasMap(metadataBag);
|
|
1536
1698
|
const originalModelId = this.extractClientModelId(metadataBag, options.originalRequest);
|
|
1537
1699
|
// 以 HubPipeline metadata 为基础构建 AdapterContext,确保诸如
|
|
1538
1700
|
// capturedChatRequest / webSearch / routeHint 等字段在响应侧可见,
|
|
@@ -1550,12 +1712,6 @@ export class RouteCodexHttpServer {
|
|
|
1550
1712
|
baseContext.providerProtocol = providerProtocol;
|
|
1551
1713
|
baseContext.originalModelId = originalModelId;
|
|
1552
1714
|
const adapterContext = baseContext;
|
|
1553
|
-
// 将 serverToolFollowup 等标记从 pipelineMetadata 透传到 AdapterContext,
|
|
1554
|
-
// 便于 convertProviderResponse 正确识别内部二跳请求并跳过 servertool。
|
|
1555
|
-
if (metadataBag && Object.prototype.hasOwnProperty.call(metadataBag, 'serverToolFollowup')) {
|
|
1556
|
-
adapterContext.serverToolFollowup = metadataBag
|
|
1557
|
-
.serverToolFollowup;
|
|
1558
|
-
}
|
|
1559
1715
|
const compatProfile = metadataBag &&
|
|
1560
1716
|
typeof metadataBag === 'object' &&
|
|
1561
1717
|
metadataBag.target &&
|
|
@@ -1566,21 +1722,6 @@ export class RouteCodexHttpServer {
|
|
|
1566
1722
|
if (compatProfile && compatProfile.trim()) {
|
|
1567
1723
|
adapterContext.compatibilityProfile = compatProfile.trim();
|
|
1568
1724
|
}
|
|
1569
|
-
if (aliasMap) {
|
|
1570
|
-
adapterContext.anthropicToolNameMap = aliasMap;
|
|
1571
|
-
}
|
|
1572
|
-
if (metadataBag && typeof metadataBag === 'object') {
|
|
1573
|
-
const webSearchConfig = metadataBag.webSearch;
|
|
1574
|
-
if (webSearchConfig && typeof webSearchConfig === 'object') {
|
|
1575
|
-
adapterContext.webSearch = webSearchConfig;
|
|
1576
|
-
}
|
|
1577
|
-
if (metadataBag.forceWebSearch === true) {
|
|
1578
|
-
adapterContext.forceWebSearch = true;
|
|
1579
|
-
}
|
|
1580
|
-
if (metadataBag.forceVision === true) {
|
|
1581
|
-
adapterContext.forceVision = true;
|
|
1582
|
-
}
|
|
1583
|
-
}
|
|
1584
1725
|
const stageRecorder = await bridgeCreateSnapshotRecorder(adapterContext, typeof adapterContext.entryEndpoint === 'string'
|
|
1585
1726
|
? adapterContext.entryEndpoint
|
|
1586
1727
|
: options.entryEndpoint || entry);
|
|
@@ -1600,7 +1741,6 @@ export class RouteCodexHttpServer {
|
|
|
1600
1741
|
const reenterPipeline = async (reenterOpts) => {
|
|
1601
1742
|
const nestedEntry = reenterOpts.entryEndpoint || options.entryEndpoint || entry;
|
|
1602
1743
|
const nestedExtra = asRecord(reenterOpts.metadata) ?? {};
|
|
1603
|
-
const nestedEntryLower = nestedEntry.toLowerCase();
|
|
1604
1744
|
// 基于首次 HubPipeline metadata + 调用方注入的 metadata 构建新的请求 metadata。
|
|
1605
1745
|
// 不在 Host 层编码 servertool/web_search 等语义,由 llmswitch-core 负责。
|
|
1606
1746
|
const nestedMetadata = {
|
|
@@ -1612,25 +1752,20 @@ export class RouteCodexHttpServer {
|
|
|
1612
1752
|
};
|
|
1613
1753
|
// servertool followup 是内部二跳请求:不应继承客户端 headers 偏好(尤其是 Accept),
|
|
1614
1754
|
// 否则会导致上游返回非 SSE 响应而被当作 SSE 解析,出现“空回复”。
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
}
|
|
1623
|
-
else if (nestedEntryLower.includes('/v1/responses')) {
|
|
1624
|
-
nestedMetadata.providerProtocol = 'openai-responses';
|
|
1755
|
+
// E1: merge internal runtime metadata carrier (`__rt`) instead of clobbering it.
|
|
1756
|
+
try {
|
|
1757
|
+
const baseRt = asRecord(metadataBag?.__rt) ?? {};
|
|
1758
|
+
const extraRt = asRecord(nestedExtra?.__rt) ?? {};
|
|
1759
|
+
if (Object.keys(baseRt).length || Object.keys(extraRt).length) {
|
|
1760
|
+
nestedMetadata.__rt = { ...baseRt, ...extraRt };
|
|
1761
|
+
}
|
|
1625
1762
|
}
|
|
1626
|
-
|
|
1627
|
-
|
|
1763
|
+
catch {
|
|
1764
|
+
// best-effort
|
|
1628
1765
|
}
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
if (followupProtocol) {
|
|
1633
|
-
nestedMetadata.providerProtocol = followupProtocol;
|
|
1766
|
+
if (asRecord(nestedMetadata.__rt)?.serverToolFollowup === true) {
|
|
1767
|
+
delete nestedMetadata.clientHeaders;
|
|
1768
|
+
delete nestedMetadata.clientRequestId;
|
|
1634
1769
|
}
|
|
1635
1770
|
const nestedInput = {
|
|
1636
1771
|
entryEndpoint: nestedEntry,
|
|
@@ -1653,6 +1788,7 @@ export class RouteCodexHttpServer {
|
|
|
1653
1788
|
context: adapterContext,
|
|
1654
1789
|
entryEndpoint: options.entryEndpoint || entry,
|
|
1655
1790
|
wantsStream: options.wantsStream,
|
|
1791
|
+
requestSemantics: options.requestSemantics,
|
|
1656
1792
|
providerInvoker,
|
|
1657
1793
|
stageRecorder,
|
|
1658
1794
|
reenterPipeline
|
|
@@ -1674,12 +1810,21 @@ export class RouteCodexHttpServer {
|
|
|
1674
1810
|
const errRecord = err;
|
|
1675
1811
|
const errCode = typeof errRecord.code === 'string' ? errRecord.code : undefined;
|
|
1676
1812
|
const errName = typeof errRecord.name === 'string' ? errRecord.name : undefined;
|
|
1813
|
+
const statusCandidate = typeof errRecord.status === 'number'
|
|
1814
|
+
? errRecord.status
|
|
1815
|
+
: typeof errRecord.statusCode === 'number'
|
|
1816
|
+
? errRecord.statusCode
|
|
1817
|
+
: undefined;
|
|
1677
1818
|
const isSseDecodeError = errCode === 'SSE_DECODE_ERROR' ||
|
|
1678
1819
|
(errName === 'ProviderProtocolError' && message.toLowerCase().includes('sse'));
|
|
1679
1820
|
const isServerToolFollowupError = errCode === 'SERVERTOOL_FOLLOWUP_FAILED' ||
|
|
1680
1821
|
errCode === 'SERVERTOOL_EMPTY_FOLLOWUP' ||
|
|
1681
1822
|
(typeof errCode === 'string' && errCode.startsWith('SERVERTOOL_'));
|
|
1682
|
-
|
|
1823
|
+
const isProviderProtocolError = errName === 'ProviderProtocolError';
|
|
1824
|
+
// If we need to stream a client response, conversion failures are fatal: there is no safe fallback
|
|
1825
|
+
// that preserves protocol correctness.
|
|
1826
|
+
const isStreamingConversion = Boolean(options.wantsStream && (needsAnthropicConversion || needsResponsesConversion || needsChatConversion));
|
|
1827
|
+
if (isSseDecodeError || isServerToolFollowupError || isStreamingConversion || (isProviderProtocolError && typeof statusCandidate === 'number')) {
|
|
1683
1828
|
console.error('[RouteCodexHttpServer] Fatal conversion error, bubbling as HTTP error', error);
|
|
1684
1829
|
throw error;
|
|
1685
1830
|
}
|