@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
@@ -0,0 +1,239 @@
1
+ import { applyErrorEvent as applyQuotaErrorEvent, createInitialQuotaState } from '../../quota/provider-quota-center.js';
2
+ import { appendProviderErrorEvent, saveProviderQuotaSnapshot } from '../../quota/provider-quota-store.js';
3
+ import { canonicalizeProviderKey } from './provider-key-normalization.js';
4
+ import { capAutoCooldownMs, capAutoCooldownUntil, extractVirtualRouterSeriesCooldown, parseQuotaResetDelayMs } from './provider-quota-daemon.cooldown.js';
5
+ import { isModelCapacityExhausted429, ProviderModelBackoffTracker } from './provider-quota-daemon.model-backoff.js';
6
+ export async function handleProviderQuotaErrorEvent(ctx, event) {
7
+ if (!ctx.quotaRoutingEnabled) {
8
+ return;
9
+ }
10
+ if (!event) {
11
+ return;
12
+ }
13
+ const code = typeof event.code === 'string' ? event.code : '';
14
+ const extracted = extractProviderKey(event);
15
+ const providerKey = extracted ? canonicalizeProviderKey(extracted) : null;
16
+ if (!providerKey) {
17
+ return;
18
+ }
19
+ const nowMs = typeof event.timestamp === 'number' && Number.isFinite(event.timestamp) && event.timestamp > 0
20
+ ? event.timestamp
21
+ : Date.now();
22
+ const previous = ctx.quotaStates.get(providerKey) ??
23
+ createInitialQuotaState(providerKey, ctx.staticConfigs.get(providerKey), nowMs);
24
+ // Manual/operator blacklist is rigid: do not override it with automated error/quota signals.
25
+ if (previous.reason === 'blacklist' && previous.blacklistUntil && nowMs < previous.blacklistUntil) {
26
+ return;
27
+ }
28
+ // Upstream capacity exhaustion is not quota depletion. Cool down the entire model series immediately
29
+ // so the router can try other models/providers instead of hammering 429s.
30
+ if (isModelCapacityExhausted429(event)) {
31
+ ctx.modelBackoff.recordCapacity429(providerKey, event, nowMs);
32
+ const cooldownUntil = ctx.modelBackoff.getActiveCooldownUntil(providerKey, nowMs) ??
33
+ (nowMs + 15_000);
34
+ const errorForQuota = {
35
+ providerKey,
36
+ httpStatus: typeof event.status === 'number' ? event.status : undefined,
37
+ code: typeof event.code === 'string' ? event.code : undefined,
38
+ fatal: false,
39
+ timestampMs: nowMs
40
+ };
41
+ const applied = applyQuotaErrorEvent(previous, errorForQuota, nowMs);
42
+ const nextState = {
43
+ ...applied,
44
+ inPool: false,
45
+ reason: 'cooldown',
46
+ cooldownUntil
47
+ };
48
+ ctx.quotaStates.set(providerKey, nextState);
49
+ ctx.schedulePersist(nowMs);
50
+ return;
51
+ }
52
+ // QUOTA_* 属于“确定性配额信号”,不进入错误 series 统计。
53
+ if (code === 'QUOTA_DEPLETED') {
54
+ const detailCarrier = (event.details && typeof event.details === 'object') ? event.details : {};
55
+ const raw = detailCarrier.virtualRouterQuotaDepleted;
56
+ const cooldownMs = raw && typeof raw === 'object' && typeof raw.cooldownMs === 'number'
57
+ ? raw.cooldownMs
58
+ : undefined;
59
+ const ttl = typeof cooldownMs === 'number' && Number.isFinite(cooldownMs) && cooldownMs > 0
60
+ ? cooldownMs
61
+ : undefined;
62
+ const cappedTtl = capAutoCooldownMs(ttl);
63
+ const nextCooldownUntil = cappedTtl ? nowMs + cappedTtl : previous.cooldownUntil;
64
+ const existingCooldownUntil = previous.cooldownUntil;
65
+ const cooldownUntil = typeof existingCooldownUntil === 'number' && typeof nextCooldownUntil === 'number' && existingCooldownUntil > nextCooldownUntil
66
+ ? existingCooldownUntil
67
+ : nextCooldownUntil;
68
+ const nextState = {
69
+ ...previous,
70
+ inPool: false,
71
+ reason: 'quotaDepleted',
72
+ cooldownUntil
73
+ };
74
+ ctx.quotaStates.set(providerKey, nextState);
75
+ ctx.schedulePersist(nowMs);
76
+ return;
77
+ }
78
+ if (code === 'QUOTA_RECOVERY') {
79
+ const withinBlacklist = previous.blacklistUntil !== null && nowMs < previous.blacklistUntil;
80
+ // QUOTA_RECOVERY should only flip providers that are waiting on an explicit quota snapshot:
81
+ // - previously quota-depleted, or
82
+ // - antigravity oauth "untracked" initial state (cooldown with no timers / no error series).
83
+ //
84
+ // It must NOT override active cooldown windows caused by real upstream failures
85
+ // (e.g. MODEL_CAPACITY_EXHAUSTED short backoff), otherwise the pool will keep hammering 429s.
86
+ const isUntrackedAntigravityOauthGate = previous.reason === 'cooldown' &&
87
+ previous.cooldownUntil === null &&
88
+ previous.blacklistUntil === null &&
89
+ previous.lastErrorSeries === null &&
90
+ previous.lastErrorCode === null &&
91
+ previous.lastErrorAtMs === null &&
92
+ previous.consecutiveErrorCount === 0;
93
+ const canRecover = previous.reason === 'quotaDepleted' || isUntrackedAntigravityOauthGate;
94
+ if (canRecover && !withinBlacklist) {
95
+ const nextState = {
96
+ ...previous,
97
+ inPool: true,
98
+ reason: 'ok',
99
+ cooldownUntil: null
100
+ };
101
+ ctx.quotaStates.set(providerKey, nextState);
102
+ ctx.schedulePersist(nowMs);
103
+ }
104
+ return;
105
+ }
106
+ // Gemini-family quota exhausted errors often carry quota reset delay.
107
+ // When present, treat as deterministic quota depletion signal rather than generic 429 backoff/blacklist.
108
+ if (typeof event.status === 'number' && event.status === 429) {
109
+ const seriesCooldown = extractVirtualRouterSeriesCooldown(event, nowMs);
110
+ if (seriesCooldown) {
111
+ const withinBlacklist = previous.blacklistUntil !== null && nowMs < previous.blacklistUntil;
112
+ // Do not override an active blacklist window (manual ops or policy).
113
+ if (withinBlacklist) {
114
+ return;
115
+ }
116
+ const isCapacityCooldown = typeof seriesCooldown.source === 'string' && seriesCooldown.source.toLowerCase().includes('capacity');
117
+ const until = capAutoCooldownUntil(seriesCooldown.until, nowMs);
118
+ const existingCooldownUntil = previous.cooldownUntil;
119
+ const cooldownUntil = typeof existingCooldownUntil === 'number' && existingCooldownUntil > until
120
+ ? existingCooldownUntil
121
+ : until;
122
+ const nextState = {
123
+ ...previous,
124
+ inPool: false,
125
+ reason: isCapacityCooldown ? 'cooldown' : 'quotaDepleted',
126
+ cooldownUntil,
127
+ lastErrorSeries: null,
128
+ lastErrorCode: null,
129
+ lastErrorAtMs: null,
130
+ consecutiveErrorCount: 0,
131
+ ...(isCapacityCooldown
132
+ ? {}
133
+ : {
134
+ blacklistUntil: null,
135
+ // deterministic quota signals should clear blacklist to avoid sticky long locks
136
+ // when upstream provides explicit reset delay.
137
+ })
138
+ };
139
+ ctx.quotaStates.set(providerKey, nextState);
140
+ ctx.schedulePersist(nowMs);
141
+ return;
142
+ }
143
+ const runtime = event.runtime;
144
+ const providerIdRaw = runtime && typeof runtime.providerId === 'string' ? runtime.providerId.trim().toLowerCase() : '';
145
+ const isQuotaProvider = providerIdRaw === 'antigravity' || providerIdRaw === 'gemini-cli';
146
+ if (isQuotaProvider) {
147
+ const ttl = parseQuotaResetDelayMs(event);
148
+ if (ttl && ttl > 0) {
149
+ const capped = capAutoCooldownMs(ttl);
150
+ const nextState = {
151
+ ...previous,
152
+ inPool: false,
153
+ reason: 'quotaDepleted',
154
+ cooldownUntil: nowMs + (capped ?? ttl),
155
+ blacklistUntil: null,
156
+ lastErrorSeries: null,
157
+ lastErrorCode: null,
158
+ lastErrorAtMs: null,
159
+ consecutiveErrorCount: 0
160
+ };
161
+ ctx.quotaStates.set(providerKey, nextState);
162
+ ctx.schedulePersist(nowMs);
163
+ return;
164
+ }
165
+ }
166
+ }
167
+ const errorForQuota = {
168
+ providerKey,
169
+ httpStatus: typeof event.status === 'number' ? event.status : undefined,
170
+ code: typeof event.code === 'string' ? event.code : undefined,
171
+ fatal: isFatalForQuota(event),
172
+ timestampMs: nowMs
173
+ };
174
+ const nextState = applyQuotaErrorEvent(previous, errorForQuota, nowMs);
175
+ ctx.quotaStates.set(providerKey, nextState);
176
+ const tsIso = new Date(nowMs).toISOString();
177
+ try {
178
+ await appendProviderErrorEvent({
179
+ ts: tsIso,
180
+ providerKey,
181
+ code: typeof errorForQuota.code === 'string' ? errorForQuota.code : undefined,
182
+ httpStatus: typeof errorForQuota.httpStatus === 'number' ? errorForQuota.httpStatus : undefined,
183
+ message: event.message,
184
+ details: {
185
+ stage: event.stage,
186
+ routeName: event.runtime.routeName,
187
+ entryEndpoint: event.runtime.entryEndpoint
188
+ }
189
+ });
190
+ }
191
+ catch {
192
+ // logging failure is non-fatal
193
+ }
194
+ try {
195
+ await saveProviderQuotaSnapshot(ctx.toSnapshotObject(), new Date(nowMs));
196
+ }
197
+ catch {
198
+ // best-effort persistence only
199
+ }
200
+ }
201
+ function extractProviderKey(event) {
202
+ const runtime = event.runtime;
203
+ const direct = runtime && typeof runtime.providerKey === 'string' && runtime.providerKey.trim()
204
+ ? runtime.providerKey.trim()
205
+ : null;
206
+ if (direct) {
207
+ return direct;
208
+ }
209
+ const target = runtime && runtime.target;
210
+ if (target && typeof target === 'object') {
211
+ const targetKey = target.providerKey;
212
+ if (typeof targetKey === 'string' && targetKey.trim()) {
213
+ return targetKey.trim();
214
+ }
215
+ }
216
+ return null;
217
+ }
218
+ function isFatalForQuota(event) {
219
+ const status = typeof event.status === 'number' ? event.status : undefined;
220
+ const code = typeof event.code === 'string' ? event.code.toUpperCase() : '';
221
+ const stage = typeof event.stage === 'string' ? event.stage.toLowerCase() : '';
222
+ if (status === 401 || status === 402 || status === 403) {
223
+ return true;
224
+ }
225
+ if (code.includes('AUTH') || code.includes('UNAUTHORIZED')) {
226
+ return true;
227
+ }
228
+ if (code.includes('CONFIG')) {
229
+ return true;
230
+ }
231
+ if (stage.includes('compat')) {
232
+ return true;
233
+ }
234
+ if (event.recoverable === false && status !== undefined && status >= 500) {
235
+ return true;
236
+ }
237
+ return false;
238
+ }
239
+ //# sourceMappingURL=provider-quota-daemon.events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-quota-daemon.events.js","sourceRoot":"","sources":["../../../../src/manager/modules/quota/provider-quota-daemon.events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,404 @@
1
+ import { getProviderErrorCenter } from '../../../modules/llmswitch/bridge.js';
2
+ import { applySuccessEvent as applyQuotaSuccessEvent, applyUsageEvent as applyQuotaUsageEvent, createInitialQuotaState, tickQuotaStateTime } from '../../quota/provider-quota-center.js';
3
+ import { saveProviderQuotaSnapshot } from '../../quota/provider-quota-store.js';
4
+ import { canonicalizeProviderKey } from './provider-key-normalization.js';
5
+ import { handleProviderQuotaErrorEvent } from './provider-quota-daemon.events.js';
6
+ import { loadProviderQuotaStates } from './provider-quota-daemon.snapshot.js';
7
+ import { buildQuotaViewEntry } from './provider-quota-daemon.view.js';
8
+ import { ProviderModelBackoffTracker } from './provider-quota-daemon.model-backoff.js';
9
+ const ERROR_PRIORITY_WINDOW_MS = readPositiveNumberFromEnv('ROUTECODEX_QUOTA_ERROR_PRIORITY_WINDOW_MS', 10 * 60_000);
10
+ export class ProviderQuotaDaemonModule {
11
+ id = 'provider-quota';
12
+ quotaStates = new Map();
13
+ staticConfigs = new Map();
14
+ modelBackoff = new ProviderModelBackoffTracker();
15
+ unsubscribe = null;
16
+ maintenanceTimer = null;
17
+ persistTimer = null;
18
+ quotaRoutingEnabled = true;
19
+ async loadSnapshotIntoMemory() {
20
+ const { quotaStates, seeded, needsPersist } = await loadProviderQuotaStates({
21
+ staticConfigs: this.staticConfigs
22
+ });
23
+ this.quotaStates = quotaStates;
24
+ const nowMs = Date.now();
25
+ if (seeded || needsPersist) {
26
+ this.schedulePersist(nowMs);
27
+ }
28
+ }
29
+ async init(context) {
30
+ this.quotaRoutingEnabled = context.quotaRoutingEnabled !== false;
31
+ try {
32
+ await this.loadSnapshotIntoMemory();
33
+ }
34
+ catch {
35
+ this.quotaStates = new Map();
36
+ }
37
+ }
38
+ async reloadFromDisk() {
39
+ await this.loadSnapshotIntoMemory();
40
+ return { loadedAt: Date.now(), providerCount: this.quotaStates.size };
41
+ }
42
+ async reset(options = {}) {
43
+ const nowMs = Date.now();
44
+ this.quotaStates = new Map();
45
+ if (this.staticConfigs.size) {
46
+ for (const [providerKey, cfg] of this.staticConfigs.entries()) {
47
+ this.quotaStates.set(providerKey, createInitialQuotaState(providerKey, cfg, nowMs));
48
+ }
49
+ }
50
+ const persisted = options.persist !== false;
51
+ if (persisted) {
52
+ try {
53
+ await saveProviderQuotaSnapshot(this.toSnapshotObject(), new Date(nowMs));
54
+ }
55
+ catch {
56
+ // ignore persistence failure
57
+ }
58
+ }
59
+ return { resetAt: nowMs, persisted };
60
+ }
61
+ async resetProvider(providerKey) {
62
+ const raw = typeof providerKey === 'string' ? providerKey.trim() : '';
63
+ const key = raw ? canonicalizeProviderKey(raw) : '';
64
+ if (!key) {
65
+ return null;
66
+ }
67
+ const nowMs = Date.now();
68
+ const next = createInitialQuotaState(key, this.staticConfigs.get(key), nowMs);
69
+ this.quotaStates.set(key, next);
70
+ try {
71
+ await saveProviderQuotaSnapshot(this.toSnapshotObject(), new Date(nowMs));
72
+ }
73
+ catch {
74
+ // ignore persistence failure
75
+ }
76
+ return { providerKey: key, state: next };
77
+ }
78
+ async recoverProvider(providerKey) {
79
+ const raw = typeof providerKey === 'string' ? providerKey.trim() : '';
80
+ const key = raw ? canonicalizeProviderKey(raw) : '';
81
+ if (!key) {
82
+ return null;
83
+ }
84
+ const nowMs = Date.now();
85
+ const previous = this.quotaStates.get(key) ?? createInitialQuotaState(key, this.staticConfigs.get(key), nowMs);
86
+ const next = {
87
+ ...previous,
88
+ inPool: true,
89
+ reason: 'ok',
90
+ cooldownUntil: null,
91
+ blacklistUntil: null,
92
+ lastErrorSeries: null,
93
+ lastErrorCode: null,
94
+ lastErrorAtMs: null,
95
+ consecutiveErrorCount: 0
96
+ };
97
+ this.quotaStates.set(key, next);
98
+ try {
99
+ await saveProviderQuotaSnapshot(this.toSnapshotObject(), new Date(nowMs));
100
+ }
101
+ catch {
102
+ // ignore persistence failure
103
+ }
104
+ return { providerKey: key, state: next };
105
+ }
106
+ async disableProvider(options) {
107
+ const raw = typeof options?.providerKey === 'string' ? options.providerKey.trim() : '';
108
+ const key = raw ? canonicalizeProviderKey(raw) : '';
109
+ if (!key) {
110
+ return null;
111
+ }
112
+ const durationMs = typeof options.durationMs === 'number' && Number.isFinite(options.durationMs) && options.durationMs > 0
113
+ ? Math.floor(options.durationMs)
114
+ : 0;
115
+ if (!durationMs) {
116
+ return null;
117
+ }
118
+ const mode = options.mode === 'blacklist' ? 'blacklist' : 'cooldown';
119
+ const nowMs = Date.now();
120
+ const previous = this.quotaStates.get(key) ?? createInitialQuotaState(key, this.staticConfigs.get(key), nowMs);
121
+ const next = mode === 'blacklist'
122
+ ? {
123
+ ...previous,
124
+ inPool: false,
125
+ reason: 'blacklist',
126
+ blacklistUntil: nowMs + durationMs,
127
+ cooldownUntil: null
128
+ }
129
+ : {
130
+ ...previous,
131
+ inPool: false,
132
+ reason: 'cooldown',
133
+ cooldownUntil: nowMs + durationMs
134
+ };
135
+ this.quotaStates.set(key, next);
136
+ try {
137
+ await saveProviderQuotaSnapshot(this.toSnapshotObject(), new Date(nowMs));
138
+ }
139
+ catch {
140
+ // ignore persistence failure
141
+ }
142
+ return { providerKey: key, state: next };
143
+ }
144
+ getAdminSnapshot() {
145
+ return this.toSnapshotObject();
146
+ }
147
+ async start() {
148
+ if (!this.quotaRoutingEnabled) {
149
+ return;
150
+ }
151
+ let center = null;
152
+ try {
153
+ center = await getProviderErrorCenter();
154
+ }
155
+ catch {
156
+ center = null;
157
+ }
158
+ if (center && typeof center.subscribe === 'function') {
159
+ this.unsubscribe = center.subscribe((event) => {
160
+ void this.handleProviderErrorEvent(event).catch(() => {
161
+ // swallow handler errors; quota updates are best-effort
162
+ });
163
+ });
164
+ }
165
+ const intervalMs = readPositiveNumberFromEnv('ROUTECODEX_QUOTA_DAEMON_INTERVAL_MS', 60_000);
166
+ if (intervalMs > 0) {
167
+ this.maintenanceTimer = setInterval(() => {
168
+ void this.runMaintenanceTick().catch(() => {
169
+ // ignore maintenance failures
170
+ });
171
+ }, intervalMs);
172
+ }
173
+ void this.runMaintenanceTick().catch(() => {
174
+ // ignore immediate tick failures
175
+ });
176
+ }
177
+ async stop() {
178
+ if (this.unsubscribe) {
179
+ try {
180
+ this.unsubscribe();
181
+ }
182
+ catch {
183
+ // ignore unsubscribe failures
184
+ }
185
+ this.unsubscribe = null;
186
+ }
187
+ if (this.maintenanceTimer) {
188
+ clearInterval(this.maintenanceTimer);
189
+ this.maintenanceTimer = null;
190
+ }
191
+ if (this.persistTimer) {
192
+ clearTimeout(this.persistTimer);
193
+ this.persistTimer = null;
194
+ }
195
+ if (!this.quotaRoutingEnabled) {
196
+ return;
197
+ }
198
+ try {
199
+ await saveProviderQuotaSnapshot(this.toSnapshotObject(), new Date());
200
+ }
201
+ catch {
202
+ // best-effort persistence
203
+ }
204
+ }
205
+ recordProviderUsage(event) {
206
+ if (!this.quotaRoutingEnabled) {
207
+ return;
208
+ }
209
+ const rawKey = typeof event?.providerKey === 'string' ? event.providerKey.trim() : '';
210
+ const providerKey = rawKey ? canonicalizeProviderKey(rawKey) : '';
211
+ if (!providerKey) {
212
+ return;
213
+ }
214
+ const nowMs = typeof event.timestampMs === 'number' && Number.isFinite(event.timestampMs) && event.timestampMs > 0
215
+ ? event.timestampMs
216
+ : Date.now();
217
+ const requestedTokens = typeof event.requestedTokens === 'number' && Number.isFinite(event.requestedTokens) && event.requestedTokens > 0
218
+ ? event.requestedTokens
219
+ : 0;
220
+ const previous = this.quotaStates.get(providerKey) ??
221
+ createInitialQuotaState(providerKey, this.staticConfigs.get(providerKey), nowMs);
222
+ const nextState = applyQuotaUsageEvent(previous, { providerKey, requestedTokens, timestampMs: nowMs }, nowMs);
223
+ this.quotaStates.set(providerKey, nextState);
224
+ this.schedulePersist(nowMs);
225
+ }
226
+ recordProviderSuccess(event) {
227
+ if (!this.quotaRoutingEnabled) {
228
+ return;
229
+ }
230
+ const rawKey = typeof event?.providerKey === 'string' ? event.providerKey.trim() : '';
231
+ const providerKey = rawKey ? canonicalizeProviderKey(rawKey) : '';
232
+ if (!providerKey) {
233
+ return;
234
+ }
235
+ const nowMs = typeof event.timestampMs === 'number' && Number.isFinite(event.timestampMs) && event.timestampMs > 0
236
+ ? event.timestampMs
237
+ : Date.now();
238
+ const usedTokens = typeof event.usedTokens === 'number' && Number.isFinite(event.usedTokens) && event.usedTokens > 0
239
+ ? event.usedTokens
240
+ : 0;
241
+ const previous = this.quotaStates.get(providerKey) ??
242
+ createInitialQuotaState(providerKey, this.staticConfigs.get(providerKey), nowMs);
243
+ const nextState = applyQuotaSuccessEvent(previous, { providerKey, usedTokens, timestampMs: nowMs }, nowMs);
244
+ this.quotaStates.set(providerKey, nextState);
245
+ this.modelBackoff.recordSuccess(providerKey);
246
+ this.schedulePersist(nowMs);
247
+ }
248
+ registerProviderStaticConfig(providerKey, config = {}) {
249
+ if (!this.quotaRoutingEnabled) {
250
+ return;
251
+ }
252
+ const raw = typeof providerKey === 'string' ? providerKey.trim() : '';
253
+ const key = raw ? canonicalizeProviderKey(raw) : '';
254
+ if (!key) {
255
+ return;
256
+ }
257
+ const authTypeRaw = typeof config.authType === 'string' ? config.authType.trim().toLowerCase() : '';
258
+ const authType = authTypeRaw === 'apikey' ? 'apikey' : authTypeRaw === 'oauth' ? 'oauth' : 'unknown';
259
+ const staticConfig = {
260
+ ...(typeof config.priorityTier === 'number' && Number.isFinite(config.priorityTier)
261
+ ? { priorityTier: config.priorityTier }
262
+ : {}),
263
+ authType
264
+ };
265
+ this.staticConfigs.set(key, staticConfig);
266
+ const nowMs = Date.now();
267
+ const existing = this.quotaStates.get(key);
268
+ if (existing) {
269
+ const merged = {
270
+ ...existing,
271
+ ...(staticConfig.authType ? { authType: staticConfig.authType } : {}),
272
+ ...(typeof staticConfig.priorityTier === 'number' ? { priorityTier: staticConfig.priorityTier } : {})
273
+ };
274
+ this.quotaStates.set(key, merged);
275
+ this.schedulePersist(nowMs);
276
+ return;
277
+ }
278
+ const initial = createInitialQuotaState(key, staticConfig, nowMs);
279
+ const isAntigravity = key.toLowerCase().startsWith('antigravity.');
280
+ if (isAntigravity && authType === 'oauth') {
281
+ this.quotaStates.set(key, {
282
+ ...initial,
283
+ inPool: false,
284
+ reason: 'cooldown',
285
+ cooldownUntil: null
286
+ });
287
+ }
288
+ else {
289
+ this.quotaStates.set(key, initial);
290
+ }
291
+ this.schedulePersist(nowMs);
292
+ }
293
+ async handleProviderErrorEvent(event) {
294
+ await handleProviderQuotaErrorEvent({
295
+ quotaStates: this.quotaStates,
296
+ staticConfigs: this.staticConfigs,
297
+ quotaRoutingEnabled: this.quotaRoutingEnabled,
298
+ modelBackoff: this.modelBackoff,
299
+ schedulePersist: (nowMs) => this.schedulePersist(nowMs),
300
+ toSnapshotObject: () => this.toSnapshotObject()
301
+ }, event);
302
+ }
303
+ async runMaintenanceTick() {
304
+ if (!this.quotaStates.size) {
305
+ return;
306
+ }
307
+ const nowMs = Date.now();
308
+ const updated = new Map();
309
+ for (const [providerKey, state] of this.quotaStates.entries()) {
310
+ const next = tickQuotaStateTime(state, nowMs);
311
+ updated.set(providerKey, next);
312
+ }
313
+ this.quotaStates = updated;
314
+ try {
315
+ await saveProviderQuotaSnapshot(this.toSnapshotObject(), new Date(nowMs));
316
+ }
317
+ catch {
318
+ // ignore persistence errors
319
+ }
320
+ }
321
+ schedulePersist(_nowMs) {
322
+ if (this.persistTimer) {
323
+ return;
324
+ }
325
+ const debounceMs = readPositiveNumberFromEnv('ROUTECODEX_QUOTA_PERSIST_DEBOUNCE_MS', 5_000);
326
+ this.persistTimer = setTimeout(() => {
327
+ this.persistTimer = null;
328
+ void saveProviderQuotaSnapshot(this.toSnapshotObject(), new Date()).catch(() => {
329
+ // ignore persistence errors
330
+ });
331
+ }, debounceMs);
332
+ }
333
+ toSnapshotObject() {
334
+ const result = {};
335
+ for (const [key, state] of this.quotaStates.entries()) {
336
+ result[key] = state;
337
+ }
338
+ return result;
339
+ }
340
+ getQuotaView() {
341
+ if (!this.quotaRoutingEnabled) {
342
+ return () => null;
343
+ }
344
+ return (providerKey) => {
345
+ const raw = typeof providerKey === 'string' ? providerKey.trim() : '';
346
+ const key = raw ? canonicalizeProviderKey(raw) : '';
347
+ if (!key) {
348
+ return null;
349
+ }
350
+ const state = this.quotaStates.get(key);
351
+ if (!state) {
352
+ return null;
353
+ }
354
+ const nowMs = Date.now();
355
+ const normalized = tickQuotaStateTime(state, nowMs);
356
+ if (normalized !== state) {
357
+ this.quotaStates.set(key, normalized);
358
+ this.schedulePersist(nowMs);
359
+ }
360
+ return buildQuotaViewEntry({
361
+ state: normalized,
362
+ nowMs,
363
+ modelBackoff: this.modelBackoff,
364
+ errorPriorityWindowMs: ERROR_PRIORITY_WINDOW_MS
365
+ });
366
+ };
367
+ }
368
+ getQuotaViewReadOnly() {
369
+ if (!this.quotaRoutingEnabled) {
370
+ return () => null;
371
+ }
372
+ return (providerKey) => {
373
+ const raw = typeof providerKey === 'string' ? providerKey.trim() : '';
374
+ const key = raw ? canonicalizeProviderKey(raw) : '';
375
+ if (!key) {
376
+ return null;
377
+ }
378
+ const state = this.quotaStates.get(key);
379
+ if (!state) {
380
+ return null;
381
+ }
382
+ const nowMs = Date.now();
383
+ const effective = tickQuotaStateTime(state, nowMs);
384
+ return buildQuotaViewEntry({
385
+ state: effective,
386
+ nowMs,
387
+ modelBackoff: this.modelBackoff,
388
+ errorPriorityWindowMs: ERROR_PRIORITY_WINDOW_MS
389
+ });
390
+ };
391
+ }
392
+ }
393
+ function readPositiveNumberFromEnv(name, fallback) {
394
+ const raw = process.env[name];
395
+ if (!raw) {
396
+ return fallback;
397
+ }
398
+ const parsed = Number(raw);
399
+ if (!Number.isFinite(parsed) || parsed <= 0) {
400
+ return fallback;
401
+ }
402
+ return parsed;
403
+ }
404
+ //# sourceMappingURL=provider-quota-daemon.js.map