@jsonstudio/rcc 0.89.1189 → 0.89.1348

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. package/README.md +17 -0
  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 +74 -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 +91 -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 +36 -0
  40. package/dist/cli/config/init-config.js +180 -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-cli/gemini-cli-protocol-client.js +1 -1
  51. package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -1
  52. package/dist/config/risk-control-config.d.ts +94 -0
  53. package/dist/config/risk-control-config.js +196 -0
  54. package/dist/config/risk-control-config.js.map +1 -0
  55. package/dist/constants/index.d.ts +6 -0
  56. package/dist/constants/index.js +13 -0
  57. package/dist/constants/index.js.map +1 -1
  58. package/dist/docs/daemon-admin-ui.html +2113 -190
  59. package/dist/index.js +0 -1
  60. package/dist/index.js.map +1 -1
  61. package/dist/manager/modules/health/index.d.ts +1 -1
  62. package/dist/manager/modules/quota/antigravity-quota-manager.d.ts +70 -0
  63. package/dist/manager/modules/quota/antigravity-quota-manager.js +442 -0
  64. package/dist/manager/modules/quota/antigravity-quota-manager.js.map +1 -0
  65. package/dist/manager/modules/quota/index.d.ts +3 -127
  66. package/dist/manager/modules/quota/index.js +2 -1093
  67. package/dist/manager/modules/quota/index.js.map +1 -1
  68. package/dist/manager/modules/quota/provider-key-normalization.d.ts +3 -0
  69. package/dist/manager/modules/quota/provider-key-normalization.js +155 -0
  70. package/dist/manager/modules/quota/provider-key-normalization.js.map +1 -0
  71. package/dist/manager/modules/quota/provider-quota-daemon.cooldown.d.ts +9 -0
  72. package/dist/manager/modules/quota/provider-quota-daemon.cooldown.js +115 -0
  73. package/dist/manager/modules/quota/provider-quota-daemon.cooldown.js.map +1 -0
  74. package/dist/manager/modules/quota/provider-quota-daemon.d.ts +77 -0
  75. package/dist/manager/modules/quota/provider-quota-daemon.events.d.ts +12 -0
  76. package/dist/manager/modules/quota/provider-quota-daemon.events.js +237 -0
  77. package/dist/manager/modules/quota/provider-quota-daemon.events.js.map +1 -0
  78. package/dist/manager/modules/quota/provider-quota-daemon.js +404 -0
  79. package/dist/manager/modules/quota/provider-quota-daemon.js.map +1 -0
  80. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.d.ts +11 -0
  81. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js +189 -0
  82. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js.map +1 -0
  83. package/dist/manager/modules/quota/provider-quota-daemon.snapshot.d.ts +8 -0
  84. package/dist/manager/modules/quota/provider-quota-daemon.snapshot.js +96 -0
  85. package/dist/manager/modules/quota/provider-quota-daemon.snapshot.js.map +1 -0
  86. package/dist/manager/modules/quota/provider-quota-daemon.view.d.ts +19 -0
  87. package/dist/manager/modules/quota/provider-quota-daemon.view.js +37 -0
  88. package/dist/manager/modules/quota/provider-quota-daemon.view.js.map +1 -0
  89. package/dist/manager/modules/routing/index.d.ts +1 -0
  90. package/dist/manager/modules/routing/index.js +11 -25
  91. package/dist/manager/modules/routing/index.js.map +1 -1
  92. package/dist/manager/quota/provider-quota-center.d.ts +2 -0
  93. package/dist/manager/quota/provider-quota-center.js +80 -82
  94. package/dist/manager/quota/provider-quota-center.js.map +1 -1
  95. package/dist/modules/llmswitch/bridge.d.ts +16 -18
  96. package/dist/modules/llmswitch/bridge.js +314 -71
  97. package/dist/modules/llmswitch/bridge.js.map +1 -1
  98. package/dist/modules/llmswitch/core-loader.d.ts +4 -2
  99. package/dist/modules/llmswitch/core-loader.js +32 -20
  100. package/dist/modules/llmswitch/core-loader.js.map +1 -1
  101. package/dist/modules/pipeline/utils/colored-logger.js +3 -2
  102. package/dist/modules/pipeline/utils/colored-logger.js.map +1 -1
  103. package/dist/modules/pipeline/utils/debug-logger.js +1 -1
  104. package/dist/modules/pipeline/utils/debug-logger.js.map +1 -1
  105. package/dist/providers/auth/iflow-cookie-auth.js +0 -2
  106. package/dist/providers/auth/iflow-cookie-auth.js.map +1 -1
  107. package/dist/providers/auth/oauth-lifecycle.js +2 -23
  108. package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
  109. package/dist/providers/core/config/camoufox-launcher.js +35 -4
  110. package/dist/providers/core/config/camoufox-launcher.js.map +1 -1
  111. package/dist/providers/core/runtime/antigravity-quota-client.js +6 -3
  112. package/dist/providers/core/runtime/antigravity-quota-client.js.map +1 -1
  113. package/dist/providers/core/runtime/base-provider.d.ts +2 -2
  114. package/dist/providers/core/runtime/base-provider.js +74 -69
  115. package/dist/providers/core/runtime/base-provider.js.map +1 -1
  116. package/dist/providers/core/runtime/gemini-cli-http-provider.js +6 -4
  117. package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
  118. package/dist/providers/core/runtime/http-request-executor.js +2 -2
  119. package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
  120. package/dist/providers/core/runtime/http-transport-provider.d.ts +14 -0
  121. package/dist/providers/core/runtime/http-transport-provider.js +111 -5
  122. package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
  123. package/dist/providers/core/runtime/provider-error-classifier.js +10 -0
  124. package/dist/providers/core/runtime/provider-error-classifier.js.map +1 -1
  125. package/dist/providers/core/runtime/provider-factory.js +7 -5
  126. package/dist/providers/core/runtime/provider-factory.js.map +1 -1
  127. package/dist/providers/core/runtime/provider-runtime-metadata.d.ts +6 -0
  128. package/dist/providers/core/runtime/provider-runtime-metadata.js.map +1 -1
  129. package/dist/providers/core/runtime/responses-provider.d.ts +1 -7
  130. package/dist/providers/core/runtime/responses-provider.js +12 -93
  131. package/dist/providers/core/runtime/responses-provider.js.map +1 -1
  132. package/dist/providers/core/strategies/oauth-auth-code-flow.js +12 -8
  133. package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
  134. package/dist/providers/core/utils/http-client.js +16 -3
  135. package/dist/providers/core/utils/http-client.js.map +1 -1
  136. package/dist/providers/core/utils/provider-error-logger.d.ts +1 -1
  137. package/dist/providers/core/utils/provider-error-reporter.d.ts +3 -1
  138. package/dist/providers/core/utils/provider-error-reporter.js +3 -0
  139. package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
  140. package/dist/providers/core/utils/snapshot-writer.js +1 -4
  141. package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
  142. package/dist/providers/mock/mock-provider-runtime.js +57 -27
  143. package/dist/providers/mock/mock-provider-runtime.js.map +1 -1
  144. package/dist/scripts/camoufox/launch-auth.mjs +193 -58
  145. package/dist/server/handlers/handler-utils.js +3 -2
  146. package/dist/server/handlers/handler-utils.js.map +1 -1
  147. package/dist/server/runtime/http-server/daemon-admin/auth-handler.d.ts +2 -0
  148. package/dist/server/runtime/http-server/daemon-admin/auth-handler.js +103 -0
  149. package/dist/server/runtime/http-server/daemon-admin/auth-handler.js.map +1 -0
  150. package/dist/server/runtime/http-server/daemon-admin/auth-session.d.ts +5 -0
  151. package/dist/server/runtime/http-server/daemon-admin/auth-session.js +77 -0
  152. package/dist/server/runtime/http-server/daemon-admin/auth-session.js.map +1 -0
  153. package/dist/server/runtime/http-server/daemon-admin/auth-store.d.ts +18 -0
  154. package/dist/server/runtime/http-server/daemon-admin/auth-store.js +89 -0
  155. package/dist/server/runtime/http-server/daemon-admin/auth-store.js.map +1 -0
  156. package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js +1 -2
  157. package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js.map +1 -1
  158. package/dist/server/runtime/http-server/daemon-admin/providers-handler.js +226 -24
  159. package/dist/server/runtime/http-server/daemon-admin/providers-handler.js.map +1 -1
  160. package/dist/server/runtime/http-server/daemon-admin/quota-handler.js +47 -8
  161. package/dist/server/runtime/http-server/daemon-admin/quota-handler.js.map +1 -1
  162. package/dist/server/runtime/http-server/daemon-admin/restart-handler.js +1 -1
  163. package/dist/server/runtime/http-server/daemon-admin/restart-handler.js.map +1 -1
  164. package/dist/server/runtime/http-server/daemon-admin/stats-handler.js +1 -1
  165. package/dist/server/runtime/http-server/daemon-admin/stats-handler.js.map +1 -1
  166. package/dist/server/runtime/http-server/daemon-admin/status-handler.js +68 -4
  167. package/dist/server/runtime/http-server/daemon-admin/status-handler.js.map +1 -1
  168. package/dist/server/runtime/http-server/daemon-admin-routes.d.ts +3 -4
  169. package/dist/server/runtime/http-server/daemon-admin-routes.js +9 -14
  170. package/dist/server/runtime/http-server/daemon-admin-routes.js.map +1 -1
  171. package/dist/server/runtime/http-server/executor-metadata.js +1 -1
  172. package/dist/server/runtime/http-server/executor-metadata.js.map +1 -1
  173. package/dist/server/runtime/http-server/executor-response.js +0 -16
  174. package/dist/server/runtime/http-server/executor-response.js.map +1 -1
  175. package/dist/server/runtime/http-server/hub-shadow-compare.d.ts +18 -0
  176. package/dist/server/runtime/http-server/hub-shadow-compare.js +256 -0
  177. package/dist/server/runtime/http-server/hub-shadow-compare.js.map +1 -0
  178. package/dist/server/runtime/http-server/index.d.ts +7 -2
  179. package/dist/server/runtime/http-server/index.js +287 -49
  180. package/dist/server/runtime/http-server/index.js.map +1 -1
  181. package/dist/server/runtime/http-server/middleware.js +19 -1
  182. package/dist/server/runtime/http-server/middleware.js.map +1 -1
  183. package/dist/server/runtime/http-server/request-executor.js +10 -19
  184. package/dist/server/runtime/http-server/request-executor.js.map +1 -1
  185. package/dist/server/runtime/http-server/routes.js +8 -2
  186. package/dist/server/runtime/http-server/routes.js.map +1 -1
  187. package/dist/server/runtime/http-server/session-dir.d.ts +2 -0
  188. package/dist/server/runtime/http-server/session-dir.js +59 -0
  189. package/dist/server/runtime/http-server/session-dir.js.map +1 -0
  190. package/dist/server/runtime/http-server/types.d.ts +0 -4
  191. package/dist/server/utils/utf8-chunk-buffer.js +6 -3
  192. package/dist/server/utils/utf8-chunk-buffer.js.map +1 -1
  193. package/dist/server/utils/warmup-storm-tracker.js +1 -1
  194. package/dist/server/utils/warmup-storm-tracker.js.map +1 -1
  195. package/dist/server-factory.d.ts +6 -28
  196. package/dist/server-factory.js +8 -93
  197. package/dist/server-factory.js.map +1 -1
  198. package/dist/token-daemon/index.js +2 -2
  199. package/dist/token-daemon/index.js.map +1 -1
  200. package/dist/token-daemon/provider-registry.js +0 -1
  201. package/dist/token-daemon/provider-registry.js.map +1 -1
  202. package/dist/token-daemon/server-utils.js +8 -9
  203. package/dist/token-daemon/server-utils.js.map +1 -1
  204. package/dist/token-daemon/token-utils.js +1 -1
  205. package/dist/token-daemon/token-utils.js.map +1 -1
  206. package/dist/tools/semantic-replay.js +2 -2
  207. package/dist/tools/semantic-replay.js.map +1 -1
  208. package/dist/tools/stats-request-events.d.ts +1 -1
  209. package/dist/tools/stats-usage.js +6 -3
  210. package/dist/tools/stats-usage.js.map +1 -1
  211. package/dist/utils/errorsamples.d.ts +5 -0
  212. package/dist/utils/errorsamples.js +27 -0
  213. package/dist/utils/errorsamples.js.map +1 -0
  214. package/dist/utils/llms-engine-shadow.d.ts +19 -0
  215. package/dist/utils/llms-engine-shadow.js +209 -0
  216. package/dist/utils/llms-engine-shadow.js.map +1 -0
  217. package/dist/utils/runtime-versions.d.ts +1 -0
  218. package/dist/utils/runtime-versions.js +39 -0
  219. package/dist/utils/runtime-versions.js.map +1 -0
  220. package/docs/ARCHITECTURE.md +402 -0
  221. package/docs/CODEX_AND_CLAUDE_CODE.md +69 -0
  222. package/docs/CONFIG_ARCHITECTURE.md +517 -0
  223. package/docs/ERROR_HANDLING_AUDIT.md +0 -0
  224. package/docs/GCLI2API_PARITY_GAPS.md +98 -0
  225. package/docs/INSTALLATION_AND_QUICKSTART.md +74 -0
  226. package/docs/INSTRUCTION_MARKUP.md +89 -0
  227. package/docs/MODULE_ENHANCEMENT_SYSTEM.md +666 -0
  228. package/docs/PORTS.md +36 -0
  229. package/docs/PROVIDERS_BUILTIN.md +111 -0
  230. package/docs/PROVIDER_TYPES.md +55 -0
  231. package/docs/SERVERTOOL_CLOCK_DESIGN.md +233 -0
  232. package/docs/USAGE_HANDLING_ANALYSIS.md +335 -0
  233. package/docs/USER_CONFIG_PARSER_CHANGES.md +175 -0
  234. package/docs/V3_INBOUND_OUTBOUND_DESIGN.md +86 -0
  235. package/docs/VIRTUAL_ROUTER_PRIORITY_AND_HEALTH.md +125 -0
  236. package/docs/anthropic-request-golden-samples.md +50 -0
  237. package/docs/ccr-alignment-enhancetool.md +105 -0
  238. package/docs/chat-glm-500-analysis.md +79 -0
  239. package/docs/chat-request-golden-samples.md +42 -0
  240. package/docs/chat-semantic-expansion-plan.md +82 -0
  241. package/docs/cli-command-inventory.md +76 -0
  242. package/docs/codex-samples-replay.md +50 -0
  243. package/docs/daemon-admin-api-design.md +350 -0
  244. package/docs/daemon-admin-module-structure.md +169 -0
  245. package/docs/daemon-admin-ui.html +3394 -0
  246. package/docs/debug-system-design.md +734 -0
  247. package/docs/debugging/gemini-sse-root-cause.md +52 -0
  248. package/docs/debugging/sse_encoding_failure_analysis.md +53 -0
  249. package/docs/dry-run/README.md +721 -0
  250. package/docs/error-handling-v2.md +92 -0
  251. package/docs/exec-command-guard-policy.example.v1.json +42 -0
  252. package/docs/fixes/gemini-protocol-mapping.md +57 -0
  253. package/docs/fixes/oauth-portal-timing-fix.md +202 -0
  254. package/docs/fixes/web-search-hop3-fix.md +265 -0
  255. package/docs/glm-api-reference.md +390 -0
  256. package/docs/glm-chat-completions.md +1779 -0
  257. package/docs/glm-history-inline-images.md +44 -0
  258. package/docs/golden-ci-library.md +66 -0
  259. package/docs/lmstudio-dry-run-summary.md +203 -0
  260. package/docs/lmstudio-tool-calling.md +214 -0
  261. package/docs/mapping-tables/anthropic-to-openai.json +290 -0
  262. package/docs/mapping-tables/iflow-to-openai.json +215 -0
  263. package/docs/mapping-tables/openai-passthrough.json +190 -0
  264. package/docs/mapping-tables/openai-to-iflow.json +227 -0
  265. package/docs/monitoring/Design.md +61 -0
  266. package/docs/multi-token-auth-guide.md +66 -0
  267. package/docs/oauth-authentication-guide.md +168 -0
  268. package/docs/oauth-iflow-implementation.md +153 -0
  269. package/docs/pipeline-routing-report.md +209 -0
  270. package/docs/plans/manager-daemon/PLAN.md +86 -0
  271. package/docs/plans/provider-config-v2-plan.md +176 -0
  272. package/docs/plans/provider-runtime-manager-plan.md +209 -0
  273. package/docs/plans/transparent-429-failover.md +89 -0
  274. package/docs/plans/unified-hub-framework-v1.md +245 -0
  275. package/docs/provider-config-v2-ui-design.md +181 -0
  276. package/docs/provider-quota-design.md +129 -0
  277. package/docs/providers/gemini-provider.md +62 -0
  278. package/docs/providers/lmstudio-v2-migration-report.md +102 -0
  279. package/docs/providers/provider-composite-design.md +142 -0
  280. package/docs/providers/provider-composite-testing.md +98 -0
  281. package/docs/providers/provider-type-only-migration.md +111 -0
  282. package/docs/rccx-wasm-migration.md +74 -0
  283. package/docs/refactoring/architecture-comparison-diagram.md +140 -0
  284. package/docs/refactoring/compatibility-v2-architecture-design.md +738 -0
  285. package/docs/refactoring/workflow-compatibility-refactoring-design.md +361 -0
  286. package/docs/reports/routing-classification-report.json +24 -0
  287. package/docs/reports/routing-classification-report.md +18 -0
  288. package/docs/reports/thinking-keywords-report.json +19 -0
  289. package/docs/responses/README.md +156 -0
  290. package/docs/responses-generic-provider.md +86 -0
  291. package/docs/responses-passthrough-provider-design.md +202 -0
  292. package/docs/routing-awrr-health-weighted-round-robin.md +179 -0
  293. package/docs/routing-instructions.md +393 -0
  294. package/docs/stop-message-auto.md +225 -0
  295. package/docs/streaming-flow.html +30 -0
  296. package/docs/streaming-flow.md +182 -0
  297. package/docs/token-daemon-preview.html +490 -0
  298. package/docs/token-refresh-daemon-plan.md +269 -0
  299. package/docs/transformation-tables/Gemini-FinishReason/345/256/214/346/225/264/350/275/254/346/215/242/350/241/250.json +233 -0
  300. package/docs/transformation-tables/README.md +225 -0
  301. package/docs/transformation-tables/claude-code-router-anthropic-to-gemini.json +283 -0
  302. package/docs/transformation-tables/claude-code-router-anthropic-to-openai.json +208 -0
  303. package/docs/transformation-tables/claude-code-router-openai-to-anthropic.json +261 -0
  304. package/docs/transformation-tables/claude-code-router-openai-to-gemini.json +208 -0
  305. package/docs/transformation-tables/claude-code-router-openai-to-lmstudio.json +182 -0
  306. package/docs/transformation-tables/claude-code-router-openai-to-ollama.json +250 -0
  307. package/docs/transformation-tables/claude-code-router-openai-to-textgenwebui.json +295 -0
  308. package/docs/transformation-tables/claude-code-router-provider-conversions.json +193 -0
  309. 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
  310. 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
  311. 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
  312. 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
  313. 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
  314. 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
  315. 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
  316. package/docs/v2-architecture/IMPLEMENTATION-ROADMAP.md +367 -0
  317. package/docs/v2-architecture/OPTIMIZED-DESIGN.md +827 -0
  318. package/docs/v2-architecture/PRERUN-CONNECTION-DESIGN.md +716 -0
  319. package/docs/v2-architecture/README.md +551 -0
  320. package/docs/verification/modelscope-verify.md +59 -0
  321. package/docs/web-search-service-design.md +322 -0
  322. package/package.json +12 -7
  323. package/scripts/camoufox/launch-auth.mjs +193 -58
  324. package/scripts/monitor-diff.mjs +126 -0
  325. package/scripts/pack-mode.mjs +19 -1
  326. package/scripts/pack-rcc.mjs +63 -0
  327. package/scripts/unified-hub-shadow-compare.mjs +33 -13
  328. package/scripts/verify-e2e-toolcall.mjs +115 -26
  329. package/dist/modules/llmswitch/pipeline-registry.d.ts +0 -57
  330. package/dist/modules/llmswitch/pipeline-registry.js +0 -229
  331. package/dist/modules/llmswitch/pipeline-registry.js.map +0 -1
  332. package/dist/server/RouteCodexServer.d.ts +0 -13
  333. package/dist/server/RouteCodexServer.js +0 -25
  334. package/dist/server/RouteCodexServer.js.map +0 -1
  335. package/dist/v2/conversion/hub/snapshot-recorder.d.ts +0 -12
  336. package/dist/v2/conversion/hub/snapshot-recorder.js +0 -22
  337. package/dist/v2/conversion/hub/snapshot-recorder.js.map +0 -1
