@jsonstudio/rcc 0.89.1205 → 0.89.1457

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