@jsonstudio/rcc 0.89.1189 → 0.89.1348
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 +17 -0
- 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 +74 -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 +91 -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 +36 -0
- package/dist/cli/config/init-config.js +180 -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-cli/gemini-cli-protocol-client.js +1 -1
- package/dist/client/gemini-cli/gemini-cli-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/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 +237 -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 +189 -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 +314 -71
- 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/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/core/config/camoufox-launcher.js +35 -4
- package/dist/providers/core/config/camoufox-launcher.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 -2
- package/dist/providers/core/runtime/base-provider.js +74 -69
- package/dist/providers/core/runtime/base-provider.js.map +1 -1
- package/dist/providers/core/runtime/gemini-cli-http-provider.js +6 -4
- package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
- package/dist/providers/core/runtime/http-request-executor.js +2 -2
- package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
- package/dist/providers/core/runtime/http-transport-provider.d.ts +14 -0
- package/dist/providers/core/runtime/http-transport-provider.js +111 -5
- 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/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 +16 -3
- 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 +3 -2
- package/dist/server/handlers/handler-utils.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.d.ts +18 -0
- package/dist/server/runtime/http-server/hub-shadow-compare.js +256 -0
- package/dist/server/runtime/http-server/hub-shadow-compare.js.map +1 -0
- package/dist/server/runtime/http-server/index.d.ts +7 -2
- package/dist/server/runtime/http-server/index.js +287 -49
- 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 +10 -19
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/server/runtime/http-server/routes.js +8 -2
- 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/errorsamples.d.ts +5 -0
- package/dist/utils/errorsamples.js +27 -0
- package/dist/utils/errorsamples.js.map +1 -0
- 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.d.ts +1 -0
- package/dist/utils/runtime-versions.js +39 -0
- package/dist/utils/runtime-versions.js.map +1 -0
- package/docs/ARCHITECTURE.md +402 -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/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 +82 -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/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 +551 -0
- package/docs/verification/modelscope-verify.md +59 -0
- package/docs/web-search-service-design.md +322 -0
- package/package.json +12 -7
- package/scripts/camoufox/launch-auth.mjs +193 -58
- package/scripts/monitor-diff.mjs +126 -0
- package/scripts/pack-mode.mjs +19 -1
- package/scripts/pack-rcc.mjs +63 -0
- package/scripts/unified-hub-shadow-compare.mjs +33 -13
- 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
|
@@ -21,7 +21,7 @@ import { registerHttpRoutes, registerOAuthPortalRoute } from './routes.js';
|
|
|
21
21
|
import { mapProviderProtocol, normalizeProviderType, resolveProviderIdentity, asRecord } from './provider-utils.js';
|
|
22
22
|
import { resolveRepoRoot } from './llmswitch-loader.js';
|
|
23
23
|
import { enhanceProviderRequestId } from '../../utils/request-id-manager.js';
|
|
24
|
-
import { convertProviderResponse as bridgeConvertProviderResponse, createSnapshotRecorder as bridgeCreateSnapshotRecorder, rebindResponsesConversationRequestId, bootstrapVirtualRouterConfig, getHubPipelineCtor } from '../../../modules/llmswitch/bridge.js';
|
|
24
|
+
import { convertProviderResponse as bridgeConvertProviderResponse, createSnapshotRecorder as bridgeCreateSnapshotRecorder, rebindResponsesConversationRequestId, extractSessionIdentifiersFromMetadata, bootstrapVirtualRouterConfig, getHubPipelineCtor } from '../../../modules/llmswitch/bridge.js';
|
|
25
25
|
import { initializeRouteErrorHub, reportRouteError } from '../../../error-handling/route-error-hub.js';
|
|
26
26
|
import { writeClientSnapshot } from '../../../providers/core/utils/snapshot-writer.js';
|
|
27
27
|
import { createServerColoredLogger } from './colored-logger.js';
|
|
@@ -32,8 +32,22 @@ import { ManagerDaemon } from '../../../manager/index.js';
|
|
|
32
32
|
import { HealthManagerModule } from '../../../manager/modules/health/index.js';
|
|
33
33
|
import { RoutingStateManagerModule } from '../../../manager/modules/routing/index.js';
|
|
34
34
|
import { TokenManagerModule } from '../../../manager/modules/token/index.js';
|
|
35
|
+
import { ensureServerScopedSessionDir } from './session-dir.js';
|
|
35
36
|
import { StatsManager } from './stats-manager.js';
|
|
36
37
|
import { loadRouteCodexConfig } from '../../../config/routecodex-config-loader.js';
|
|
38
|
+
import { buildInfo } from '../../../build-info.js';
|
|
39
|
+
import { recordHubShadowCompareDiff, resolveHubShadowCompareConfig, shouldRunHubShadowCompare } from './hub-shadow-compare.js';
|
|
40
|
+
import { recordLlmsEngineShadowDiff, isLlmsEngineShadowEnabledForSubpath, resolveLlmsEngineShadowConfig, shouldRunLlmsEngineShadowForSubpath } from '../../../utils/llms-engine-shadow.js';
|
|
41
|
+
import { resolveLlmswitchCoreVersion } from '../../../utils/runtime-versions.js';
|
|
42
|
+
const DEFAULT_MAX_PROVIDER_ATTEMPTS = 6;
|
|
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
|
+
}
|
|
37
51
|
/**
|
|
38
52
|
* RouteCodex Server V2
|
|
39
53
|
*
|
|
@@ -66,16 +80,19 @@ export class RouteCodexHttpServer {
|
|
|
66
80
|
managerDaemon = null;
|
|
67
81
|
stats = new StatsManager();
|
|
68
82
|
restartChain = Promise.resolve();
|
|
83
|
+
hubShadowCompareConfig = resolveHubShadowCompareConfig();
|
|
84
|
+
llmsEngineShadowConfig = resolveLlmsEngineShadowConfig();
|
|
85
|
+
hubPolicyMode = null;
|
|
86
|
+
hubPipelineEngineShadow = null;
|
|
87
|
+
hubPipelineConfigForShadow = null;
|
|
69
88
|
constructor(config) {
|
|
70
89
|
this.config = config;
|
|
71
90
|
this.app = express();
|
|
72
91
|
this.errorHandling = new QuietErrorHandlingCenter();
|
|
73
92
|
this.stageLoggingEnabled = isStageLoggingEnabled();
|
|
74
93
|
this.repoRoot = resolveRepoRoot(import.meta.url);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
console.warn('[RouteCodexHttpServer] Super pipeline has been removed; falling back to Hub pipeline.');
|
|
78
|
-
}
|
|
94
|
+
// Ensure session-scoped routing state does not leak across server instances.
|
|
95
|
+
ensureServerScopedSessionDir(`${this.config.server.host}:${this.config.server.port}`);
|
|
79
96
|
try {
|
|
80
97
|
this.pipelineLogger = new PipelineDebugLoggerImpl({ colored: this.coloredLogger }, { enableConsoleLogging: true });
|
|
81
98
|
}
|
|
@@ -111,20 +128,11 @@ export class RouteCodexHttpServer {
|
|
|
111
128
|
/**
|
|
112
129
|
* Register Daemon Admin UI route.
|
|
113
130
|
* Serves docs/daemon-admin-ui.html as a static page.
|
|
114
|
-
* -
|
|
115
|
-
* - If `httpserver.apikey` is configured: allow remote UI access (API calls still require apikey).
|
|
131
|
+
* Note: daemon-admin UI/API now uses password login (stored at ~/.routecodex/login) instead of httpserver.apikey.
|
|
116
132
|
*/
|
|
117
133
|
registerDaemonAdminUiRoute() {
|
|
118
134
|
this.app.get('/daemon/admin', async (req, res) => {
|
|
119
135
|
try {
|
|
120
|
-
const ip = req.socket?.remoteAddress || '';
|
|
121
|
-
const isLocal = ip === '127.0.0.1' || ip === '::1' || ip === '::ffff:127.0.0.1';
|
|
122
|
-
const expectedKey = typeof this.config?.server?.apikey === 'string' ? this.config.server.apikey.trim() : '';
|
|
123
|
-
const hasConfiguredKey = Boolean(expectedKey);
|
|
124
|
-
if (!isLocal && !hasConfiguredKey) {
|
|
125
|
-
res.status(403).json({ error: { message: 'forbidden', code: 'forbidden' } });
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
136
|
const fs = await import('node:fs/promises');
|
|
129
137
|
let html = '';
|
|
130
138
|
try {
|
|
@@ -353,6 +361,46 @@ export class RouteCodexHttpServer {
|
|
|
353
361
|
this.hubPipelineCtor = ctorFactory;
|
|
354
362
|
return this.hubPipelineCtor;
|
|
355
363
|
}
|
|
364
|
+
async ensureHubPipelineEngineShadow() {
|
|
365
|
+
if (this.hubPipelineEngineShadow) {
|
|
366
|
+
return this.hubPipelineEngineShadow;
|
|
367
|
+
}
|
|
368
|
+
if (!this.hubPipelineConfigForShadow) {
|
|
369
|
+
throw new Error('Hub pipeline shadow config is not initialized');
|
|
370
|
+
}
|
|
371
|
+
const baseConfig = this.hubPipelineConfigForShadow;
|
|
372
|
+
const shadowConfig = { ...baseConfig };
|
|
373
|
+
// Avoid double side effects when shadow-running the pipeline: keep reads, drop writes.
|
|
374
|
+
const routingStateStore = baseConfig.routingStateStore;
|
|
375
|
+
if (routingStateStore && typeof routingStateStore.loadSync === 'function') {
|
|
376
|
+
shadowConfig.routingStateStore = {
|
|
377
|
+
loadSync: routingStateStore.loadSync.bind(routingStateStore),
|
|
378
|
+
saveAsync: () => { }
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
const healthStore = baseConfig.healthStore;
|
|
382
|
+
if (healthStore && typeof healthStore.loadInitialSnapshot === 'function') {
|
|
383
|
+
shadowConfig.healthStore = {
|
|
384
|
+
loadInitialSnapshot: healthStore.loadInitialSnapshot.bind(healthStore)
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
const quotaViewReadOnly = baseConfig.quotaViewReadOnly;
|
|
388
|
+
if (typeof quotaViewReadOnly === 'function') {
|
|
389
|
+
shadowConfig.quotaView = quotaViewReadOnly;
|
|
390
|
+
}
|
|
391
|
+
const bridge = (await import('../../../modules/llmswitch/bridge.js'));
|
|
392
|
+
const getCtor = bridge.getHubPipelineCtorForImpl;
|
|
393
|
+
if (typeof getCtor !== 'function') {
|
|
394
|
+
throw new Error('llmswitch bridge does not expose getHubPipelineCtorForImpl');
|
|
395
|
+
}
|
|
396
|
+
const ctorFactory = await getCtor('engine');
|
|
397
|
+
const hubCtor = ctorFactory;
|
|
398
|
+
if (!('virtualRouter' in shadowConfig)) {
|
|
399
|
+
throw new Error('HubPipeline shadow config missing virtualRouter');
|
|
400
|
+
}
|
|
401
|
+
this.hubPipelineEngineShadow = new hubCtor(shadowConfig);
|
|
402
|
+
return this.hubPipelineEngineShadow;
|
|
403
|
+
}
|
|
356
404
|
isPipelineReady() {
|
|
357
405
|
return Boolean(this.hubPipeline);
|
|
358
406
|
}
|
|
@@ -656,6 +704,7 @@ export class RouteCodexHttpServer {
|
|
|
656
704
|
const hubPolicyMode = hubPolicyModeRaw === 'off' || hubPolicyModeRaw === '0' || hubPolicyModeRaw === 'false'
|
|
657
705
|
? null
|
|
658
706
|
: (hubPolicyModeRaw === 'observe' || hubPolicyModeRaw === 'enforce' ? hubPolicyModeRaw : 'enforce');
|
|
707
|
+
this.hubPolicyMode = hubPolicyMode ?? 'off';
|
|
659
708
|
if (hubPolicyMode) {
|
|
660
709
|
const sampleRateRaw = String(process.env.ROUTECODEX_HUB_POLICY_SAMPLE_RATE || '').trim();
|
|
661
710
|
const sampleRate = sampleRateRaw ? Number(sampleRateRaw) : undefined;
|
|
@@ -664,6 +713,40 @@ export class RouteCodexHttpServer {
|
|
|
664
713
|
...(Number.isFinite(sampleRate) ? { sampleRate } : {})
|
|
665
714
|
};
|
|
666
715
|
}
|
|
716
|
+
// Unified Hub Framework V1: tool surface rollout toggle (enforce by default in dev).
|
|
717
|
+
// - Disable via env: ROUTECODEX_HUB_TOOL_SURFACE_MODE=off
|
|
718
|
+
// - Observe via env: ROUTECODEX_HUB_TOOL_SURFACE_MODE=observe
|
|
719
|
+
// - Shadow (diff-only, no rewrites) via env: ROUTECODEX_HUB_TOOL_SURFACE_MODE=shadow
|
|
720
|
+
// - Enforce (rewrite outbound payload) via env: ROUTECODEX_HUB_TOOL_SURFACE_MODE=enforce
|
|
721
|
+
const toolSurfaceModeRaw = String(process.env.ROUTECODEX_HUB_TOOL_SURFACE_MODE || '').trim().toLowerCase();
|
|
722
|
+
const toolSurfaceMode = toolSurfaceModeRaw === 'off' || toolSurfaceModeRaw === '0' || toolSurfaceModeRaw === 'false'
|
|
723
|
+
? null
|
|
724
|
+
: toolSurfaceModeRaw === 'observe' || toolSurfaceModeRaw === 'shadow' || toolSurfaceModeRaw === 'enforce'
|
|
725
|
+
? toolSurfaceModeRaw
|
|
726
|
+
: buildInfo.mode === 'dev'
|
|
727
|
+
? 'enforce'
|
|
728
|
+
: null;
|
|
729
|
+
if (toolSurfaceMode) {
|
|
730
|
+
const sampleRateRaw = String(process.env.ROUTECODEX_HUB_TOOL_SURFACE_SAMPLE_RATE || '').trim();
|
|
731
|
+
const sampleRate = sampleRateRaw ? Number(sampleRateRaw) : undefined;
|
|
732
|
+
hubConfig.toolSurface = {
|
|
733
|
+
mode: toolSurfaceMode,
|
|
734
|
+
...(Number.isFinite(sampleRate) ? { sampleRate } : {})
|
|
735
|
+
};
|
|
736
|
+
// Also export the resolved mode to env so llmswitch-core response conversion
|
|
737
|
+
// (convertProviderResponse) can observe tool surface mismatches consistently.
|
|
738
|
+
if (!process.env.ROUTECODEX_HUB_TOOL_SURFACE_MODE) {
|
|
739
|
+
process.env.ROUTECODEX_HUB_TOOL_SURFACE_MODE = toolSurfaceMode;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
// Unified Hub Framework V1: followup (servertool) shadow compare toggle.
|
|
743
|
+
// Implemented in llmswitch-core servertool engine; controlled by env for progressive rollout.
|
|
744
|
+
// Default: shadow in dev builds; off in release builds.
|
|
745
|
+
if (!process.env.ROUTECODEX_HUB_FOLLOWUP_MODE) {
|
|
746
|
+
if (buildInfo.mode === 'dev') {
|
|
747
|
+
process.env.ROUTECODEX_HUB_FOLLOWUP_MODE = 'shadow';
|
|
748
|
+
}
|
|
749
|
+
}
|
|
667
750
|
const healthModule = this.managerDaemon?.getModule('health');
|
|
668
751
|
const healthStore = healthModule?.getHealthStore();
|
|
669
752
|
if (healthStore) {
|
|
@@ -677,6 +760,9 @@ export class RouteCodexHttpServer {
|
|
|
677
760
|
const quotaModule = this.managerDaemon?.getModule('provider-quota');
|
|
678
761
|
if (this.isQuotaRoutingEnabled() && quotaModule && typeof quotaModule.getQuotaView === 'function') {
|
|
679
762
|
hubConfig.quotaView = quotaModule.getQuotaView();
|
|
763
|
+
if (typeof quotaModule.getQuotaViewReadOnly === 'function') {
|
|
764
|
+
hubConfig.quotaViewReadOnly = quotaModule.getQuotaViewReadOnly();
|
|
765
|
+
}
|
|
680
766
|
}
|
|
681
767
|
if (!this.hubPipeline) {
|
|
682
768
|
this.hubPipeline = new hubCtor(hubConfig);
|
|
@@ -695,6 +781,9 @@ export class RouteCodexHttpServer {
|
|
|
695
781
|
}
|
|
696
782
|
this.hubPipeline.updateVirtualRouterConfig(bootstrapArtifacts.config);
|
|
697
783
|
}
|
|
784
|
+
// llms-engine shadow: capture the latest hub config and reset shadow pipeline to avoid stale deps.
|
|
785
|
+
this.hubPipelineConfigForShadow = hubConfig;
|
|
786
|
+
this.hubPipelineEngineShadow = null;
|
|
698
787
|
await this.initializeProviderRuntimes(bootstrapArtifacts);
|
|
699
788
|
}
|
|
700
789
|
buildHandlerContext() {
|
|
@@ -924,11 +1013,12 @@ export class RouteCodexHttpServer {
|
|
|
924
1013
|
}
|
|
925
1014
|
const pipelineLabel = 'hub';
|
|
926
1015
|
const iterationMetadata = initialMetadata;
|
|
927
|
-
|
|
928
|
-
// 单次 HTTP
|
|
1016
|
+
// _followupTriggered = false;
|
|
1017
|
+
// 单次 HTTP 请求内允许多次 failover(不在 Provider 层做重试):
|
|
929
1018
|
// - 让 VirtualRouter 根据 excludedProviderKeys 跳过失败目标
|
|
930
1019
|
// - 避免客户端“一次就断”导致对话破裂(尤其是 429 / prompt too long 等可恢复错误)
|
|
931
|
-
|
|
1020
|
+
// - 通过 env 允许按部署/客户端调整:ROUTECODEX_MAX_PROVIDER_ATTEMPTS / RCC_MAX_PROVIDER_ATTEMPTS
|
|
1021
|
+
const maxAttempts = resolveMaxProviderAttempts();
|
|
932
1022
|
let attempt = 0;
|
|
933
1023
|
let firstError = null;
|
|
934
1024
|
const originalBodySnapshot = this.cloneRequestPayload(input.body);
|
|
@@ -1102,9 +1192,13 @@ export class RouteCodexHttpServer {
|
|
|
1102
1192
|
const sessionId = typeof mergedMetadata.sessionId === "string" && mergedMetadata.sessionId.trim()
|
|
1103
1193
|
? mergedMetadata.sessionId.trim()
|
|
1104
1194
|
: undefined;
|
|
1105
|
-
|
|
1195
|
+
let conversationId = typeof mergedMetadata.conversationId === "string" && mergedMetadata.conversationId.trim()
|
|
1106
1196
|
? mergedMetadata.conversationId.trim()
|
|
1107
1197
|
: undefined;
|
|
1198
|
+
// 对称补齐:如果只有 session_id,则回传 conversation_id=session_id
|
|
1199
|
+
if (!conversationId && sessionId) {
|
|
1200
|
+
conversationId = sessionId;
|
|
1201
|
+
}
|
|
1108
1202
|
if (sessionId || conversationId) {
|
|
1109
1203
|
if (!converted.headers) {
|
|
1110
1204
|
converted.headers = {};
|
|
@@ -1167,11 +1261,18 @@ export class RouteCodexHttpServer {
|
|
|
1167
1261
|
throw new Error('Hub pipeline runtime is not initialized');
|
|
1168
1262
|
}
|
|
1169
1263
|
const payload = asRecord(input.body);
|
|
1264
|
+
const isInternalFollowup = metadata.serverToolFollowup === true;
|
|
1265
|
+
const wantsShadowCompare = !isInternalFollowup && shouldRunHubShadowCompare(this.hubShadowCompareConfig);
|
|
1170
1266
|
const pipelineInput = {
|
|
1171
1267
|
...input,
|
|
1268
|
+
id: input.requestId,
|
|
1269
|
+
endpoint: input.entryEndpoint,
|
|
1172
1270
|
metadata: {
|
|
1173
1271
|
...metadata,
|
|
1174
|
-
logger: this.coloredLogger
|
|
1272
|
+
logger: this.coloredLogger,
|
|
1273
|
+
...(wantsShadowCompare
|
|
1274
|
+
? { __hubShadowCompare: { baselineMode: this.hubShadowCompareConfig.baselineMode } }
|
|
1275
|
+
: {})
|
|
1175
1276
|
},
|
|
1176
1277
|
payload
|
|
1177
1278
|
};
|
|
@@ -1187,6 +1288,156 @@ export class RouteCodexHttpServer {
|
|
|
1187
1288
|
const derivedRequestId = typeof resultRecord.requestId === 'string'
|
|
1188
1289
|
? resultRecord.requestId
|
|
1189
1290
|
: input.requestId;
|
|
1291
|
+
const llmsEngineShadowEnabled = !isInternalFollowup &&
|
|
1292
|
+
isLlmsEngineShadowEnabledForSubpath(this.llmsEngineShadowConfig, 'conversion/hub/pipeline');
|
|
1293
|
+
if (llmsEngineShadowEnabled) {
|
|
1294
|
+
// Fail fast: if shadow is enabled for this module, engine core must be available.
|
|
1295
|
+
await this.ensureHubPipelineEngineShadow();
|
|
1296
|
+
}
|
|
1297
|
+
const wantsLlmsEngineShadow = llmsEngineShadowEnabled &&
|
|
1298
|
+
shouldRunLlmsEngineShadowForSubpath(this.llmsEngineShadowConfig, 'conversion/hub/pipeline');
|
|
1299
|
+
// Unified Hub Framework V1: runtime black-box shadow compare (baseline policy vs current policy).
|
|
1300
|
+
// - baseline payload is computed in the SAME hub pipeline execution (single-pass)
|
|
1301
|
+
// - only writes errorsample when diff exists
|
|
1302
|
+
try {
|
|
1303
|
+
const shadow = result.metadata?.hubShadowCompare;
|
|
1304
|
+
const baselineProviderPayload = shadow && typeof shadow === 'object' && !Array.isArray(shadow)
|
|
1305
|
+
? shadow.baselineProviderPayload
|
|
1306
|
+
: undefined;
|
|
1307
|
+
if (wantsShadowCompare && baselineProviderPayload && typeof baselineProviderPayload === 'object') {
|
|
1308
|
+
const entryEndpoint = String(input.entryEndpoint || '/v1/chat/completions');
|
|
1309
|
+
const routeHint = typeof metadata.routeHint === 'string'
|
|
1310
|
+
? String(metadata.routeHint)
|
|
1311
|
+
: undefined;
|
|
1312
|
+
const excludedProviderKeys = Array.isArray(metadata.excludedProviderKeys)
|
|
1313
|
+
? metadata.excludedProviderKeys
|
|
1314
|
+
: [];
|
|
1315
|
+
const cloneJsonSafe = (value) => {
|
|
1316
|
+
try {
|
|
1317
|
+
return JSON.parse(JSON.stringify(value));
|
|
1318
|
+
}
|
|
1319
|
+
catch {
|
|
1320
|
+
return value;
|
|
1321
|
+
}
|
|
1322
|
+
};
|
|
1323
|
+
const candidateOut = {
|
|
1324
|
+
providerPayload: cloneJsonSafe(result.providerPayload),
|
|
1325
|
+
target: cloneJsonSafe(result.target),
|
|
1326
|
+
metadata: {
|
|
1327
|
+
entryEndpoint: result.metadata?.entryEndpoint,
|
|
1328
|
+
providerProtocol: result.metadata?.providerProtocol,
|
|
1329
|
+
processMode: result.metadata?.processMode,
|
|
1330
|
+
stream: result.metadata?.stream,
|
|
1331
|
+
routeHint: result.metadata?.routeHint
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1334
|
+
void (async () => {
|
|
1335
|
+
try {
|
|
1336
|
+
const baselineOut = {
|
|
1337
|
+
providerPayload: cloneJsonSafe(baselineProviderPayload),
|
|
1338
|
+
target: shadow && typeof shadow === 'object' && !Array.isArray(shadow) && shadow.baselineTarget
|
|
1339
|
+
? cloneJsonSafe(shadow.baselineTarget)
|
|
1340
|
+
: cloneJsonSafe(result.target),
|
|
1341
|
+
metadata: {
|
|
1342
|
+
entryEndpoint: result.metadata?.entryEndpoint,
|
|
1343
|
+
providerProtocol: result.metadata?.providerProtocol,
|
|
1344
|
+
processMode: result.metadata?.processMode,
|
|
1345
|
+
stream: result.metadata?.stream,
|
|
1346
|
+
routeHint: result.metadata?.routeHint
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1349
|
+
await recordHubShadowCompareDiff({
|
|
1350
|
+
requestId: derivedRequestId,
|
|
1351
|
+
entryEndpoint,
|
|
1352
|
+
routeHint,
|
|
1353
|
+
excludedProviderKeys,
|
|
1354
|
+
baselineMode: this.hubShadowCompareConfig.baselineMode,
|
|
1355
|
+
candidateMode: typeof shadow?.candidateMode === 'string' ? shadow.candidateMode : (this.hubPolicyMode ?? undefined),
|
|
1356
|
+
baselineOut,
|
|
1357
|
+
candidateOut
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
catch (error) {
|
|
1361
|
+
// eslint-disable-next-line no-console
|
|
1362
|
+
console.error('[unified-hub-shadow-runtime] baseline compare failed:', error);
|
|
1363
|
+
}
|
|
1364
|
+
})();
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
catch {
|
|
1368
|
+
// best-effort only
|
|
1369
|
+
}
|
|
1370
|
+
// llms-engine: runtime black-box shadow compare (TS vs engine) for hub pipeline.
|
|
1371
|
+
if (wantsLlmsEngineShadow) {
|
|
1372
|
+
const cloneJsonSafe = (value) => {
|
|
1373
|
+
try {
|
|
1374
|
+
return JSON.parse(JSON.stringify(value));
|
|
1375
|
+
}
|
|
1376
|
+
catch {
|
|
1377
|
+
return value;
|
|
1378
|
+
}
|
|
1379
|
+
};
|
|
1380
|
+
const entryEndpoint = String(input.entryEndpoint || '/v1/chat/completions');
|
|
1381
|
+
const routeHint = typeof metadata.routeHint === 'string'
|
|
1382
|
+
? String(metadata.routeHint)
|
|
1383
|
+
: undefined;
|
|
1384
|
+
const baselineOut = {
|
|
1385
|
+
providerPayload: cloneJsonSafe(result.providerPayload),
|
|
1386
|
+
target: cloneJsonSafe(result.target),
|
|
1387
|
+
metadata: {
|
|
1388
|
+
entryEndpoint: result.metadata?.entryEndpoint,
|
|
1389
|
+
providerProtocol: result.metadata?.providerProtocol,
|
|
1390
|
+
processMode: result.metadata?.processMode,
|
|
1391
|
+
stream: result.metadata?.stream,
|
|
1392
|
+
routeHint: result.metadata?.routeHint
|
|
1393
|
+
}
|
|
1394
|
+
};
|
|
1395
|
+
void (async () => {
|
|
1396
|
+
try {
|
|
1397
|
+
const shadowPipeline = await this.ensureHubPipelineEngineShadow();
|
|
1398
|
+
const shadowRequestId = `${input.requestId}__llms_engine_shadow`;
|
|
1399
|
+
const baseMeta = pipelineInput.metadata;
|
|
1400
|
+
const shadowInput = {
|
|
1401
|
+
...pipelineInput,
|
|
1402
|
+
id: shadowRequestId,
|
|
1403
|
+
endpoint: input.entryEndpoint,
|
|
1404
|
+
metadata: {
|
|
1405
|
+
...(baseMeta && typeof baseMeta === 'object' ? baseMeta : {}),
|
|
1406
|
+
__llmsEngineShadow: { baselineRequestId: derivedRequestId, entryEndpoint, routeHint }
|
|
1407
|
+
},
|
|
1408
|
+
payload: cloneJsonSafe(payload)
|
|
1409
|
+
};
|
|
1410
|
+
const shadowResult = await shadowPipeline.execute(shadowInput);
|
|
1411
|
+
if (!shadowResult?.providerPayload || !shadowResult?.target) {
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
const candidateOut = {
|
|
1415
|
+
providerPayload: cloneJsonSafe(shadowResult.providerPayload),
|
|
1416
|
+
target: cloneJsonSafe(shadowResult.target),
|
|
1417
|
+
metadata: {
|
|
1418
|
+
entryEndpoint: shadowResult.metadata?.entryEndpoint,
|
|
1419
|
+
providerProtocol: shadowResult.metadata?.providerProtocol,
|
|
1420
|
+
processMode: shadowResult.metadata?.processMode,
|
|
1421
|
+
stream: shadowResult.metadata?.stream,
|
|
1422
|
+
routeHint: shadowResult.metadata?.routeHint
|
|
1423
|
+
}
|
|
1424
|
+
};
|
|
1425
|
+
await recordLlmsEngineShadowDiff({
|
|
1426
|
+
group: 'hub-pipeline',
|
|
1427
|
+
requestId: derivedRequestId,
|
|
1428
|
+
subpath: 'conversion/hub/pipeline',
|
|
1429
|
+
baselineImpl: 'ts',
|
|
1430
|
+
candidateImpl: 'engine',
|
|
1431
|
+
baselineOut,
|
|
1432
|
+
candidateOut
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
catch (error) {
|
|
1436
|
+
// eslint-disable-next-line no-console
|
|
1437
|
+
console.error('[llms-engine-shadow] hub pipeline shadow failed:', error);
|
|
1438
|
+
}
|
|
1439
|
+
})();
|
|
1440
|
+
}
|
|
1190
1441
|
return {
|
|
1191
1442
|
requestId: derivedRequestId,
|
|
1192
1443
|
providerPayload: result.providerPayload,
|
|
@@ -1209,6 +1460,8 @@ export class RouteCodexHttpServer {
|
|
|
1209
1460
|
: inboundOriginator;
|
|
1210
1461
|
const routeHint = this.extractRouteHint(input) ?? userMeta.routeHint;
|
|
1211
1462
|
const processMode = userMeta.processMode || 'chat';
|
|
1463
|
+
const runtimeFromUser = asRecord(userMeta.runtime);
|
|
1464
|
+
const llmsVersion = resolveLlmswitchCoreVersion();
|
|
1212
1465
|
const metadata = {
|
|
1213
1466
|
...userMeta,
|
|
1214
1467
|
entryEndpoint: input.entryEndpoint,
|
|
@@ -1217,6 +1470,15 @@ export class RouteCodexHttpServer {
|
|
|
1217
1470
|
stage: 'inbound',
|
|
1218
1471
|
routeHint,
|
|
1219
1472
|
stream: userMeta.stream === true,
|
|
1473
|
+
runtime: {
|
|
1474
|
+
...(runtimeFromUser ?? {}),
|
|
1475
|
+
routecodex: {
|
|
1476
|
+
version: buildInfo.version,
|
|
1477
|
+
mode: buildInfo.mode
|
|
1478
|
+
},
|
|
1479
|
+
llmswitchCore: llmsVersion ? { version: llmsVersion } : undefined,
|
|
1480
|
+
node: { version: process.version }
|
|
1481
|
+
},
|
|
1220
1482
|
...(resolvedUserAgent ? { userAgent: resolvedUserAgent } : {}),
|
|
1221
1483
|
...(resolvedOriginator ? { clientOriginator: resolvedOriginator } : {})
|
|
1222
1484
|
};
|
|
@@ -1244,19 +1506,12 @@ export class RouteCodexHttpServer {
|
|
|
1244
1506
|
}
|
|
1245
1507
|
// 在 Host 入口统一解析会话标识,后续 HubPipeline / servertool 等模块仅依赖
|
|
1246
1508
|
// sessionId / conversationId 字段,不再重复解析 clientHeaders。
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
const identifiers = extractSessionIdentifiersFromMetadata(metadata);
|
|
1251
|
-
if (identifiers.sessionId) {
|
|
1252
|
-
metadata.sessionId = identifiers.sessionId;
|
|
1253
|
-
}
|
|
1254
|
-
if (identifiers.conversationId) {
|
|
1255
|
-
metadata.conversationId = identifiers.conversationId;
|
|
1256
|
-
}
|
|
1509
|
+
const identifiers = extractSessionIdentifiersFromMetadata(metadata);
|
|
1510
|
+
if (identifiers.sessionId) {
|
|
1511
|
+
metadata.sessionId = identifiers.sessionId;
|
|
1257
1512
|
}
|
|
1258
|
-
|
|
1259
|
-
|
|
1513
|
+
if (identifiers.conversationId) {
|
|
1514
|
+
metadata.conversationId = identifiers.conversationId;
|
|
1260
1515
|
}
|
|
1261
1516
|
return metadata;
|
|
1262
1517
|
}
|
|
@@ -1468,7 +1723,6 @@ export class RouteCodexHttpServer {
|
|
|
1468
1723
|
const reenterPipeline = async (reenterOpts) => {
|
|
1469
1724
|
const nestedEntry = reenterOpts.entryEndpoint || options.entryEndpoint || entry;
|
|
1470
1725
|
const nestedExtra = asRecord(reenterOpts.metadata) ?? {};
|
|
1471
|
-
const nestedEntryLower = nestedEntry.toLowerCase();
|
|
1472
1726
|
// 基于首次 HubPipeline metadata + 调用方注入的 metadata 构建新的请求 metadata。
|
|
1473
1727
|
// 不在 Host 层编码 servertool/web_search 等语义,由 llmswitch-core 负责。
|
|
1474
1728
|
const nestedMetadata = {
|
|
@@ -1484,22 +1738,6 @@ export class RouteCodexHttpServer {
|
|
|
1484
1738
|
delete nestedMetadata.clientHeaders;
|
|
1485
1739
|
delete nestedMetadata.clientRequestId;
|
|
1486
1740
|
}
|
|
1487
|
-
// 针对 reenterPipeline 的入口端点,纠正 providerProtocol,避免沿用外层协议。
|
|
1488
|
-
if (nestedEntryLower.includes('/v1/chat/completions')) {
|
|
1489
|
-
nestedMetadata.providerProtocol = 'openai-chat';
|
|
1490
|
-
}
|
|
1491
|
-
else if (nestedEntryLower.includes('/v1/responses')) {
|
|
1492
|
-
nestedMetadata.providerProtocol = 'openai-responses';
|
|
1493
|
-
}
|
|
1494
|
-
else if (nestedEntryLower.includes('/v1/messages')) {
|
|
1495
|
-
nestedMetadata.providerProtocol = 'anthropic-messages';
|
|
1496
|
-
}
|
|
1497
|
-
const followupProtocol = typeof nestedExtra.serverToolFollowupProtocol === 'string'
|
|
1498
|
-
? nestedExtra.serverToolFollowupProtocol
|
|
1499
|
-
: undefined;
|
|
1500
|
-
if (followupProtocol) {
|
|
1501
|
-
nestedMetadata.providerProtocol = followupProtocol;
|
|
1502
|
-
}
|
|
1503
1741
|
const nestedInput = {
|
|
1504
1742
|
entryEndpoint: nestedEntry,
|
|
1505
1743
|
method: 'POST',
|