@@ -0,0 +1,237 @@
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, nowMs + 60_000);
32
+ const errorForQuota = {
33
+ providerKey,
34
+ httpStatus: typeof event.status === 'number' ? event.status : undefined,
35
+ code: typeof event.code === 'string' ? event.code : undefined,
36
+ fatal: false,
37
+ timestampMs: nowMs
38
+ };
39
+ const applied = applyQuotaErrorEvent(previous, errorForQuota, nowMs);
40
+ const nextState = {
41
+ ...applied,
42
+ inPool: false,
43
+ reason: 'cooldown',
44
+ cooldownUntil: nowMs + 60_000
45
+ };
46
+ ctx.quotaStates.set(providerKey, nextState);
47
+ ctx.schedulePersist(nowMs);
48
+ return;
49
+ }
50
+ // QUOTA_* 属于“确定性配额信号”,不进入错误 series 统计。
51
+ if (code === 'QUOTA_DEPLETED') {
52
+ const detailCarrier = (event.details && typeof event.details === 'object') ? event.details : {};
53
+ const raw = detailCarrier.virtualRouterQuotaDepleted;
54
+ const cooldownMs = raw && typeof raw === 'object' && typeof raw.cooldownMs === 'number'
55
+ ? raw.cooldownMs
56
+ : undefined;
57
+ const ttl = typeof cooldownMs === 'number' && Number.isFinite(cooldownMs) && cooldownMs > 0
58
+ ? cooldownMs
59
+ : undefined;
60
+ const cappedTtl = capAutoCooldownMs(ttl);
61
+ const nextCooldownUntil = cappedTtl ? nowMs + cappedTtl : previous.cooldownUntil;
62
+ const existingCooldownUntil = previous.cooldownUntil;
63
+ const cooldownUntil = typeof existingCooldownUntil === 'number' && typeof nextCooldownUntil === 'number' && existingCooldownUntil > nextCooldownUntil
64
+ ? existingCooldownUntil
65
+ : nextCooldownUntil;
66
+ const nextState = {
67
+ ...previous,
68
+ inPool: false,
69
+ reason: 'quotaDepleted',
70
+ cooldownUntil
71
+ };
72
+ ctx.quotaStates.set(providerKey, nextState);
73
+ ctx.schedulePersist(nowMs);
74
+ return;
75
+ }
76
+ if (code === 'QUOTA_RECOVERY') {
77
+ const withinBlacklist = previous.blacklistUntil !== null && nowMs < previous.blacklistUntil;
78
+ // QUOTA_RECOVERY should only flip providers that are waiting on an explicit quota snapshot:
79
+ // - previously quota-depleted, or
80
+ // - antigravity oauth "untracked" initial state (cooldown with no timers / no error series).
81
+ //
82
+ // It must NOT override active cooldown windows caused by real upstream failures
83
+ // (e.g. MODEL_CAPACITY_EXHAUSTED short backoff), otherwise the pool will keep hammering 429s.
84
+ const isUntrackedAntigravityOauthGate = previous.reason === 'cooldown' &&
85
+ previous.cooldownUntil === null &&
86
+ previous.blacklistUntil === null &&
87
+ previous.lastErrorSeries === null &&
88
+ previous.lastErrorCode === null &&
89
+ previous.lastErrorAtMs === null &&
90
+ previous.consecutiveErrorCount === 0;
91
+ const canRecover = previous.reason === 'quotaDepleted' || isUntrackedAntigravityOauthGate;
92
+ if (canRecover && !withinBlacklist) {
93
+ const nextState = {
94
+ ...previous,
95
+ inPool: true,
96
+ reason: 'ok',
97
+ cooldownUntil: null
98
+ };
99
+ ctx.quotaStates.set(providerKey, nextState);
100
+ ctx.schedulePersist(nowMs);
101
+ }
102
+ return;
103
+ }
104
+ // Gemini-family quota exhausted errors often carry quota reset delay.
105
+ // When present, treat as deterministic quota depletion signal rather than generic 429 backoff/blacklist.
106
+ if (typeof event.status === 'number' && event.status === 429) {
107
+ const seriesCooldown = extractVirtualRouterSeriesCooldown(event, nowMs);
108
+ if (seriesCooldown) {
109
+ const withinBlacklist = previous.blacklistUntil !== null && nowMs < previous.blacklistUntil;
110
+ // Do not override an active blacklist window (manual ops or policy).
111
+ if (withinBlacklist) {
112
+ return;
113
+ }
114
+ const isCapacityCooldown = typeof seriesCooldown.source === 'string' && seriesCooldown.source.toLowerCase().includes('capacity');
115
+ const until = capAutoCooldownUntil(seriesCooldown.until, nowMs);
116
+ const existingCooldownUntil = previous.cooldownUntil;
117
+ const cooldownUntil = typeof existingCooldownUntil === 'number' && existingCooldownUntil > until
118
+ ? existingCooldownUntil
119
+ : until;
120
+ const nextState = {
121
+ ...previous,
122
+ inPool: false,
123
+ reason: isCapacityCooldown ? 'cooldown' : 'quotaDepleted',
124
+ cooldownUntil,
125
+ lastErrorSeries: null,
126
+ lastErrorCode: null,
127
+ lastErrorAtMs: null,
128
+ consecutiveErrorCount: 0,
129
+ ...(isCapacityCooldown
130
+ ? {}
131
+ : {
132
+ blacklistUntil: null,
133
+ // deterministic quota signals should clear blacklist to avoid sticky long locks
134
+ // when upstream provides explicit reset delay.
135
+ })
136
+ };
137
+ ctx.quotaStates.set(providerKey, nextState);
138
+ ctx.schedulePersist(nowMs);
139
+ return;
140
+ }
141
+ const runtime = event.runtime;
142
+ const providerIdRaw = runtime && typeof runtime.providerId === 'string' ? runtime.providerId.trim().toLowerCase() : '';
143
+ const isQuotaProvider = providerIdRaw === 'antigravity' || providerIdRaw === 'gemini-cli';
144
+ if (isQuotaProvider) {
145
+ const ttl = parseQuotaResetDelayMs(event);
146
+ if (ttl && ttl > 0) {
147
+ const capped = capAutoCooldownMs(ttl);
148
+ const nextState = {
149
+ ...previous,
150
+ inPool: false,
151
+ reason: 'quotaDepleted',
152
+ cooldownUntil: nowMs + (capped ?? ttl),
153
+ blacklistUntil: null,
154
+ lastErrorSeries: null,
155
+ lastErrorCode: null,
156
+ lastErrorAtMs: null,
157
+ consecutiveErrorCount: 0
158
+ };
159
+ ctx.quotaStates.set(providerKey, nextState);
160
+ ctx.schedulePersist(nowMs);
161
+ return;
162
+ }
163
+ }
164
+ }
165
+ const errorForQuota = {
166
+ providerKey,
167
+ httpStatus: typeof event.status === 'number' ? event.status : undefined,
168
+ code: typeof event.code === 'string' ? event.code : undefined,
169
+ fatal: isFatalForQuota(event),
170
+ timestampMs: nowMs
171
+ };
172
+ const nextState = applyQuotaErrorEvent(previous, errorForQuota, nowMs);
173
+ ctx.quotaStates.set(providerKey, nextState);
174
+ const tsIso = new Date(nowMs).toISOString();
175
+ try {
176
+ await appendProviderErrorEvent({
177
+ ts: tsIso,
178
+ providerKey,
179
+ code: typeof errorForQuota.code === 'string' ? errorForQuota.code : undefined,
180
+ httpStatus: typeof errorForQuota.httpStatus === 'number' ? errorForQuota.httpStatus : undefined,
181
+ message: event.message,
182
+ details: {
183
+ stage: event.stage,
184
+ routeName: event.runtime.routeName,
185
+ entryEndpoint: event.runtime.entryEndpoint
186
+ }
187
+ });
188
+ }
189
+ catch {
190
+ // logging failure is non-fatal
191
+ }
192
+ try {
193
+ await saveProviderQuotaSnapshot(ctx.toSnapshotObject(), new Date(nowMs));
194
+ }
195
+ catch {
196
+ // best-effort persistence only
197
+ }
198
+ }
199
+ function extractProviderKey(event) {
200
+ const runtime = event.runtime;
201
+ const direct = runtime && typeof runtime.providerKey === 'string' && runtime.providerKey.trim()
202
+ ? runtime.providerKey.trim()
203
+ : null;
204
+ if (direct) {
205
+ return direct;
206
+ }
207
+ const target = runtime && runtime.target;
208
+ if (target && typeof target === 'object') {
209
+ const targetKey = target.providerKey;
210
+ if (typeof targetKey === 'string' && targetKey.trim()) {
211
+ return targetKey.trim();
212
+ }
213
+ }
214
+ return null;
215
+ }
216
+ function isFatalForQuota(event) {
217
+ const status = typeof event.status === 'number' ? event.status : undefined;
218
+ const code = typeof event.code === 'string' ? event.code.toUpperCase() : '';
219
+ const stage = typeof event.stage === 'string' ? event.stage.toLowerCase() : '';
220
+ if (status === 401 || status === 402 || status === 403) {
221
+ return true;
222
+ }
223
+ if (code.includes('AUTH') || code.includes('UNAUTHORIZED')) {
224
+ return true;
225
+ }
226
+ if (code.includes('CONFIG')) {
227
+ return true;
228
+ }
229
+ if (stage.includes('compat')) {
230
+ return true;
231
+ }
232
+ if (event.recoverable === false && status !== undefined && status >= 500) {
233
+ return true;
234
+ }
235
+ return false;
236
+ }
237
+ //# 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