@jsonstudio/rcc 0.89.3 → 0.89.164

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 (270) hide show
  1. package/README.md +240 -179
  2. package/config/modules.json +1 -11
  3. package/dist/build-info.js +2 -2
  4. package/dist/build-info.js.map +1 -1
  5. package/dist/client/gemini-cli/gemini-cli-protocol-client.d.ts +16 -0
  6. package/dist/client/gemini-cli/gemini-cli-protocol-client.js +56 -0
  7. package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -0
  8. package/dist/client/openai/chat-protocol-client.js.map +1 -1
  9. package/dist/config/modules.json +1 -11
  10. package/dist/core/provider-health-manager.d.ts +17 -0
  11. package/dist/core/provider-health-manager.js +66 -0
  12. package/dist/core/provider-health-manager.js.map +1 -0
  13. package/dist/error-handling/route-error-hub.d.ts +48 -0
  14. package/dist/error-handling/route-error-hub.js +131 -0
  15. package/dist/error-handling/route-error-hub.js.map +1 -0
  16. package/dist/index.js +26 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/modules/llmswitch/bridge.d.ts +2 -0
  19. package/dist/modules/llmswitch/bridge.js +17 -0
  20. package/dist/modules/llmswitch/bridge.js.map +1 -1
  21. package/dist/modules/pipeline/utils/colored-logger.d.ts +14 -0
  22. package/dist/modules/pipeline/utils/colored-logger.js +48 -0
  23. package/dist/modules/pipeline/utils/colored-logger.js.map +1 -0
  24. package/dist/modules/pipeline/utils/debug-logger.d.ts +2 -0
  25. package/dist/modules/pipeline/utils/debug-logger.js +36 -0
  26. package/dist/modules/pipeline/utils/debug-logger.js.map +1 -1
  27. package/dist/providers/auth/gemini-cli-userinfo-helper.d.ts +53 -0
  28. package/dist/providers/auth/gemini-cli-userinfo-helper.js +152 -0
  29. package/dist/providers/auth/gemini-cli-userinfo-helper.js.map +1 -0
  30. package/dist/providers/auth/oauth-auth.js +3 -2
  31. package/dist/providers/auth/oauth-auth.js.map +1 -1
  32. package/dist/providers/auth/oauth-lifecycle.js +21 -20
  33. package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
  34. package/dist/providers/auth/oauth-logger.d.ts +1 -0
  35. package/dist/providers/auth/oauth-logger.js +21 -0
  36. package/dist/providers/auth/oauth-logger.js.map +1 -0
  37. package/dist/providers/compat/compat-directory-loader.js +2 -55
  38. package/dist/providers/compat/compat-directory-loader.js.map +1 -1
  39. package/dist/providers/compat/compatibility-factory.d.ts +4 -4
  40. package/dist/providers/compat/compatibility-factory.js +108 -0
  41. package/dist/providers/compat/compatibility-factory.js.map +1 -1
  42. package/dist/providers/compat/glm/glm-compatibility.d.ts +2 -2
  43. package/dist/providers/compat/glm/glm-compatibility.js +7 -7
  44. package/dist/providers/compat/glm/glm-compatibility.js.map +1 -1
  45. package/dist/providers/compat/glm/index.js +0 -6
  46. package/dist/providers/compat/glm/index.js.map +1 -1
  47. package/dist/providers/compat/iflow/iflow-compatibility.d.ts +1 -1
  48. package/dist/providers/compat/iflow/iflow-compatibility.js +6 -6
  49. package/dist/providers/compat/iflow/iflow-compatibility.js.map +1 -1
  50. package/dist/providers/compat/index.d.ts +0 -6
  51. package/dist/providers/compat/index.js +0 -7
  52. package/dist/providers/compat/index.js.map +1 -1
  53. package/dist/providers/compat/lmstudio-compatibility.d.ts +2 -2
  54. package/dist/providers/compat/lmstudio-compatibility.js +4 -4
  55. package/dist/providers/compat/lmstudio-compatibility.js.map +1 -1
  56. package/dist/providers/compat/passthrough-compatibility.d.ts +1 -1
  57. package/dist/providers/compat/passthrough-compatibility.js +3 -3
  58. package/dist/providers/compat/passthrough-compatibility.js.map +1 -1
  59. package/dist/providers/compat/profiles/chat/glm/index.d.ts +6 -0
  60. package/dist/providers/compat/profiles/chat/glm/index.js +6 -0
  61. package/dist/providers/compat/profiles/chat/glm/index.js.map +1 -0
  62. package/dist/providers/compat/profiles/chat/iflow/index.d.ts +6 -0
  63. package/dist/providers/compat/profiles/chat/iflow/index.js +6 -0
  64. package/dist/providers/compat/profiles/chat/iflow/index.js.map +1 -0
  65. package/dist/providers/compat/profiles/chat/lmstudio/index.d.ts +6 -0
  66. package/dist/providers/compat/profiles/chat/lmstudio/index.js +6 -0
  67. package/dist/providers/compat/profiles/chat/lmstudio/index.js.map +1 -0
  68. package/dist/providers/compat/profiles/chat/qwen/index.d.ts +6 -0
  69. package/dist/providers/compat/profiles/chat/qwen/index.js +6 -0
  70. package/dist/providers/compat/profiles/chat/qwen/index.js.map +1 -0
  71. package/dist/providers/compat/profiles/compat/passthrough/index.d.ts +6 -0
  72. package/dist/providers/compat/profiles/compat/passthrough/index.js +6 -0
  73. package/dist/providers/compat/profiles/compat/passthrough/index.js.map +1 -0
  74. package/dist/providers/compat/profiles/responses/c4m/index.d.ts +6 -0
  75. package/dist/providers/compat/profiles/responses/c4m/index.js +6 -0
  76. package/dist/providers/compat/profiles/responses/c4m/index.js.map +1 -0
  77. package/dist/providers/compat/profiles/responses/default/index.d.ts +6 -0
  78. package/dist/providers/compat/profiles/responses/default/index.js +6 -0
  79. package/dist/providers/compat/profiles/responses/default/index.js.map +1 -0
  80. package/dist/providers/compat/profiles/responses/fai/index.d.ts +6 -0
  81. package/dist/providers/compat/profiles/responses/fai/index.js +6 -0
  82. package/dist/providers/compat/profiles/responses/fai/index.js.map +1 -0
  83. package/dist/providers/compat/profiles/responses/fc/index.d.ts +6 -0
  84. package/dist/providers/compat/profiles/responses/fc/index.js +6 -0
  85. package/dist/providers/compat/profiles/responses/fc/index.js.map +1 -0
  86. package/dist/providers/compat/qwen/index.js +0 -6
  87. package/dist/providers/compat/qwen/index.js.map +1 -1
  88. package/dist/providers/compat/qwen-compatibility.d.ts +2 -2
  89. package/dist/providers/compat/qwen-compatibility.js +4 -4
  90. package/dist/providers/compat/qwen-compatibility.js.map +1 -1
  91. package/dist/providers/compat/register-compat-module.d.ts +8 -0
  92. package/dist/providers/compat/register-compat-module.js +53 -0
  93. package/dist/providers/compat/register-compat-module.js.map +1 -0
  94. package/dist/providers/compat/responses/c4m-responses-compatibility.d.ts +6 -2
  95. package/dist/providers/compat/responses/c4m-responses-compatibility.js +85 -3
  96. package/dist/providers/compat/responses/c4m-responses-compatibility.js.map +1 -1
  97. package/dist/providers/compat/standard-compatibility-utils.js +45 -15
  98. package/dist/providers/compat/standard-compatibility-utils.js.map +1 -1
  99. package/dist/providers/core/api/provider-config.d.ts +1 -1
  100. package/dist/providers/core/api/provider-types.d.ts +3 -1
  101. package/dist/providers/core/api/provider-types.js +1 -0
  102. package/dist/providers/core/api/provider-types.js.map +1 -1
  103. package/dist/providers/core/config/service-profiles.js +5 -2
  104. package/dist/providers/core/config/service-profiles.js.map +1 -1
  105. package/dist/providers/core/runtime/base-provider.d.ts +3 -0
  106. package/dist/providers/core/runtime/base-provider.js +101 -6
  107. package/dist/providers/core/runtime/base-provider.js.map +1 -1
  108. package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +34 -0
  109. package/dist/providers/core/runtime/gemini-cli-http-provider.js +152 -0
  110. package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -0
  111. package/dist/providers/core/runtime/http-transport-provider.d.ts +1 -0
  112. package/dist/providers/core/runtime/http-transport-provider.js +178 -123
  113. package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
  114. package/dist/providers/core/runtime/provider-factory.d.ts +1 -1
  115. package/dist/providers/core/runtime/provider-factory.js +8 -0
  116. package/dist/providers/core/runtime/provider-factory.js.map +1 -1
  117. package/dist/providers/core/runtime/provider-runtime-metadata.d.ts +1 -0
  118. package/dist/providers/core/runtime/provider-runtime-metadata.js.map +1 -1
  119. package/dist/providers/core/runtime/responses-provider.d.ts +7 -0
  120. package/dist/providers/core/runtime/responses-provider.js +228 -12
  121. package/dist/providers/core/runtime/responses-provider.js.map +1 -1
  122. package/dist/providers/core/strategies/oauth-auth-code-flow.js +10 -9
  123. package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
  124. package/dist/providers/core/strategies/oauth-device-flow.js +10 -9
  125. package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
  126. package/dist/providers/core/utils/provider-error-reporter.js +63 -15
  127. package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
  128. package/dist/providers/core/utils/provider-type-utils.d.ts +1 -1
  129. package/dist/providers/core/utils/provider-type-utils.js +6 -1
  130. package/dist/providers/core/utils/provider-type-utils.js.map +1 -1
  131. package/dist/providers/core/utils/snapshot-writer.d.ts +10 -0
  132. package/dist/providers/core/utils/snapshot-writer.js +85 -0
  133. package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
  134. package/dist/providers/mock/mock-provider-runtime.js +44 -0
  135. package/dist/providers/mock/mock-provider-runtime.js.map +1 -1
  136. package/dist/providers/profile/provider-profile-loader.js +26 -19
  137. package/dist/providers/profile/provider-profile-loader.js.map +1 -1
  138. package/dist/providers/profile/provider-profile.d.ts +2 -2
  139. package/dist/server/handlers/chat-handler.js +9 -3
  140. package/dist/server/handlers/chat-handler.js.map +1 -1
  141. package/dist/server/handlers/handler-utils.d.ts +7 -1
  142. package/dist/server/handlers/handler-utils.js +64 -52
  143. package/dist/server/handlers/handler-utils.js.map +1 -1
  144. package/dist/server/handlers/messages-handler.js +9 -3
  145. package/dist/server/handlers/messages-handler.js.map +1 -1
  146. package/dist/server/handlers/responses-handler.js +21 -13
  147. package/dist/server/handlers/responses-handler.js.map +1 -1
  148. package/dist/server/runtime/http-server/colored-logger.d.ts +1 -0
  149. package/dist/server/runtime/http-server/colored-logger.js +33 -0
  150. package/dist/server/runtime/http-server/colored-logger.js.map +1 -0
  151. package/dist/server/runtime/http-server/index.d.ts +3 -0
  152. package/dist/server/runtime/http-server/index.js +76 -19
  153. package/dist/server/runtime/http-server/index.js.map +1 -1
  154. package/dist/server/runtime/http-server/provider-utils.d.ts +3 -1
  155. package/dist/server/runtime/http-server/provider-utils.js +12 -2
  156. package/dist/server/runtime/http-server/provider-utils.js.map +1 -1
  157. package/dist/server/runtime/http-server/request-executor.js +6 -2
  158. package/dist/server/runtime/http-server/request-executor.js.map +1 -1
  159. package/dist/server/runtime/http-server/routes.js +31 -11
  160. package/dist/server/runtime/http-server/routes.js.map +1 -1
  161. package/dist/server/runtime/http-server/types.d.ts +2 -1
  162. package/dist/utils/error-center-payload.d.ts +7 -0
  163. package/dist/utils/error-center-payload.js +67 -0
  164. package/dist/utils/error-center-payload.js.map +1 -0
  165. package/dist/utils/error-handler-registry.d.ts +7 -0
  166. package/dist/utils/error-handler-registry.js +44 -12
  167. package/dist/utils/error-handler-registry.js.map +1 -1
  168. package/node_modules/@jsonstudio/llms/dist/conversion/codecs/responses-openai-codec.js +16 -1
  169. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-glm.json +17 -0
  170. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-iflow.json +36 -0
  171. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-lmstudio.json +37 -0
  172. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-qwen.json +18 -0
  173. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/responses-c4m.json +45 -0
  174. package/node_modules/@jsonstudio/llms/dist/conversion/config/compat-profiles.json +38 -0
  175. package/node_modules/@jsonstudio/llms/dist/conversion/config/sample-config.json +314 -0
  176. package/node_modules/@jsonstudio/llms/dist/conversion/config/version-switch.json +150 -0
  177. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.d.ts +4 -0
  178. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.js +667 -0
  179. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-profile-store.d.ts +2 -0
  180. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-profile-store.js +76 -0
  181. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-types.d.ts +62 -0
  182. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-types.js +1 -0
  183. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.d.ts +2 -0
  184. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.js +110 -29
  185. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.d.ts +14 -0
  186. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +23 -0
  187. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +34 -0
  188. package/node_modules/@jsonstudio/llms/dist/conversion/hub/process/chat-process.js +4 -1
  189. package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/provider-response.js +26 -0
  190. package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.d.ts +1 -0
  191. package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.js +71 -0
  192. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-conversation-store.d.ts +35 -0
  193. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-conversation-store.js +64 -19
  194. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-filter-pipeline.d.ts +21 -0
  195. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-filter-pipeline.js +138 -22
  196. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-governor.d.ts +21 -0
  197. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-governor.js +116 -1
  198. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-mapping.js +52 -2
  199. package/node_modules/@jsonstudio/llms/dist/filters/config/openai-openai.fieldmap.json +18 -0
  200. package/node_modules/@jsonstudio/llms/dist/filters/special/request-tools-normalize.js +20 -1
  201. package/node_modules/@jsonstudio/llms/dist/guidance/index.js +6 -2
  202. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/bootstrap.js +16 -7
  203. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/classifier.js +40 -37
  204. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/default-thinking-keywords.d.ts +1 -0
  205. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/default-thinking-keywords.js +13 -0
  206. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.d.ts +39 -0
  207. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.js +52 -11
  208. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/features.js +340 -11
  209. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-counter.d.ts +2 -0
  210. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-counter.js +105 -0
  211. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.d.ts +8 -0
  212. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.js +2 -2
  213. package/node_modules/@jsonstudio/llms/dist/sse/sse-to-json/builders/response-builder.d.ts +2 -0
  214. package/node_modules/@jsonstudio/llms/dist/sse/sse-to-json/builders/response-builder.js +53 -11
  215. package/node_modules/@jsonstudio/llms/dist/test-output/virtual-router/results.json +1 -0
  216. package/node_modules/@jsonstudio/llms/dist/test-output/virtual-router/summary.json +12 -0
  217. package/node_modules/@jsonstudio/llms/dist/tools/tool-registry.js +4 -3
  218. package/node_modules/@jsonstudio/llms/package.json +3 -3
  219. package/package.json +11 -9
  220. package/scripts/analyze-routing-classifier.mjs +166 -0
  221. package/scripts/analyze-routing-samples.mjs +216 -0
  222. package/scripts/analyze-thinking-keywords.mjs +17 -2
  223. package/scripts/build-core.mjs +8 -0
  224. package/scripts/classify-sample-tools.mjs +252 -0
  225. package/scripts/ensure-llmswitch-mode.mjs +95 -0
  226. package/scripts/gen-build-info.mjs +58 -4
  227. package/scripts/install-global.sh +1 -1
  228. package/scripts/install-release.sh +7 -0
  229. package/scripts/mock-provider/run-regressions.mjs +60 -14
  230. package/scripts/tests/apply-patch-loop.mjs +100 -9
  231. package/scripts/tests/golden-provider-cycle.mjs +12 -1
  232. package/scripts/tests/responses-provider-dry-run.mjs +15 -1
  233. package/scripts/tests/virtual-router-health.mjs +12 -5
  234. package/scripts/tools/capture-provider-goldens.mjs +75 -25
  235. package/scripts/tools/responses-golden-dry-run.mjs +17 -1
  236. package/scripts/tools/responses-provider-replay.mjs +17 -1
  237. package/scripts/tools/sync-ci-goldens.mjs +131 -0
  238. package/scripts/verification/samples/openai-chat-list-local-files.json +19 -796
  239. package/scripts/verify-e2e-toolcall.mjs +52 -0
  240. package/dist/providers/compat/config/index.d.ts +0 -1
  241. package/dist/providers/compat/config/index.js +0 -5
  242. package/dist/providers/compat/config/index.js.map +0 -1
  243. package/dist/providers/compat/iflow/index.d.ts +0 -27
  244. package/dist/providers/compat/iflow/index.js +0 -32
  245. package/dist/providers/compat/iflow/index.js.map +0 -1
  246. package/dist/providers/compat/lmstudio/index.d.ts +0 -4
  247. package/dist/providers/compat/lmstudio/index.js +0 -10
  248. package/dist/providers/compat/lmstudio/index.js.map +0 -1
  249. package/dist/providers/compat/passthrough/index.d.ts +0 -4
  250. package/dist/providers/compat/passthrough/index.js +0 -9
  251. package/dist/providers/compat/passthrough/index.js.map +0 -1
  252. package/dist/providers/compat/responses/index.d.ts +0 -1
  253. package/dist/providers/compat/responses/index.js +0 -8
  254. package/dist/providers/compat/responses/index.js.map +0 -1
  255. package/dist/providers/core/composite/compat/anthropic.d.ts +0 -3
  256. package/dist/providers/core/composite/compat/anthropic.js +0 -7
  257. package/dist/providers/core/composite/compat/anthropic.js.map +0 -1
  258. package/dist/providers/core/composite/compat/gemini.d.ts +0 -3
  259. package/dist/providers/core/composite/compat/gemini.js +0 -7
  260. package/dist/providers/core/composite/compat/gemini.js.map +0 -1
  261. package/dist/providers/core/composite/compat/openai-compat-aggregator.d.ts +0 -9
  262. package/dist/providers/core/composite/compat/openai-compat-aggregator.js +0 -135
  263. package/dist/providers/core/composite/compat/openai-compat-aggregator.js.map +0 -1
  264. package/dist/providers/core/composite/compat/responses.d.ts +0 -3
  265. package/dist/providers/core/composite/compat/responses.js +0 -91
  266. package/dist/providers/core/composite/compat/responses.js.map +0 -1
  267. package/dist/providers/core/composite/provider-composite.d.ts +0 -50
  268. package/dist/providers/core/composite/provider-composite.js +0 -235
  269. package/dist/providers/core/composite/provider-composite.js.map +0 -1
  270. package/scripts/tests/apply-patch-loop.mjs.bak +0 -363
