@jsonstudio/rcc 0.89.1205 → 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 +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/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.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 +215 -109
- 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/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/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,11 +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';
|
|
37
38
|
import { buildInfo } from '../../../build-info.js';
|
|
38
39
|
import { recordHubShadowCompareDiff, resolveHubShadowCompareConfig, shouldRunHubShadowCompare } from './hub-shadow-compare.js';
|
|
40
|
+
import { recordLlmsEngineShadowDiff, isLlmsEngineShadowEnabledForSubpath, resolveLlmsEngineShadowConfig, shouldRunLlmsEngineShadowForSubpath } from '../../../utils/llms-engine-shadow.js';
|
|
39
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
|
+
}
|
|
40
51
|
/**
|
|
41
52
|
* RouteCodex Server V2
|
|
42
53
|
*
|
|
@@ -52,7 +63,6 @@ export class RouteCodexHttpServer {
|
|
|
52
63
|
_isRunning = false;
|
|
53
64
|
// Runtime state
|
|
54
65
|
hubPipeline = null;
|
|
55
|
-
hubShadowComparePipeline = null;
|
|
56
66
|
providerHandles = new Map();
|
|
57
67
|
providerKeyToRuntimeKey = new Map();
|
|
58
68
|
pipelineLogger = createNoopPipelineLogger();
|
|
@@ -71,17 +81,18 @@ export class RouteCodexHttpServer {
|
|
|
71
81
|
stats = new StatsManager();
|
|
72
82
|
restartChain = Promise.resolve();
|
|
73
83
|
hubShadowCompareConfig = resolveHubShadowCompareConfig();
|
|
84
|
+
llmsEngineShadowConfig = resolveLlmsEngineShadowConfig();
|
|
74
85
|
hubPolicyMode = null;
|
|
86
|
+
hubPipelineEngineShadow = null;
|
|
87
|
+
hubPipelineConfigForShadow = null;
|
|
75
88
|
constructor(config) {
|
|
76
89
|
this.config = config;
|
|
77
90
|
this.app = express();
|
|
78
91
|
this.errorHandling = new QuietErrorHandlingCenter();
|
|
79
92
|
this.stageLoggingEnabled = isStageLoggingEnabled();
|
|
80
93
|
this.repoRoot = resolveRepoRoot(import.meta.url);
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
console.warn('[RouteCodexHttpServer] Super pipeline has been removed; falling back to Hub pipeline.');
|
|
84
|
-
}
|
|
94
|
+
// Ensure session-scoped routing state does not leak across server instances.
|
|
95
|
+
ensureServerScopedSessionDir(`${this.config.server.host}:${this.config.server.port}`);
|
|
85
96
|
try {
|
|
86
97
|
this.pipelineLogger = new PipelineDebugLoggerImpl({ colored: this.coloredLogger }, { enableConsoleLogging: true });
|
|
87
98
|
}
|
|
@@ -117,20 +128,11 @@ export class RouteCodexHttpServer {
|
|
|
117
128
|
/**
|
|
118
129
|
* Register Daemon Admin UI route.
|
|
119
130
|
* 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).
|
|
131
|
+
* Note: daemon-admin UI/API now uses password login (stored at ~/.routecodex/login) instead of httpserver.apikey.
|
|
122
132
|
*/
|
|
123
133
|
registerDaemonAdminUiRoute() {
|
|
124
134
|
this.app.get('/daemon/admin', async (req, res) => {
|
|
125
135
|
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
136
|
const fs = await import('node:fs/promises');
|
|
135
137
|
let html = '';
|
|
136
138
|
try {
|
|
@@ -359,6 +361,46 @@ export class RouteCodexHttpServer {
|
|
|
359
361
|
this.hubPipelineCtor = ctorFactory;
|
|
360
362
|
return this.hubPipelineCtor;
|
|
361
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
|
+
}
|
|
362
404
|
isPipelineReady() {
|
|
363
405
|
return Boolean(this.hubPipeline);
|
|
364
406
|
}
|
|
@@ -671,6 +713,40 @@ export class RouteCodexHttpServer {
|
|
|
671
713
|
...(Number.isFinite(sampleRate) ? { sampleRate } : {})
|
|
672
714
|
};
|
|
673
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
|
+
}
|
|
674
750
|
const healthModule = this.managerDaemon?.getModule('health');
|
|
675
751
|
const healthStore = healthModule?.getHealthStore();
|
|
676
752
|
if (healthStore) {
|
|
@@ -684,6 +760,9 @@ export class RouteCodexHttpServer {
|
|
|
684
760
|
const quotaModule = this.managerDaemon?.getModule('provider-quota');
|
|
685
761
|
if (this.isQuotaRoutingEnabled() && quotaModule && typeof quotaModule.getQuotaView === 'function') {
|
|
686
762
|
hubConfig.quotaView = quotaModule.getQuotaView();
|
|
763
|
+
if (typeof quotaModule.getQuotaViewReadOnly === 'function') {
|
|
764
|
+
hubConfig.quotaViewReadOnly = quotaModule.getQuotaViewReadOnly();
|
|
765
|
+
}
|
|
687
766
|
}
|
|
688
767
|
if (!this.hubPipeline) {
|
|
689
768
|
this.hubPipeline = new hubCtor(hubConfig);
|
|
@@ -702,37 +781,9 @@ export class RouteCodexHttpServer {
|
|
|
702
781
|
}
|
|
703
782
|
this.hubPipeline.updateVirtualRouterConfig(bootstrapArtifacts.config);
|
|
704
783
|
}
|
|
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
|
-
}
|
|
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;
|
|
736
787
|
await this.initializeProviderRuntimes(bootstrapArtifacts);
|
|
737
788
|
}
|
|
738
789
|
buildHandlerContext() {
|
|
@@ -962,11 +1013,12 @@ export class RouteCodexHttpServer {
|
|
|
962
1013
|
}
|
|
963
1014
|
const pipelineLabel = 'hub';
|
|
964
1015
|
const iterationMetadata = initialMetadata;
|
|
965
|
-
|
|
966
|
-
// 单次 HTTP
|
|
1016
|
+
// _followupTriggered = false;
|
|
1017
|
+
// 单次 HTTP 请求内允许多次 failover(不在 Provider 层做重试):
|
|
967
1018
|
// - 让 VirtualRouter 根据 excludedProviderKeys 跳过失败目标
|
|
968
1019
|
// - 避免客户端“一次就断”导致对话破裂(尤其是 429 / prompt too long 等可恢复错误)
|
|
969
|
-
|
|
1020
|
+
// - 通过 env 允许按部署/客户端调整:ROUTECODEX_MAX_PROVIDER_ATTEMPTS / RCC_MAX_PROVIDER_ATTEMPTS
|
|
1021
|
+
const maxAttempts = resolveMaxProviderAttempts();
|
|
970
1022
|
let attempt = 0;
|
|
971
1023
|
let firstError = null;
|
|
972
1024
|
const originalBodySnapshot = this.cloneRequestPayload(input.body);
|
|
@@ -1140,9 +1192,13 @@ export class RouteCodexHttpServer {
|
|
|
1140
1192
|
const sessionId = typeof mergedMetadata.sessionId === "string" && mergedMetadata.sessionId.trim()
|
|
1141
1193
|
? mergedMetadata.sessionId.trim()
|
|
1142
1194
|
: undefined;
|
|
1143
|
-
|
|
1195
|
+
let conversationId = typeof mergedMetadata.conversationId === "string" && mergedMetadata.conversationId.trim()
|
|
1144
1196
|
? mergedMetadata.conversationId.trim()
|
|
1145
1197
|
: undefined;
|
|
1198
|
+
// 对称补齐:如果只有 session_id,则回传 conversation_id=session_id
|
|
1199
|
+
if (!conversationId && sessionId) {
|
|
1200
|
+
conversationId = sessionId;
|
|
1201
|
+
}
|
|
1146
1202
|
if (sessionId || conversationId) {
|
|
1147
1203
|
if (!converted.headers) {
|
|
1148
1204
|
converted.headers = {};
|
|
@@ -1205,11 +1261,18 @@ export class RouteCodexHttpServer {
|
|
|
1205
1261
|
throw new Error('Hub pipeline runtime is not initialized');
|
|
1206
1262
|
}
|
|
1207
1263
|
const payload = asRecord(input.body);
|
|
1264
|
+
const isInternalFollowup = metadata.serverToolFollowup === true;
|
|
1265
|
+
const wantsShadowCompare = !isInternalFollowup && shouldRunHubShadowCompare(this.hubShadowCompareConfig);
|
|
1208
1266
|
const pipelineInput = {
|
|
1209
1267
|
...input,
|
|
1268
|
+
id: input.requestId,
|
|
1269
|
+
endpoint: input.entryEndpoint,
|
|
1210
1270
|
metadata: {
|
|
1211
1271
|
...metadata,
|
|
1212
|
-
logger: this.coloredLogger
|
|
1272
|
+
logger: this.coloredLogger,
|
|
1273
|
+
...(wantsShadowCompare
|
|
1274
|
+
? { __hubShadowCompare: { baselineMode: this.hubShadowCompareConfig.baselineMode } }
|
|
1275
|
+
: {})
|
|
1213
1276
|
},
|
|
1214
1277
|
payload
|
|
1215
1278
|
};
|
|
@@ -1225,13 +1288,23 @@ export class RouteCodexHttpServer {
|
|
|
1225
1288
|
const derivedRequestId = typeof resultRecord.requestId === 'string'
|
|
1226
1289
|
? resultRecord.requestId
|
|
1227
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');
|
|
1228
1299
|
// Unified Hub Framework V1: runtime black-box shadow compare (baseline policy vs current policy).
|
|
1229
|
-
// - baseline
|
|
1300
|
+
// - baseline payload is computed in the SAME hub pipeline execution (single-pass)
|
|
1230
1301
|
// - only writes errorsample when diff exists
|
|
1231
|
-
// - baseline run disables hub snapshots to avoid polluting codex-samples
|
|
1232
1302
|
try {
|
|
1233
|
-
const
|
|
1234
|
-
|
|
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') {
|
|
1235
1308
|
const entryEndpoint = String(input.entryEndpoint || '/v1/chat/completions');
|
|
1236
1309
|
const routeHint = typeof metadata.routeHint === 'string'
|
|
1237
1310
|
? String(metadata.routeHint)
|
|
@@ -1260,31 +1333,17 @@ export class RouteCodexHttpServer {
|
|
|
1260
1333
|
};
|
|
1261
1334
|
void (async () => {
|
|
1262
1335
|
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
1336
|
const baselineOut = {
|
|
1280
|
-
providerPayload: cloneJsonSafe(
|
|
1281
|
-
target:
|
|
1337
|
+
providerPayload: cloneJsonSafe(baselineProviderPayload),
|
|
1338
|
+
target: shadow && typeof shadow === 'object' && !Array.isArray(shadow) && shadow.baselineTarget
|
|
1339
|
+
? cloneJsonSafe(shadow.baselineTarget)
|
|
1340
|
+
: cloneJsonSafe(result.target),
|
|
1282
1341
|
metadata: {
|
|
1283
|
-
entryEndpoint:
|
|
1284
|
-
providerProtocol:
|
|
1285
|
-
processMode:
|
|
1286
|
-
stream:
|
|
1287
|
-
routeHint:
|
|
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
|
|
1288
1347
|
}
|
|
1289
1348
|
};
|
|
1290
1349
|
await recordHubShadowCompareDiff({
|
|
@@ -1293,7 +1352,7 @@ export class RouteCodexHttpServer {
|
|
|
1293
1352
|
routeHint,
|
|
1294
1353
|
excludedProviderKeys,
|
|
1295
1354
|
baselineMode: this.hubShadowCompareConfig.baselineMode,
|
|
1296
|
-
candidateMode: this.hubPolicyMode ?? undefined,
|
|
1355
|
+
candidateMode: typeof shadow?.candidateMode === 'string' ? shadow.candidateMode : (this.hubPolicyMode ?? undefined),
|
|
1297
1356
|
baselineOut,
|
|
1298
1357
|
candidateOut
|
|
1299
1358
|
});
|
|
@@ -1308,6 +1367,77 @@ export class RouteCodexHttpServer {
|
|
|
1308
1367
|
catch {
|
|
1309
1368
|
// best-effort only
|
|
1310
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
|
+
}
|
|
1311
1441
|
return {
|
|
1312
1442
|
requestId: derivedRequestId,
|
|
1313
1443
|
providerPayload: result.providerPayload,
|
|
@@ -1376,19 +1506,12 @@ export class RouteCodexHttpServer {
|
|
|
1376
1506
|
}
|
|
1377
1507
|
// 在 Host 入口统一解析会话标识,后续 HubPipeline / servertool 等模块仅依赖
|
|
1378
1508
|
// 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
|
-
}
|
|
1509
|
+
const identifiers = extractSessionIdentifiersFromMetadata(metadata);
|
|
1510
|
+
if (identifiers.sessionId) {
|
|
1511
|
+
metadata.sessionId = identifiers.sessionId;
|
|
1389
1512
|
}
|
|
1390
|
-
|
|
1391
|
-
|
|
1513
|
+
if (identifiers.conversationId) {
|
|
1514
|
+
metadata.conversationId = identifiers.conversationId;
|
|
1392
1515
|
}
|
|
1393
1516
|
return metadata;
|
|
1394
1517
|
}
|
|
@@ -1600,7 +1723,6 @@ export class RouteCodexHttpServer {
|
|
|
1600
1723
|
const reenterPipeline = async (reenterOpts) => {
|
|
1601
1724
|
const nestedEntry = reenterOpts.entryEndpoint || options.entryEndpoint || entry;
|
|
1602
1725
|
const nestedExtra = asRecord(reenterOpts.metadata) ?? {};
|
|
1603
|
-
const nestedEntryLower = nestedEntry.toLowerCase();
|
|
1604
1726
|
// 基于首次 HubPipeline metadata + 调用方注入的 metadata 构建新的请求 metadata。
|
|
1605
1727
|
// 不在 Host 层编码 servertool/web_search 等语义,由 llmswitch-core 负责。
|
|
1606
1728
|
const nestedMetadata = {
|
|
@@ -1616,22 +1738,6 @@ export class RouteCodexHttpServer {
|
|
|
1616
1738
|
delete nestedMetadata.clientHeaders;
|
|
1617
1739
|
delete nestedMetadata.clientRequestId;
|
|
1618
1740
|
}
|
|
1619
|
-
// 针对 reenterPipeline 的入口端点,纠正 providerProtocol,避免沿用外层协议。
|
|
1620
|
-
if (nestedEntryLower.includes('/v1/chat/completions')) {
|
|
1621
|
-
nestedMetadata.providerProtocol = 'openai-chat';
|
|
1622
|
-
}
|
|
1623
|
-
else if (nestedEntryLower.includes('/v1/responses')) {
|
|
1624
|
-
nestedMetadata.providerProtocol = 'openai-responses';
|
|
1625
|
-
}
|
|
1626
|
-
else if (nestedEntryLower.includes('/v1/messages')) {
|
|
1627
|
-
nestedMetadata.providerProtocol = 'anthropic-messages';
|
|
1628
|
-
}
|
|
1629
|
-
const followupProtocol = typeof nestedExtra.serverToolFollowupProtocol === 'string'
|
|
1630
|
-
? nestedExtra.serverToolFollowupProtocol
|
|
1631
|
-
: undefined;
|
|
1632
|
-
if (followupProtocol) {
|
|
1633
|
-
nestedMetadata.providerProtocol = followupProtocol;
|
|
1634
|
-
}
|
|
1635
1741
|
const nestedInput = {
|
|
1636
1742
|
entryEndpoint: nestedEntry,
|
|
1637
1743
|
method: 'POST',
|