package/README.md CHANGED
@@ -1,216 +1,251 @@
1
- # RouteCodex - 多提供商OpenAI代理服务器
1
+ # RouteCodex 多提供商 AI 代理
2
2
 
3
- [![npm version](https://badge.fury.io/js/routecodex.svg)](https://badge.fury.io/js/routecodex)
3
+ [![npm version](https://badge.fury.io/js/%40jsonstudio%2Frcc.svg)](https://www.npmjs.com/package/@jsonstudio/rcc)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9+-blue.svg)](https://www.typescriptlang.org/)
6
6
 
7
- RouteCodex是一个功能强大的多提供商OpenAI代理服务器,基于配置驱动的V2架构,支持原生dry-run调试能力、动态路由分类、4层管道架构和实时监控。提供统一的API接口,无缝集成多个AI服务提供商。
8
-
9
- 当前开发版本:`0.87.1`
10
-
11
- ## LLM Switch(前后半段)总览
12
-
13
- - 前半段(Conversion)
14
- - Chat:保持 OpenAI Chat 标准;删除 stream,统一非流
15
- - Responses:instructions + input → Chat.messages(仅形状转换,不做工具治理/兜底)
16
- - Anthropic:Claude → Chat(仅形状转换)
17
- - SSE:默认不上游直通;需要时前半段合成为非流 JSON
18
-
19
- - 后半段(Chat Pipeline,唯一治理点)
20
- - 请求:canonicalize + arguments 修复 + MCP 两步暴露
21
- - Provider:仅 HTTP 转发与快照
22
- - 响应:统一 Chat 形状,工具结果与 tool_call_id 配对
23
- - Responses:从 Chat 反向映射 required_action/items(仅映射,不治理)
24
-
25
- 文档与代码参考:
26
- - 核心实现与详细说明:`sharedmodule/llmswitch-core/`
27
- - 源码文档:`sharedmodule/llmswitch-core/README.md`
28
-
29
- ### Hub Pipeline 架构(唯一入口)
30
-
31
- - **唯一入口**:HTTP handler 直接调用 `sharedmodule/llmswitch-core/dist/conversion/hub/pipeline/hub-pipeline`,本仓库不再维护自研 pipeline/blueprint。
32
- - **配置流**:`routecodex-config-loader` 读取用户配置,传给 `bootstrapVirtualRouterConfig`,由 llmswitch-core 输出 `VirtualRouterConfig + targetRuntime` 并注入 Hub Pipeline。
33
- - **节点链路(由 llmswitch-core 内部维护)**
34
- - `SSE Input`:SSE ↔ JSON 转换、旁路透传。
35
- - `Input Nodes`:解析 Chat / Responses / Messages 请求,生成 canonical `standardizedRequest`。
36
- - `Chat Process`:唯一工具治理点,处理 tool_calls、MCP 规则、上下文压缩。
37
- - `Virtual Router Process`:分类、熔断、挑选 provider,并覆写 `request.model`、写入 `target.runtimeKey`。
38
- - `Output/SSE Nodes`:把 `processedRequest` 还原为目标协议,生成 usage、SSE 流和最终响应。
39
- - **Host 职责**:`RouteCodexHttpServer` 只负责 HTTP/SSE 封装与 Provider runtime 映射,工具治理与路由决策全部在 llmswitch-core 完成。
40
-
41
- ### Reasoning / Tool 骨架
42
-
43
- - **入站统一拆分**:`sharedmodule/llmswitch-core/src/conversion/shared/reasoning-normalizer.ts` 会在 Chat/Responses/Anthropic/Gemini 入站阶段,把 `<think>/<reasoning>` 段落剥离到 `reasoning_content`,并同步处理 instructions/input/required_action。
44
- - **工具/理由写回**:`reasoning-tool-normalizer.ts` 与 `tool-call-utils.ts` 负责把 reasoning 文本中的工具片段转换为 `tool_calls`,处理 placeholder、capturedToolResults、metadata.extra-fields 等动作由 `bridge-actions.ts` 统一驱动。
45
- - **协议中性命名**:所有共享动作均使用 `messages.*`、`tools.*` 等协议无关名称(如 `messages.inject-system-instruction`、`tools.ensure-response-placeholders`)。兼容层不得新增带协议前缀的 helper。
46
- - **兼容层职责切换**:GLM/iFlow 等 compat hook 仅处理 usage、finish_reason、schema 轻量标准化,Reasoning 拆分/清理禁止下沉到 compat;若 Provider 需特殊字段,必须通过 JSON config 描述。
47
-
48
- ## 快照排查指南(命令行)
49
-
50
- - 快速查看某个请求 RID 在各阶段的顶层键/消息概况/可疑字段:
51
- - 运行:`npm run snapshot:inspect -- --rid <RID> [--endpoint openai-responses|openai-chat|anthropic-messages]`
52
- - 输出:
53
- - http-request / llmswitch.request.post / compatibility.request.post / provider.request.pre 的顶层键
54
- - messages 统计(条数、角色覆盖、是否存在 user)
55
- - 是否出现 data/metadata/stream 等可疑顶层键
56
- - 简要差异(哪个阶段新增了可疑键)
57
-
58
- ## 🔄 V2 架构特性
59
-
60
- 本仓库已完成面向生产的 V2 重构并默认启用,基于9大核心架构原则:
61
-
62
- ### 🏗️ V2 核心组件
63
-
64
- - **Compatibility V2(配置驱动)**
65
- - 位置:`src/providers/compat/glm/*`(模块化 + Hook 系统)
66
- - 职责:仅做 Provider 特定的最小字段标准化;reasoning/tool 清理统一由 conversion 骨架完成
67
- - 特性:配置驱动字段映射、GLM 专用最小清理与 1210/1214 错误兼容
68
- - 工具治理:统一在 llmswitch-core v2 处理;兼容层不进行工具语义修复/文本收割
69
-
70
- - **Provider V2(统一OpenAI标准)**
71
- - 位置:`src/providers/*`
72
- - 能力:统一 HTTP 发送、认证管理、请求/响应快照
73
- - 支持服务:OpenAI、GLM、Qwen、iFlow、LM Studio
74
- - 策略:Fail Fast 原则,无隐藏兜底机制
75
-
76
- - **LLM Switch Core(工具处理中心)**
77
- - 位置:`sharedmodule/llmswitch-core/`
78
- - 职责:工具调用统一处理(唯一入口)、文本意图收割、系统工具指引
79
- - 特性:三端一致性(Chat/Responses/Messages);arguments 三段式修复(JSON→JSON5→安全修复→"{}");必要时从文本块收割重建 tool_calls;(可选)SSE 参数聚合
80
-
81
- ## 📐 模块职责边界(Do / Don't)
82
-
83
- ### llmswitch-core(唯一工具入口)
84
- - Do
85
- - 统一工具规范:`canonicalizeChatResponseTools()` 保证 `content=null`、`finish_reason='tool_calls'`
86
- - arguments 统一修复:`jsonish.repairArgumentsToString()`(JSON/JSON5 容错 + 安全修复)
87
- - 文本收割:在“可疑+存在文本工具块”时,用 `harvestTools()` 重建标准 `tool_calls`
88
- - (可选)SSE 聚合:吞掉参数增量,在工具完成时一次性下发完整 arguments(默认关闭)
89
- - Don't
90
- - 进行 Provider 特定修复/HTTP 通信/配置管理
91
- - 将同样逻辑复制到兼容层或 Provider 层
92
-
93
- ### Compatibility(最小兼容层)
94
- - Do
95
- - Provider 字段标准化(usage/finish_reason 等)、配置驱动映射,遵守 shared 骨架输出
96
- - 1210/1214 最小兼容(GLM)
97
- - 请求侧最小黑名单(例如 GLM 删除 `tools[].function.strict`;无 tools 删除 `tool_choice`)
98
- - 响应侧最小黑名单(仅非流式):默认仅删 `usage.prompt_tokens_details.cached_tokens`
99
- - 配置:`src/providers/compat/<provider>/config/response-blacklist.json`
100
- - 关键字段保护:status/output/output_text/required_action/choices[].message.content/tool_calls/finish_reason
101
- - Don't
102
- - 工具语义修复、reasoning 拆分或文本收割(统一由 llmswitch-core 骨架处理)
103
-
104
- ### Provider V2(HTTP 通信)
105
- - Do
106
- - 统一 HTTP 发送、认证管理、快照记录
107
- - 配置驱动(baseUrl/timeout/retry/headers)
108
- - Don't
109
- - 工具语义修复/参数归一(如改写 `shell.command`)
110
- - 业务逻辑或格式转换
111
- - 默认不上游真流式(Responses 直通)
112
- - 开关(默认关闭):`ROUTECODEX_RESPONSES_UPSTREAM_SSE=1` 或 `RCC_RESPONSES_UPSTREAM_SSE=1`
113
-
114
- ### Server Endpoints(HTTP 协议层)
115
- - Do
116
- - SSE 预心跳/错误帧、HTTP 协议处理、委托到管道
117
- - Don't
118
- - 工具处理/格式转换/业务逻辑
119
-
120
- ### 🎯 9大核心架构原则
121
-
122
- 1. **统一工具处理** - 所有工具调用通过 llmswitch-core 统一入口
123
- 2. **最小兼容层** - Compatibility层仅处理provider特定字段
124
- 3. **统一工具引导** - 系统工具指引集中管理
125
- 4. **快速死亡** - Fail Fast,无隐藏fallback
126
- 5. **暴露问题** - 结构化日志,完整错误上下文
127
- 6. **清晰解决** - 单一处理路径,确定性行为
128
- 7. **功能分离** - 模块职责单一,边界清晰
129
- 8. **配置驱动** - 无硬编码,外部化配置管理
130
- 9. **模块化** - 文件大小控制,功能导向拆分
131
-
132
- ### 🔧 构建与调试
133
-
134
- **构建顺序(重要)**:
135
- ```bash
136
- # 1. 先编译共享模块
137
- npm --prefix sharedmodule/llmswitch-core run build
7
+ RouteCodex 是 JSON Studio 推出的多提供商 AI 代理,提供统一的 OpenAI / Anthropic / Responses / Gemini 入口,自动完成协议转换、工具治理、速率控制与快照审计。项目包含两个分发形态:
138
8
 
139
- # 2. 再编译根包
140
- npm run build
9
+ - **Release CLI (`@jsonstudio/rcc`)**:给终端用户的 npm 包,自带 `rcc` 命令。
10
+ - **Dev Worktree (`routecodex`)**:本仓库源码,开发者可修改、构建并贡献。
11
+
12
+ 本文档面向 release 使用者与贡献者,覆盖架构、安装、配置与常见操作。
13
+
14
+ ---
15
+
16
+ ## 架构总览
141
17
 
142
- # 3. 安装或发布
143
- npm pack && npm i -g ./routecodex-*.tgz
18
+ ### 单一执行路径
19
+
20
+ ```
21
+ HTTP Server → llmswitch-core Hub Pipeline → Provider V2 Runtime → 上游 AI API
144
22
  ```
145
23
 
146
- **调试与快照**:
147
- - 环境变量:`ROUTECODEX_HOOKS_VERBOSITY=verbose`
148
- - 快照路径:`~/.routecodex/codex-samples/{openai-chat|openai-responses|anthropic-messages}`
149
- - 完整链路:raw-request pre-llmswitch post-llmswitch → compat-pre → provider-request → provider-response → compat-post
150
- - 回放样本:`npm run replay:codex-sample -- --sample <sample.json>`(详见 `docs/codex-samples-replay.md`)可将 codex-samples 请求重新送入本地 RouteCodex,并生成对应的 JSON/SSE 日志。
24
+ - **Hub Pipeline(llmswitch-core)**:唯一的工具治理点,完成协议归一、tool call 修复、路由决策、SSE 处理。
25
+ - **Provider V2**:纯运输层,只负责认证、重试和兼容性 hook;不解析或修改用户语义。
26
+ - **Compatibility**:按 upstream 协议最小字段映射,确保 usage / finish_reason / required_action 一致。
27
+ - **Host (RouteCodexHttpServer)**:只做 HTTP/SSE 封装、配置加载与 provider 生命周期管理。
28
+
29
+ ### 模块职责矩阵
30
+
31
+ | 模块 | 代码位置 | 职责 | 禁止行为 |
32
+ | --- | --- | --- | --- |
33
+ | HTTP Server | `src/server/runtime/http-server` | Express 路由、SSE 包装、调用 Hub Pipeline | 工具决策、路由逻辑、配置拼装 |
34
+ | Hub Pipeline | `sharedmodule/llmswitch-core` | 请求标准化、tool_calls 统一处理、虚拟路由 | 进行 HTTP 请求、处理认证 |
35
+ | Provider V2 | `src/providers` | 请求签名、HTTP 发送、快照输出 | 解析/修复工具调用、修改配置 |
36
+ | Compatibility | `src/providers/compat/*` | 上下游字段映射、最小清理 | 工具解码、兜底 try/catch |
37
+
38
+ 更多细节请参考 `docs/ARCHITECTURE.md` 与 `docs/CONFIG_ARCHITECTURE.md`。
151
39
 
152
- ## 🔀 选择静态/动态流水线(V1/V2)
40
+ ---
41
+
42
+ ## 安装与升级
43
+
44
+ ### 环境要求
45
+ - Node.js 20.x(20.11 及以上,<26)
46
+ - npm 9.x 或 10.x
47
+ - macOS / Linux:bash 或 zsh
48
+ - Windows:PowerShell 5.1+ 或 Windows Terminal
153
49
 
154
- - 开关:`ROUTECODEX_PIPELINE_MODE`
155
- - 取值:`dynamic`(动态流水线,V2,默认)或 `static`(静态流水线,V1)
156
- - 兼容:历史 `ROUTECODEX_USE_V2` 已弃用,请迁移至 `ROUTECODEX_PIPELINE_MODE`
50
+ ### Release CLI(推荐)
157
51
 
158
- 示例:
52
+ > CLI 名称:`rcc`,包名:`@jsonstudio/rcc`
159
53
 
54
+ **macOS / Linux**
160
55
  ```bash
161
- # 动态流水线(V2,默认)
162
- ROUTECODEX_PIPELINE_MODE=dynamic routecodex
56
+ npm install -g @jsonstudio/rcc
57
+ rcc --version
58
+ ```
163
59
 
164
- # 静态流水线(V1)
165
- ROUTECODEX_PIPELINE_MODE=static routecodex
60
+ **Windows(PowerShell)**
61
+ ```powershell
62
+ npm install -g @jsonstudio/rcc
63
+ rcc --version
166
64
  ```
167
65
 
168
- ## 🖥️ CLI:`rcc code` 参数透传到 Claude
66
+ 安装成功后,`rcc --version` 会显示形如 `0.89.xxx (release)` 的版本信息;可通过 `npm update -g @jsonstudio/rcc` 升级,`npm uninstall -g @jsonstudio/rcc` 卸载。
67
+
68
+ ### Dev CLI(本仓库)
69
+ 开发者仍可直接在仓库根目录执行 `npm run install:global`,该脚本会构建源码并把 `routecodex` 命令安装到全局 `$PATH`,供本地调试使用。
70
+
71
+ ---
72
+
73
+ ## 默认目录结构
74
+
75
+ | 系统 | 主配置 | Provider 配置 | 日志 / 快照 |
76
+ | --- | --- | --- | --- |
77
+ | macOS / Linux | `~/.routecodex/config.json`(或 `ROUTECODEX_CONFIG_PATH` 指定路径) | `~/.routecodex/provider/<name>/config.v1.json` | `~/.routecodex/logs`、`~/.routecodex/codex-samples/*` |
78
+ | Windows | `%USERPROFILE%\.routecodex\config.json` | `%USERPROFILE%\.routecodex\provider\<name>\config.v1.json` | `%USERPROFILE%\.routecodex\logs` 等 |
79
+
80
+ RouteCodex 会按以下优先级查找配置:
81
+
82
+ 1. CLI 参数 `--config <path>`
83
+ 2. 环境变量 `ROUTECODEX_CONFIG_PATH`
84
+ 3. 默认路径(见上表)
169
85
 
170
- `rcc code` 会把紧跟在子命令 `code` 之后的参数默认传递给 Claude(Claude Code 可执行文件)。这使你可以无缝使用 Claude 自身的命令行参数,同时由 RouteCodex 代理请求到本地服务。
86
+ ---
87
+
88
+ ## 无密钥配置样本
171
89
 
172
- - 透传规则
173
- - `rcc code` 自身会消费的选项(不会透传):
174
- - `-p/--port`、`-h/--host`、`-c/--config`、`--claude-path`、`--model`、`--profile`、`--ensure-server`
175
- - 除上述选项外,`code` 后的其它参数会按原顺序透传给 Claude。
176
- - 若使用分隔符 `--`,则 `--` 之后的所有参数将不做解析、原样透传。
90
+ 仓库附带了一份不含真实密钥的示例:`samples/configs/openai-chat-sample.json`。复制到本地后,只需提供环境变量即可启动。
177
91
 
178
- - 环境与代理
179
- - `rcc code` 会为子进程设置:`ANTHROPIC_BASE_URL/ANTHROPIC_API_URL=http://<host>:<port>` 与 `ANTHROPIC_API_KEY=rcc-proxy-key`,并清理 `ANTHROPIC_AUTH_TOKEN/ANTHROPIC_TOKEN`,确保经由 RouteCodex 代理。
180
- - 可用 `--ensure-server` 在启动 Claude 前探测并尝试启动本地 RouteCodex 服务。
92
+ ```json
93
+ {
94
+ "httpserver": { "host": "127.0.0.1", "port": 5555 },
95
+ "virtualrouter": {
96
+ "providers": {
97
+ "demo.glm": {
98
+ "providerType": "openai",
99
+ "protocol": "openai-chat",
100
+ "baseUrl": "https://api.example.com/v1",
101
+ "auth": { "type": "apikey", "env": "GLM_API_KEY" },
102
+ "models": {
103
+ "glm-4.6": {
104
+ "supportsStreaming": true,
105
+ "profiles": ["glm-default"]
106
+ }
107
+ }
108
+ }
109
+ },
110
+ "routing": {
111
+ "default": ["demo.glm.glm-4.6"]
112
+ }
113
+ }
114
+ }
115
+ ```
181
116
 
182
- - 使用示例
183
- ```bash
184
- # 直接传递 Claude 自身参数(无分隔符)
185
- rcc code --model claude-3-5 -- --project ~/my/repo --editor vscode
117
+ 使用步骤:
186
118
 
187
- # 显式使用分隔符 -- 强制原样传参(推荐在复杂参数场景)
188
- rcc code -p 5506 -- --project ~/src/foo --some-claude-flag value
119
+ 1. **复制样本**
120
+ ```bash
121
+ mkdir -p ~/.routecodex
122
+ cp samples/configs/openai-chat-sample.json ~/.routecodex/config.json
123
+ ```
124
+ 2. **提供密钥(示例为环境变量)**
125
+ - macOS / Linux:`export GLM_API_KEY="sk-your-key"`
126
+ - Windows:`setx GLM_API_KEY "sk-your-key"`
127
+ 3. **启动**
128
+ ```bash
129
+ rcc start --config ~/.routecodex/config.json
130
+ ```
131
+ 4. **验证**
132
+ - 健康检查:`curl http://127.0.0.1:5555/health`
133
+ - Chat API:`curl http://127.0.0.1:5555/v1/chat/completions ...`
189
134
 
190
- # 指定 Claude 可执行文件路径
191
- rcc code --claude-path /usr/local/bin/claude -- --project ~/repo
192
- ```
135
+ > 样本仅用于演示。请把 `baseUrl` / `routing` 更新为真实 provider,再通过环境变量、`authfile-*` 或 Secret 管理工具提供密钥。
193
136
 
194
- > 提示:若透传参数与 `rcc code` 自身选项名冲突,建议使用 `--` 分隔,避免被 CLI 解析。
137
+ ### 自定义路由关键字
195
138
 
196
- ## 🚀 核心特性
139
+ 虚拟路由器内置了一组默认关键字(如 `思考/think` → `thinking` 路由,`vision/image` → `vision` 路由)。若希望在不覆盖默认词表的前提下追加命中词,可以在用户配置中加入 `virtualrouter.classifier.keywordInjections`:
197
140
 
198
- ### 🏗️ 双向4层管道架构
199
- - **LLM Switch Workflow层**: 动态路由分类、协议转换、llmswitch-core工具处理统一入口
200
- - **Compatibility层**: Provider特定字段标准化、reasoning_content处理、双向修剪转换
141
+ ```json
142
+ {
143
+ "virtualrouter": {
144
+ "classifier": {
145
+ "keywordInjections": {
146
+ "thinking": ["慢慢分析", "stepwise"],
147
+ "vision": ["截图如下"],
148
+ "background": ["context dump please"]
149
+ }
150
+ }
151
+ }
152
+ }
153
+ ```
154
+
155
+ - 字段名对应路由类别(`thinking` / `background` / `vision` / `coding`),只需写新增词条即可,默认常量会自动保留。
156
+ - 若同一词出现在多个路由,将沿用 `ROUTE_PRIORITY`(`longcontext → thinking → vision → ...`)顺序做匹配。
157
+ - 更新配置文件后重启服务即可生效。
158
+
159
+ ---
160
+
161
+ ## 快速使用
162
+
163
+ 1. **准备配置**:如上所述放置 `config.json` 或使用 `--config` 指定文件。
164
+ 2. **启动 release server**
165
+ ```bash
166
+ rcc start --config ~/.routecodex/config.json
167
+ ```
168
+ CLI 会输出健康检查地址、配置文件路径和当前版本。
169
+ 3. **调用 API**
170
+ - OpenAI Chat:`POST /v1/chat/completions`
171
+ - OpenAI Responses:`POST /v1/responses`
172
+ - Anthropic:`POST /v1/messages`
173
+ 4. **开发者模式**
174
+ - `rcc code ...`:启动 Claude Code 并把所有请求代理到本地 RouteCodex。
175
+ - `rcc start --exclusive`:独占端口,自动终止旧实例。
176
+
177
+ ---
178
+
179
+ ## 配置与密钥管理
180
+
181
+ - **AuthFile 引用**:在配置中使用 `authfile-<name>`,RouteCodex 会读取 `~/.routecodex/auth/<name>`。适用于多账号切换。
182
+ - **环境变量**:将 `auth.type` 设为 `apikey` 且 `env` 字段指定变量名,server 会在启动时解析。
183
+ - **provider profiles**:`src/providers/profile/` 定义了各 provider 允许的协议、Auth 方式及兼容 profile,可在配置中通过 `profiles` 字段引用。
184
+
185
+ 更多细节见 `docs/CONFIG_ARCHITECTURE.md`。
186
+
187
+ ---
188
+
189
+ ## 开发者工作流
190
+
191
+ 1. **克隆仓库并安装依赖**
192
+ ```bash
193
+ git clone https://github.com/jsonstudio/routecodex.git
194
+ cd routecodex
195
+ npm install
196
+ ```
197
+ 2. **构建 sharedmodule(必要)**
198
+ ```bash
199
+ npm --prefix sharedmodule/llmswitch-core run build
200
+ ```
201
+ 3. **编译与验证**
202
+ ```bash
203
+ npm run build:dev # 生成 dist 并执行工具链验证
204
+ npm run install:global # 安装本地版 routecodex CLI
205
+ ```
206
+ 4. **与 release 区分**
207
+ - Release:使用 npm 安装 `@jsonstudio/rcc`
208
+ - Dev:仓库内 `routecodex` CLI,支持 `npm run start:bg` 等脚本
209
+
210
+ ---
211
+
212
+ ## 故障排查
213
+
214
+ | 症状 | 检查点 |
215
+ | --- | --- |
216
+ | `config:core:run` 提示缺失 | Release CLI 默认跳过动态 pipeline 生成;自定义流程可设置 `config:core:run` 脚本。 |
217
+ | SSE 变为 JSON | 检查入口 `stream` 字段与客户端 `Accept` 头;RouteCodex 会根据 inbound 请求保持一致。 |
218
+ | usage 始终 100% | 确保配置启用了对应 provider 的 `supportsStreaming`,并检查 `~/.routecodex/codex-samples/*` 快照确认 usage 字段已写入。 |
219
+ | Release install 验证失败 | 查看 `/tmp/routecodex-release-verify-*.log`;脚本位于 `scripts/install-verify.mjs`,可单独执行 `node scripts/install-verify.mjs --launcher cli --cli-binary rcc ...`。 |
220
+
221
+ ---
222
+
223
+ ## 参考文档
224
+
225
+ - `docs/ARCHITECTURE.md` – 全量架构细节与数据流
226
+ - `docs/CONFIG_ARCHITECTURE.md` – 配置解析、authfile、虚拟路由
227
+ - `docs/pipeline-routing-report.md` – Hub Pipeline 节点详解
228
+ - `docs/codex-samples-replay.md` – 快照与回放说明
229
+
230
+ 如需提交问题或贡献代码,请查看 `CONTRIBUTING.md`(若不存在可参考 Issues 模板)并遵守 `AGENTS.md` 中的 V2 工作约定。
201
231
  - **Provider层**: 统一HTTP通信、认证管理、连接池优化、双向请求响应处理
202
232
  - **External AI Service层**: 多提供商AI模型支持、性能监控、双向数据流
203
233
 
204
234
  ### 🔧 智能路由系统
205
235
  支持7种动态路由类别,自动选择最优处理流水线:
206
236
  - `default`: 标准请求路由
207
- - `longcontext`: 长文本处理请求
237
+ - `longcontext`: 长文本处理请求(tiktoken 统计超过 180k token 时切向 ≥256k provider,例如 fai/c4m)
208
238
  - `thinking`: 复杂推理请求
209
239
  - `background`: 后台处理请求
210
240
  - `websearch`: 网络搜索请求
211
241
  - `vision`: 图像处理请求
212
242
  - `coding`: 代码生成请求
213
243
 
244
+ **强制路由/模型标签(请求文本内插入 `<**...**>`)**
245
+ - `<**thinking|coding|tools|vision|websearch|longcontext|background**>`:强制命中对应路由,忽略其它关键词。
246
+ - `<**provider.model**>`:强制命中某个 provider 模型(如 `<**c4m.gpt-5.1-codex**>`,当 provider 存在并健康时直接命中)。
247
+ - 标签在路由阶段被剥离,真实请求不会把控制标签透传给上游。
248
+
214
249
  ### 🛠️ Provider V2架构
215
250
  完全重构的Provider系统,提供:
216
251
  - 统一的OpenAI标准接口(支持5大提供商)
@@ -509,12 +544,16 @@ curl -X POST http://localhost:5506/v1/chat/completions \
509
544
  "longcontext": {
510
545
  "targets": [
511
546
  {
512
- "providerId": "anthropic-provider",
513
- "modelId": "claude-3-5-sonnet-20241022"
547
+ "providerId": "fai-provider",
548
+ "modelId": "gpt-5.1-codex"
549
+ },
550
+ {
551
+ "providerId": "c4m-provider",
552
+ "modelId": "gpt-5.1-codex"
514
553
  }
515
554
  ],
516
555
  "triggers": [
517
- {"type": "token_count", "threshold": 100000},
556
+ {"type": "token_count", "threshold": 180000},
518
557
  {"type": "content_type", "value": "document"}
519
558
  ]
520
559
  },
@@ -969,6 +1008,12 @@ npm run test:coverage
969
1008
 
970
1009
  # 运行性能测试
971
1010
  npm run test:performance
1011
+
1012
+ # 黄金样本 + Mock 回归(覆盖 chat/responses/anthropic)
1013
+ npm run test:golden
1014
+
1015
+ # 将 ~/.routecodex/golden_samples/new/** 同步到仓库内的 samples/ci-goldens/**
1016
+ npm run sync:ci-goldens
972
1017
  ```
973
1018
 
974
1019
  #### Provider 专项测试
@@ -982,6 +1027,22 @@ npm run test:performance
982
1027
 
983
1028
  > 建议在跑专项测试前设置 `RCC_TEST_FAKE_OPENAI_COMPAT=1` 等 mock 环境变量,以避免真实兼容模块加载 import.meta。
984
1029
 
1030
+ #### 黄金样本库与 Mock 测试
1031
+
1032
+ `samples/ci-goldens/<entry>/<provider>/` 随仓库提供一套最小聊天请求,确保在完全离线的 CI
1033
+ 环境也能复现工具字段、system 块与 streaming 行为。`npm run test:golden` 会:
1034
+
1035
+ 1. 执行 `scripts/tools/capture-provider-goldens.mjs --custom-only --update-golden`,把
1036
+ `~/.routecodex/golden_samples/new/**` 或 `samples/ci-goldens/**` 中的最新请求复制到
1037
+ `~/.routecodex/golden_samples/provider_golden_samples/`;
1038
+ 2. 执行 `scripts/mock-provider/run-regressions.mjs`,通过 mock provider 跑完整的
1039
+ chat/responses/anthropic 回归。
1040
+
1041
+ 若本地存在 `~/.routecodex/codex-samples`,脚本会提示额外运行
1042
+ `node scripts/mock-provider/capture-from-configs.mjs` 把真实 provider 录制转成 mock
1043
+ 样本。若需要把最新的 `~/.routecodex/golden_samples/new/**` 同步进仓库,执行
1044
+ `npm run sync:ci-goldens`;更多细节参见 `docs/golden-ci-library.md`。
1045
+
985
1046
  ### 代码规范
986
1047
 
987
1048
  - **TypeScript**: 严格模式,完整类型定义
@@ -27,17 +27,7 @@
27
27
  "classificationConfig": {
28
28
  "confidenceThreshold": 60,
29
29
  "enableSmartRouting": true,
30
- "longContextThresholdTokens": 100000,
31
- "thinkingKeywords": [
32
- "思考",
33
- "深度思考",
34
- "逐步思考",
35
- "一步一步思考",
36
- "先思考再回答",
37
- "推理",
38
- "逻辑推理",
39
- "分析"
40
- ],
30
+ "longContextThresholdTokens": 180000,
41
31
  "backgroundKeywords": [
42
32
  "background",
43
33
  "上下文"
@@ -1,6 +1,6 @@
1
1
  export const buildInfo = {
2
2
  mode: 'release',
3
- version: '0.89.3',
4
- buildTime: '2025-12-12T04:09:13.943Z'
3
+ version: '0.89.164',
4
+ buildTime: '2025-12-17T10:31:24.219Z'
5
5
  };
6
6
  //# sourceMappingURL=build-info.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-info.js","sourceRoot":"","sources":["../src/build-info.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,SAAS,GAAc;IAClC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,QAAQ;IACjB,SAAS,EAAE,0BAA0B;CACtC,CAAC"}
1
+ {"version":3,"file":"build-info.js","sourceRoot":"","sources":["../src/build-info.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,SAAS,GAAc;IAClC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,UAAU;IACnB,SAAS,EAAE,0BAA0B;CACtC,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Gemini CLI Protocol Client
3
+ *
4
+ * 处理 Gemini CLI API 的协议层逻辑
5
+ * - 请求体构建
6
+ * - Endpoint 解析
7
+ * - Header 最终化(添加 OAuth Bearer token)
8
+ */
9
+ import type { HttpProtocolClient, ProtocolRequestPayload } from '../http-protocol-client.js';
10
+ export declare class GeminiCLIProtocolClient implements HttpProtocolClient<ProtocolRequestPayload> {
11
+ buildRequestBody(request: ProtocolRequestPayload): Record<string, unknown>;
12
+ resolveEndpoint(request: ProtocolRequestPayload, defaultEndpoint: string): string;
13
+ finalizeHeaders(headers: Record<string, string>, _request: ProtocolRequestPayload): Record<string, string>;
14
+ private extractPayload;
15
+ }
16
+ export default GeminiCLIProtocolClient;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Gemini CLI Protocol Client
3
+ *
4
+ * 处理 Gemini CLI API 的协议层逻辑
5
+ * - 请求体构建
6
+ * - Endpoint 解析
7
+ * - Header 最终化(添加 OAuth Bearer token)
8
+ */
9
+ function hasDataEnvelope(payload) {
10
+ return typeof payload === 'object' && payload !== null && 'data' in payload;
11
+ }
12
+ export class GeminiCLIProtocolClient {
13
+ buildRequestBody(request) {
14
+ const payload = this.extractPayload(request);
15
+ // 保持原生 Gemini CLI 格式
16
+ const body = { ...payload };
17
+ // 移除不必要的字段
18
+ delete body.stream;
19
+ return body;
20
+ }
21
+ resolveEndpoint(request, defaultEndpoint) {
22
+ const payload = this.extractPayload(request);
23
+ const action = payload.action || 'generateContent';
24
+ // 根据 action 返回对应的 endpoint
25
+ // generateContent, streamGenerateContent, countTokens
26
+ return `/v1internal:${action}`;
27
+ }
28
+ finalizeHeaders(headers, _request) {
29
+ const normalized = { ...headers };
30
+ // 确保包含必需的 headers
31
+ if (!normalized['User-Agent']) {
32
+ normalized['User-Agent'] = 'google-api-nodejs-client/9.15.1';
33
+ }
34
+ if (!normalized['X-Goog-Api-Client']) {
35
+ normalized['X-Goog-Api-Client'] = 'gl-node/22.17.0';
36
+ }
37
+ if (!normalized['Client-Metadata']) {
38
+ normalized['Client-Metadata'] = 'ideType=IDE_UNSPECIFIED,platform=PLATFORM_UNSPECIFIED,pluginType=GEMINI';
39
+ }
40
+ if (!normalized['Accept']) {
41
+ normalized['Accept'] = 'application/json';
42
+ }
43
+ return normalized;
44
+ }
45
+ extractPayload(request) {
46
+ if (hasDataEnvelope(request)) {
47
+ const envelopeData = request.data;
48
+ if (envelopeData && typeof envelopeData === 'object') {
49
+ return envelopeData;
50
+ }
51
+ }
52
+ return { ...request };
53
+ }
54
+ }
55
+ export default GeminiCLIProtocolClient;
56
+ //# sourceMappingURL=gemini-cli-protocol-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-cli-protocol-client.js","sourceRoot":"","sources":["../../../src/client/gemini-cli/gemini-cli-protocol-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAkBH,SAAS,eAAe,CAAC,OAA+B;IACtD,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,MAAM,IAAI,OAAO,CAAC;AAC9E,CAAC;AAED,MAAM,OAAO,uBAAuB;IAClC,gBAAgB,CAAC,OAA+B;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAE7C,qBAAqB;QACrB,MAAM,IAAI,GAAqB,EAAE,GAAG,OAAO,EAAE,CAAC;QAE9C,WAAW;QACX,OAAQ,IAAY,CAAC,MAAM,CAAC;QAE5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,eAAe,CAAC,OAA+B,EAAE,eAAuB;QACtE,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAI,OAAO,CAAC,MAAiB,IAAI,iBAAiB,CAAC;QAE/D,2BAA2B;QAC3B,sDAAsD;QACtD,OAAO,eAAe,MAAM,EAAE,CAAC;IACjC,CAAC;IAED,eAAe,CACb,OAA+B,EAC/B,QAAgC;QAEhC,MAAM,UAAU,GAA2B,EAAE,GAAG,OAAO,EAAE,CAAC;QAE1D,kBAAkB;QAClB,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC9B,UAAU,CAAC,YAAY,CAAC,GAAG,iCAAiC,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACrC,UAAU,CAAC,mBAAmB,CAAC,GAAG,iBAAiB,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACnC,UAAU,CAAC,iBAAiB,CAAC,GAAG,yEAAyE,CAAC;QAC5G,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,UAAU,CAAC,QAAQ,CAAC,GAAG,kBAAkB,CAAC;QAC5C,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;IAEO,cAAc,CAAC,OAA+B;QACpD,IAAI,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;YAClC,IAAI,YAAY,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;gBACrD,OAAO,YAAgC,CAAC;YAC1C,CAAC;QACH,CAAC;QACD,OAAO,EAAE,GAAI,OAAmC,EAAsB,CAAC;IACzE,CAAC;CACF;AAED,eAAe,uBAAuB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-protocol-client.js","sourceRoot":"","sources":["../../../src/client/openai/chat-protocol-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chat-protocol-client.js","sourceRoot":"","sources":["../../../src/client/openai/chat-protocol-client.ts"],"names":[],"mappings":"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"}
@@ -27,17 +27,7 @@
27
27
  "classificationConfig": {
28
28
  "confidenceThreshold": 60,
29
29
  "enableSmartRouting": true,
30
- "longContextThresholdTokens": 100000,
31
- "thinkingKeywords": [
32
- "思考",
33
- "深度思考",
34
- "逐步思考",
35
- "一步一步思考",
36
- "先思考再回答",
37
- "推理",
38
- "逻辑推理",
39
- "分析"
40
- ],
30
+ "longContextThresholdTokens": 180000,
41
31
  "backgroundKeywords": [
42
32
  "background",
43
33
  "上下文"
@@ -0,0 +1,17 @@
1
+ export type ProviderBlockInfo = {
2
+ reason: string;
3
+ timestamp: number;
4
+ metadata?: Record<string, unknown>;
5
+ };
6
+ export declare class ProviderHealthManager {
7
+ private readonly blocked;
8
+ private readonly rateLimitHits;
9
+ block(providerKey: string | undefined, reason: string, metadata?: Record<string, unknown>): void;
10
+ isBlocked(providerKey: string | undefined): boolean;
11
+ getBlockInfo(providerKey: string | undefined): ProviderBlockInfo | undefined;
12
+ clear(providerKey: string | undefined): void;
13
+ recordRateLimitHit(providerKey: string | undefined): number;
14
+ resetRateLimit(providerKey: string | undefined): void;
15
+ }
16
+ export declare function setProviderHealthManager(manager: ProviderHealthManager): void;
17
+ export declare function getProviderHealthManager(): ProviderHealthManager;