@jsonstudio/rcc 0.89.683 → 0.89.912

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 (215) hide show
  1. package/README.md +44 -0
  2. package/dist/build-info.js +2 -2
  3. package/dist/cli.js +164 -116
  4. package/dist/cli.js.map +1 -1
  5. package/dist/client/anthropic/anthropic-protocol-client.js +42 -1
  6. package/dist/client/anthropic/anthropic-protocol-client.js.map +1 -1
  7. package/dist/client/gemini-cli/gemini-cli-protocol-client.js +4 -1
  8. package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -1
  9. package/dist/commands/camoufox-backfill.d.ts +2 -0
  10. package/dist/commands/camoufox-backfill.js +33 -0
  11. package/dist/commands/camoufox-backfill.js.map +1 -0
  12. package/dist/commands/camoufox-fp.d.ts +2 -0
  13. package/dist/commands/camoufox-fp.js +86 -0
  14. package/dist/commands/camoufox-fp.js.map +1 -0
  15. package/dist/commands/oauth.d.ts +2 -0
  16. package/dist/commands/oauth.js +170 -0
  17. package/dist/commands/oauth.js.map +1 -0
  18. package/dist/commands/provider-update.js +439 -2
  19. package/dist/commands/provider-update.js.map +1 -1
  20. package/dist/commands/quota-status.d.ts +2 -0
  21. package/dist/commands/quota-status.js +80 -0
  22. package/dist/commands/quota-status.js.map +1 -0
  23. package/dist/commands/token-daemon.js +12 -1
  24. package/dist/commands/token-daemon.js.map +1 -1
  25. package/dist/config/provider-v2-loader.d.ts +16 -0
  26. package/dist/config/provider-v2-loader.js +84 -0
  27. package/dist/config/provider-v2-loader.js.map +1 -0
  28. package/dist/config/routecodex-config-loader.js +27 -4
  29. package/dist/config/routecodex-config-loader.js.map +1 -1
  30. package/dist/config/system-prompts/codex-cli.txt +1 -0
  31. package/dist/config/virtual-router-builder.d.ts +9 -0
  32. package/dist/config/virtual-router-builder.js +34 -0
  33. package/dist/config/virtual-router-builder.js.map +1 -0
  34. package/dist/config/virtual-router-types.d.ts +25 -0
  35. package/dist/config/virtual-router-types.js +30 -0
  36. package/dist/config/virtual-router-types.js.map +1 -0
  37. package/dist/manager/index.d.ts +10 -0
  38. package/dist/manager/index.js +27 -0
  39. package/dist/manager/index.js.map +1 -0
  40. package/dist/manager/modules/health/index.d.ts +22 -0
  41. package/dist/manager/modules/health/index.js +82 -0
  42. package/dist/manager/modules/health/index.js.map +1 -0
  43. package/dist/manager/modules/quota/index.d.ts +57 -0
  44. package/dist/manager/modules/quota/index.js +426 -0
  45. package/dist/manager/modules/quota/index.js.map +1 -0
  46. package/dist/manager/modules/routing/index.d.ts +17 -0
  47. package/dist/manager/modules/routing/index.js +61 -0
  48. package/dist/manager/modules/routing/index.js.map +1 -0
  49. package/dist/manager/modules/token/index.d.ts +10 -0
  50. package/dist/manager/modules/token/index.js +58 -0
  51. package/dist/manager/modules/token/index.js.map +1 -0
  52. package/dist/manager/storage/base-store.d.ts +6 -0
  53. package/dist/manager/storage/base-store.js +2 -0
  54. package/dist/manager/storage/base-store.js.map +1 -0
  55. package/dist/manager/storage/file-store.d.ts +25 -0
  56. package/dist/manager/storage/file-store.js +117 -0
  57. package/dist/manager/storage/file-store.js.map +1 -0
  58. package/dist/manager/types.d.ts +9 -0
  59. package/dist/manager/types.js +2 -0
  60. package/dist/manager/types.js.map +1 -0
  61. package/dist/message-center/index.d.ts +5 -0
  62. package/dist/message-center/index.js +6 -0
  63. package/dist/message-center/index.js.map +1 -0
  64. package/dist/message-center/message-center.d.ts +93 -0
  65. package/dist/message-center/message-center.js +189 -0
  66. package/dist/message-center/message-center.js.map +1 -0
  67. package/dist/providers/auth/antigravity-userinfo-helper.d.ts +2 -0
  68. package/dist/providers/auth/antigravity-userinfo-helper.js +102 -0
  69. package/dist/providers/auth/antigravity-userinfo-helper.js.map +1 -1
  70. package/dist/providers/auth/iflow-cookie-auth.d.ts +27 -0
  71. package/dist/providers/auth/iflow-cookie-auth.js +209 -0
  72. package/dist/providers/auth/iflow-cookie-auth.js.map +1 -0
  73. package/dist/providers/auth/oauth-lifecycle.js +29 -22
  74. package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
  75. package/dist/providers/auth/token-scanner/index.js +16 -1
  76. package/dist/providers/auth/token-scanner/index.js.map +1 -1
  77. package/dist/providers/core/config/camoufox-launcher.d.ts +16 -0
  78. package/dist/providers/core/config/camoufox-launcher.js +314 -0
  79. package/dist/providers/core/config/camoufox-launcher.js.map +1 -0
  80. package/dist/providers/core/config/oauth-flows.d.ts +9 -0
  81. package/dist/providers/core/config/oauth-flows.js +50 -19
  82. package/dist/providers/core/config/oauth-flows.js.map +1 -1
  83. package/dist/providers/core/config/provider-oauth-configs.d.ts +6 -0
  84. package/dist/providers/core/config/provider-oauth-configs.js +12 -0
  85. package/dist/providers/core/config/provider-oauth-configs.js.map +1 -1
  86. package/dist/providers/core/config/service-profiles.js +26 -3
  87. package/dist/providers/core/config/service-profiles.js.map +1 -1
  88. package/dist/providers/core/runtime/antigravity-quota-client.d.ts +10 -0
  89. package/dist/providers/core/runtime/antigravity-quota-client.js +88 -0
  90. package/dist/providers/core/runtime/antigravity-quota-client.js.map +1 -0
  91. package/dist/providers/core/runtime/base-provider.d.ts +2 -1
  92. package/dist/providers/core/runtime/base-provider.js +93 -34
  93. package/dist/providers/core/runtime/base-provider.js.map +1 -1
  94. package/dist/providers/core/runtime/gemini-cli-http-provider.js +42 -10
  95. package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
  96. package/dist/providers/core/runtime/http-request-executor.js +24 -0
  97. package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
  98. package/dist/providers/core/runtime/http-transport-provider.d.ts +0 -3
  99. package/dist/providers/core/runtime/http-transport-provider.js +32 -136
  100. package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
  101. package/dist/providers/core/runtime/provider-error-classifier.js +18 -10
  102. package/dist/providers/core/runtime/provider-error-classifier.js.map +1 -1
  103. package/dist/providers/core/runtime/rate-limit-manager.d.ts +6 -0
  104. package/dist/providers/core/runtime/rate-limit-manager.js +23 -0
  105. package/dist/providers/core/runtime/rate-limit-manager.js.map +1 -1
  106. package/dist/providers/core/runtime/responses-provider.js +17 -19
  107. package/dist/providers/core/runtime/responses-provider.js.map +1 -1
  108. package/dist/providers/core/strategies/oauth-auth-code-flow.d.ts +1 -0
  109. package/dist/providers/core/strategies/oauth-auth-code-flow.js +3 -2
  110. package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
  111. package/dist/providers/core/strategies/oauth-device-flow.d.ts +1 -0
  112. package/dist/providers/core/strategies/oauth-device-flow.js +3 -2
  113. package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
  114. package/dist/providers/core/strategies/oauth-hybrid-flow.d.ts +1 -0
  115. package/dist/providers/core/strategies/oauth-hybrid-flow.js +3 -2
  116. package/dist/providers/core/strategies/oauth-hybrid-flow.js.map +1 -1
  117. package/dist/providers/core/utils/http-client.js +43 -1
  118. package/dist/providers/core/utils/http-client.js.map +1 -1
  119. package/dist/providers/mock/mock-provider-runtime.js +4 -4
  120. package/dist/providers/mock/mock-provider-runtime.js.map +1 -1
  121. package/dist/providers/profile/provider-profile-loader.js +13 -1
  122. package/dist/providers/profile/provider-profile-loader.js.map +1 -1
  123. package/dist/providers/profile/provider-profile.d.ts +5 -0
  124. package/dist/scripts/camoufox/gen-fingerprint-env.py +171 -0
  125. package/dist/scripts/camoufox/launch-auth.mjs +617 -0
  126. package/dist/server/runtime/http-server/daemon-admin/credentials-handler.d.ts +3 -0
  127. package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js +138 -0
  128. package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js.map +1 -0
  129. package/dist/server/runtime/http-server/daemon-admin/providers-handler.d.ts +3 -0
  130. package/dist/server/runtime/http-server/daemon-admin/providers-handler.js +166 -0
  131. package/dist/server/runtime/http-server/daemon-admin/providers-handler.js.map +1 -0
  132. package/dist/server/runtime/http-server/daemon-admin/quota-handler.d.ts +3 -0
  133. package/dist/server/runtime/http-server/daemon-admin/quota-handler.js +109 -0
  134. package/dist/server/runtime/http-server/daemon-admin/quota-handler.js.map +1 -0
  135. package/dist/server/runtime/http-server/daemon-admin/status-handler.d.ts +3 -0
  136. package/dist/server/runtime/http-server/daemon-admin/status-handler.js +43 -0
  137. package/dist/server/runtime/http-server/daemon-admin/status-handler.js.map +1 -0
  138. package/dist/server/runtime/http-server/daemon-admin-routes.d.ts +19 -0
  139. package/dist/server/runtime/http-server/daemon-admin-routes.js +27 -0
  140. package/dist/server/runtime/http-server/daemon-admin-routes.js.map +1 -0
  141. package/dist/server/runtime/http-server/executor-provider.d.ts +1 -0
  142. package/dist/server/runtime/http-server/executor-provider.js +26 -0
  143. package/dist/server/runtime/http-server/executor-provider.js.map +1 -1
  144. package/dist/server/runtime/http-server/executor-response.d.ts +16 -0
  145. package/dist/server/runtime/http-server/executor-response.js +164 -0
  146. package/dist/server/runtime/http-server/executor-response.js.map +1 -0
  147. package/dist/server/runtime/http-server/index.d.ts +6 -0
  148. package/dist/server/runtime/http-server/index.js +121 -53
  149. package/dist/server/runtime/http-server/index.js.map +1 -1
  150. package/dist/server/runtime/http-server/request-executor.d.ts +3 -0
  151. package/dist/server/runtime/http-server/request-executor.js +73 -21
  152. package/dist/server/runtime/http-server/request-executor.js.map +1 -1
  153. package/dist/server/runtime/http-server/routes.d.ts +5 -0
  154. package/dist/server/runtime/http-server/routes.js +45 -1
  155. package/dist/server/runtime/http-server/routes.js.map +1 -1
  156. package/dist/server/runtime/http-server/types.d.ts +1 -0
  157. package/dist/server/utils/client-connection-state.d.ts +8 -0
  158. package/dist/server/utils/client-connection-state.js +52 -0
  159. package/dist/server/utils/client-connection-state.js.map +1 -0
  160. package/dist/server/utils/request-id-manager.js +21 -3
  161. package/dist/server/utils/request-id-manager.js.map +1 -1
  162. package/dist/token-daemon/history-store.d.ts +2 -0
  163. package/dist/token-daemon/history-store.js +6 -2
  164. package/dist/token-daemon/history-store.js.map +1 -1
  165. package/dist/token-daemon/index.js +36 -5
  166. package/dist/token-daemon/index.js.map +1 -1
  167. package/dist/token-daemon/leader-lock.d.ts +11 -0
  168. package/dist/token-daemon/leader-lock.js +79 -0
  169. package/dist/token-daemon/leader-lock.js.map +1 -0
  170. package/dist/token-daemon/message-bus-integrator.d.ts +98 -0
  171. package/dist/token-daemon/message-bus-integrator.js +144 -0
  172. package/dist/token-daemon/message-bus-integrator.js.map +1 -0
  173. package/dist/token-daemon/provider-registry.d.ts +22 -0
  174. package/dist/token-daemon/provider-registry.js +201 -0
  175. package/dist/token-daemon/provider-registry.js.map +1 -0
  176. package/dist/token-daemon/token-daemon.d.ts +8 -0
  177. package/dist/token-daemon/token-daemon.js +196 -11
  178. package/dist/token-daemon/token-daemon.js.map +1 -1
  179. package/dist/token-portal/local-token-portal.d.ts +1 -0
  180. package/dist/token-portal/local-token-portal.js +18 -0
  181. package/dist/token-portal/local-token-portal.js.map +1 -1
  182. package/dist/token-portal/render.js +1 -0
  183. package/dist/token-portal/render.js.map +1 -1
  184. package/dist/tools/error-log.d.ts +31 -0
  185. package/dist/tools/error-log.js +117 -0
  186. package/dist/tools/error-log.js.map +1 -0
  187. package/dist/tools/stats-request-events.d.ts +2 -0
  188. package/dist/tools/stats-request-events.js +16 -0
  189. package/dist/tools/stats-request-events.js.map +1 -0
  190. package/dist/tools/stats-usage.d.ts +31 -0
  191. package/dist/tools/stats-usage.js +206 -0
  192. package/dist/tools/stats-usage.js.map +1 -0
  193. package/package.json +9 -4
  194. package/scripts/analyze-codex-error-failures.mjs +111 -0
  195. package/scripts/analyze-usage-estimate.mjs +240 -0
  196. package/scripts/camoufox/gen-fingerprint-env.py +171 -0
  197. package/scripts/camoufox/launch-auth.mjs +617 -0
  198. package/scripts/classify-codex-samples.mjs +251 -0
  199. package/scripts/cleanup-codex-error-samples.mjs +88 -0
  200. package/scripts/compare-codex-rccx.mjs +268 -0
  201. package/scripts/copy-compat-assets.mjs +18 -0
  202. package/scripts/install-release.sh +1 -1
  203. package/scripts/local-replay-openai-response.mjs +1 -2
  204. package/scripts/pack-mode.mjs +16 -6
  205. package/scripts/replay-codex-sample.mjs +24 -2
  206. package/scripts/responses-compare-server.mjs +119 -0
  207. package/scripts/tests/apply-patch-loop.mjs +266 -7
  208. package/scripts/tests/exec-command-loop.mjs +165 -0
  209. package/scripts/tool-classification-report.ts +281 -0
  210. package/scripts/verification/samples/openai-chat-list-local-files.json +1 -1
  211. package/scripts/verify-apply-patch.mjs +28 -17
  212. package/scripts/verify-codex-error-samples.mjs +102 -0
  213. package/scripts/verify-e2e-toolcall.mjs +71 -4
  214. package/scripts/virtual-router-shadow-v2-real.mjs +143 -0
  215. package/scripts/virtual-router-shadow-v2.mjs +122 -0
@@ -0,0 +1,82 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { JsonlFileStore } from '../../storage/file-store.js';
5
+ export class HealthManagerModule {
6
+ id = 'health';
7
+ serverId = null;
8
+ healthStore = null;
9
+ snapshotStore = null;
10
+ initialSnapshot = null;
11
+ async init(context) {
12
+ this.serverId = context.serverId;
13
+ const baseDir = this.resolveStateDir();
14
+ const filePath = path.join(baseDir, 'health.jsonl');
15
+ // 默认保留最近 7 天的 ProviderError 事件,最多 1000 条,防止无限膨胀。
16
+ const sevenDaysMs = 7 * 24 * 60 * 60 * 1000;
17
+ this.snapshotStore = new JsonlFileStore({
18
+ filePath,
19
+ maxAgeMs: sevenDaysMs,
20
+ maxEvents: 1000
21
+ });
22
+ try {
23
+ this.initialSnapshot = await this.snapshotStore.load();
24
+ }
25
+ catch {
26
+ this.initialSnapshot = null;
27
+ }
28
+ this.healthStore = {
29
+ loadInitialSnapshot: () => this.initialSnapshot,
30
+ persistSnapshot: (snapshot) => {
31
+ this.initialSnapshot = snapshot;
32
+ const store = this.snapshotStore;
33
+ if (!store) {
34
+ return;
35
+ }
36
+ void store.save(snapshot).catch(() => {
37
+ // 持久化失败不影响主流程
38
+ });
39
+ },
40
+ recordProviderError: (event) => {
41
+ const store = this.snapshotStore;
42
+ if (!store) {
43
+ return;
44
+ }
45
+ void store.append(event).catch(() => {
46
+ // 事件落盘失败忽略
47
+ });
48
+ }
49
+ };
50
+ }
51
+ async start() {
52
+ // 当前 HealthManager 仅提供 VirtualRouterHealthStore,不需要单独的后台任务。
53
+ }
54
+ async stop() {
55
+ // Server 停止时做一次 best-effort 压缩,清理过期事件记录。
56
+ if (this.snapshotStore) {
57
+ try {
58
+ await this.snapshotStore.compact();
59
+ }
60
+ catch {
61
+ // 压缩失败不影响关机流程
62
+ }
63
+ }
64
+ }
65
+ getHealthStore() {
66
+ return this.healthStore;
67
+ }
68
+ getCurrentSnapshot() {
69
+ return this.initialSnapshot;
70
+ }
71
+ resolveStateDir() {
72
+ const base = path.join(homedir(), '.routecodex', 'state', 'router', this.serverId || 'default');
73
+ try {
74
+ fs.mkdirSync(base, { recursive: true });
75
+ }
76
+ catch {
77
+ // best effort
78
+ }
79
+ return base;
80
+ }
81
+ }
82
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/manager/modules/health/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import type { ManagerContext, ManagerModule } from '../../types.js';
2
+ import { type AntigravityQuotaSnapshot } from '../../../providers/core/runtime/antigravity-quota-client.js';
3
+ export interface QuotaRecord {
4
+ remainingFraction: number | null;
5
+ resetAt?: number;
6
+ fetchedAt: number;
7
+ }
8
+ export declare class QuotaManagerModule implements ManagerModule {
9
+ readonly id = "quota";
10
+ private snapshot;
11
+ private antigravityTokens;
12
+ private refreshTimer;
13
+ private providerErrorCenter;
14
+ init(context: ManagerContext): Promise<void>;
15
+ start(): Promise<void>;
16
+ stop(): Promise<void>;
17
+ /**
18
+ * 用于 antigravity:注册需要追踪配额的 alias/token。
19
+ * 多次调用同一 alias 会覆盖最新配置。
20
+ */
21
+ registerAntigravityToken(alias: string, tokenFile: string, apiBase: string): void;
22
+ /**
23
+ * 用于 antigravity:根据 alias+model 更新配额快照。
24
+ */
25
+ updateAntigravityQuota(alias: string, quota: AntigravityQuotaSnapshot): void;
26
+ /**
27
+ * 判断给定 providerKey+model 是否有可用配额(仅针对 antigravity 语义)。
28
+ */
29
+ hasQuotaForAntigravity(providerKey: string, modelId?: string): boolean;
30
+ getRawSnapshot(): Record<string, QuotaRecord>;
31
+ private buildAntigravityKey;
32
+ private extractAntigravityAlias;
33
+ private computeResetAt;
34
+ private refreshAllAntigravityQuotas;
35
+ /**
36
+ * 根据当前 token 池的过期时间和固定 15 分钟基准,动态安排下一次 quota 刷新:
37
+ * - 如有 token 会在 15 分钟内到期,则在该 token 到期时间附近刷新;
38
+ * - 否则按固定 15 分钟间隔刷新。
39
+ */
40
+ private scheduleNextRefresh;
41
+ /**
42
+ * 扫描 antigravity token 文件,计算距离最近一次 token 过期还剩多少毫秒。
43
+ * 若所有 token 都无过期时间或已过期,则返回 null。
44
+ */
45
+ private computeNextTokenExpiryDelayMs;
46
+ /**
47
+ * 自动从本地 auth 目录扫描 antigravity OAuth token,并同步到内存注册表。
48
+ * 这确保「每个 token」都能定期刷新 quota,而不依赖额外的显式注册流程。
49
+ */
50
+ private syncAntigravityTokensFromDisk;
51
+ private resolveStatePath;
52
+ private loadSnapshotFromDisk;
53
+ private saveSnapshotToDisk;
54
+ private getProviderErrorCenterInstance;
55
+ private emitQuotaRecoveryEvent;
56
+ private emitQuotaDepletedEvent;
57
+ }
@@ -0,0 +1,426 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { fetchAntigravityQuotaSnapshot, loadAntigravityAccessToken } from '../../../providers/core/runtime/antigravity-quota-client.js';
5
+ import { scanProviderTokenFiles } from '../../../providers/auth/token-scanner/index.js';
6
+ import { resolveAntigravityApiBase } from '../../../providers/auth/antigravity-userinfo-helper.js';
7
+ import { getProviderErrorCenter } from '../../../modules/llmswitch/bridge.js';
8
+ import { readTokenFile, evaluateTokenState } from '../../../token-daemon/token-utils.js';
9
+ export class QuotaManagerModule {
10
+ id = 'quota';
11
+ snapshot = {};
12
+ antigravityTokens = new Map();
13
+ refreshTimer = null;
14
+ providerErrorCenter = null;
15
+ async init(context) {
16
+ this.snapshot = this.loadSnapshotFromDisk();
17
+ }
18
+ async start() {
19
+ // 启动时立即做一次最佳努力刷新,然后根据 token 过期时间和 15 分钟基准动态调度后续刷新。
20
+ try {
21
+ await this.refreshAllAntigravityQuotas();
22
+ }
23
+ catch {
24
+ // ignore startup refresh failures
25
+ }
26
+ void this.scheduleNextRefresh().catch(() => {
27
+ // ignore scheduling failures
28
+ });
29
+ }
30
+ async stop() {
31
+ if (this.refreshTimer) {
32
+ clearTimeout(this.refreshTimer);
33
+ this.refreshTimer = null;
34
+ }
35
+ this.saveSnapshotToDisk();
36
+ }
37
+ /**
38
+ * 用于 antigravity:注册需要追踪配额的 alias/token。
39
+ * 多次调用同一 alias 会覆盖最新配置。
40
+ */
41
+ registerAntigravityToken(alias, tokenFile, apiBase) {
42
+ const cleanAlias = alias.trim();
43
+ const cleanToken = tokenFile.trim();
44
+ const cleanBase = apiBase.trim();
45
+ if (!cleanAlias || !cleanToken || !cleanBase) {
46
+ return;
47
+ }
48
+ this.antigravityTokens.set(cleanAlias, {
49
+ alias: cleanAlias,
50
+ tokenFile: cleanToken,
51
+ apiBase: cleanBase
52
+ });
53
+ }
54
+ /**
55
+ * 用于 antigravity:根据 alias+model 更新配额快照。
56
+ */
57
+ updateAntigravityQuota(alias, quota) {
58
+ const aliasId = alias.trim();
59
+ if (!aliasId)
60
+ return;
61
+ const now = Date.now();
62
+ const next = { ...this.snapshot };
63
+ for (const [modelId, info] of Object.entries(quota.models)) {
64
+ const key = this.buildAntigravityKey(aliasId, modelId);
65
+ const record = {
66
+ remainingFraction: Number.isFinite(info.remainingFraction) ? info.remainingFraction : null,
67
+ fetchedAt: quota.fetchedAt
68
+ };
69
+ const resetAt = this.computeResetAt(info.resetTimeRaw);
70
+ if (resetAt && resetAt > now) {
71
+ record.resetAt = resetAt;
72
+ }
73
+ next[key] = record;
74
+ const providerKey = `antigravity.${aliasId}.${modelId}`;
75
+ if (record.remainingFraction !== null && record.remainingFraction > 0) {
76
+ void this.emitQuotaRecoveryEvent(providerKey, modelId);
77
+ }
78
+ else {
79
+ const cooldownHint = record.resetAt ? Math.max(0, record.resetAt - now) : undefined;
80
+ void this.emitQuotaDepletedEvent(providerKey, modelId, cooldownHint);
81
+ }
82
+ }
83
+ this.snapshot = next;
84
+ this.saveSnapshotToDisk();
85
+ }
86
+ /**
87
+ * 判断给定 providerKey+model 是否有可用配额(仅针对 antigravity 语义)。
88
+ */
89
+ hasQuotaForAntigravity(providerKey, modelId) {
90
+ const alias = this.extractAntigravityAlias(providerKey);
91
+ if (!alias || !modelId) {
92
+ return true;
93
+ }
94
+ const key = this.buildAntigravityKey(alias, modelId);
95
+ const record = this.snapshot[key];
96
+ if (!record) {
97
+ // 没有任何配额记录时视为“无配额”,禁止进入路由池。
98
+ return false;
99
+ }
100
+ const now = Date.now();
101
+ // 如果已经超过 resetAt,但尚未刷新到新一轮配额,视为配额状态未知,同样禁止。
102
+ if (record.resetAt && record.resetAt <= now) {
103
+ return false;
104
+ }
105
+ if (record.remainingFraction === null) {
106
+ return false;
107
+ }
108
+ return record.remainingFraction > 0;
109
+ }
110
+ getRawSnapshot() {
111
+ return { ...this.snapshot };
112
+ }
113
+ buildAntigravityKey(alias, modelId) {
114
+ return `antigravity://${alias}/${modelId}`;
115
+ }
116
+ extractAntigravityAlias(providerKey) {
117
+ if (!providerKey || typeof providerKey !== 'string') {
118
+ return null;
119
+ }
120
+ const trimmed = providerKey.trim();
121
+ if (!trimmed.toLowerCase().startsWith('antigravity.')) {
122
+ return null;
123
+ }
124
+ const segments = trimmed.split('.');
125
+ if (segments.length < 2) {
126
+ return null;
127
+ }
128
+ return segments[1];
129
+ }
130
+ computeResetAt(raw) {
131
+ if (!raw || typeof raw !== 'string' || !raw.trim()) {
132
+ return undefined;
133
+ }
134
+ const value = raw.trim();
135
+ try {
136
+ const normalized = value.endsWith('Z') ? value.replace(/Z$/, '+00:00') : value;
137
+ const parsed = Date.parse(normalized);
138
+ if (!Number.isFinite(parsed) || parsed <= 0) {
139
+ return undefined;
140
+ }
141
+ return parsed;
142
+ }
143
+ catch {
144
+ return undefined;
145
+ }
146
+ }
147
+ async refreshAllAntigravityQuotas() {
148
+ await this.syncAntigravityTokensFromDisk();
149
+ if (this.antigravityTokens.size === 0) {
150
+ return;
151
+ }
152
+ for (const { alias, tokenFile, apiBase } of this.antigravityTokens.values()) {
153
+ try {
154
+ const accessToken = await loadAntigravityAccessToken(tokenFile);
155
+ if (!accessToken) {
156
+ continue;
157
+ }
158
+ const snapshot = await fetchAntigravityQuotaSnapshot(apiBase, accessToken);
159
+ if (!snapshot) {
160
+ continue;
161
+ }
162
+ this.updateAntigravityQuota(alias, snapshot);
163
+ }
164
+ catch {
165
+ // 单个 alias 失败不影响其他 alias 的刷新
166
+ }
167
+ }
168
+ }
169
+ /**
170
+ * 根据当前 token 池的过期时间和固定 15 分钟基准,动态安排下一次 quota 刷新:
171
+ * - 如有 token 会在 15 分钟内到期,则在该 token 到期时间附近刷新;
172
+ * - 否则按固定 15 分钟间隔刷新。
173
+ */
174
+ async scheduleNextRefresh() {
175
+ if (this.refreshTimer) {
176
+ clearTimeout(this.refreshTimer);
177
+ this.refreshTimer = null;
178
+ }
179
+ const baseIntervalMs = 15 * 60 * 1000;
180
+ let delayMs = baseIntervalMs;
181
+ try {
182
+ const nextExpiryDelay = await this.computeNextTokenExpiryDelayMs();
183
+ if (nextExpiryDelay !== null && nextExpiryDelay > 0 && nextExpiryDelay < baseIntervalMs) {
184
+ delayMs = nextExpiryDelay;
185
+ }
186
+ }
187
+ catch {
188
+ // 如果计算失败,退回到固定 15 分钟间隔
189
+ delayMs = baseIntervalMs;
190
+ }
191
+ this.refreshTimer = setTimeout(() => {
192
+ void this.refreshAllAntigravityQuotas()
193
+ .catch(() => {
194
+ // ignore refresh failure
195
+ })
196
+ .finally(() => {
197
+ void this.scheduleNextRefresh().catch(() => {
198
+ // ignore reschedule failure
199
+ });
200
+ });
201
+ }, delayMs);
202
+ }
203
+ /**
204
+ * 扫描 antigravity token 文件,计算距离最近一次 token 过期还剩多少毫秒。
205
+ * 若所有 token 都无过期时间或已过期,则返回 null。
206
+ */
207
+ async computeNextTokenExpiryDelayMs() {
208
+ let matches = [];
209
+ try {
210
+ const raw = await scanProviderTokenFiles('antigravity');
211
+ matches = raw.map((m) => ({ filePath: m.filePath }));
212
+ }
213
+ catch {
214
+ matches = [];
215
+ }
216
+ if (!matches.length) {
217
+ return null;
218
+ }
219
+ const now = Date.now();
220
+ let minDelay = null;
221
+ for (const match of matches) {
222
+ try {
223
+ const token = await readTokenFile(match.filePath);
224
+ const state = evaluateTokenState(token, now);
225
+ const msLeft = state.msUntilExpiry;
226
+ if (msLeft === null || msLeft <= 0) {
227
+ continue;
228
+ }
229
+ if (minDelay === null || msLeft < minDelay) {
230
+ minDelay = msLeft;
231
+ }
232
+ }
233
+ catch {
234
+ // ignore single token file errors
235
+ }
236
+ }
237
+ return minDelay;
238
+ }
239
+ /**
240
+ * 自动从本地 auth 目录扫描 antigravity OAuth token,并同步到内存注册表。
241
+ * 这确保「每个 token」都能定期刷新 quota,而不依赖额外的显式注册流程。
242
+ */
243
+ async syncAntigravityTokensFromDisk() {
244
+ let matches = [];
245
+ try {
246
+ matches = await scanProviderTokenFiles('antigravity');
247
+ }
248
+ catch {
249
+ matches = [];
250
+ }
251
+ if (!matches.length) {
252
+ this.antigravityTokens.clear();
253
+ return;
254
+ }
255
+ const base = resolveAntigravityApiBase();
256
+ const next = new Map();
257
+ for (const match of matches) {
258
+ const label = match.alias && match.alias !== 'default'
259
+ ? `${match.sequence}-${match.alias}`
260
+ : String(match.sequence);
261
+ const alias = label.trim();
262
+ if (!alias) {
263
+ continue;
264
+ }
265
+ next.set(alias, {
266
+ alias,
267
+ tokenFile: match.filePath,
268
+ apiBase: base
269
+ });
270
+ }
271
+ // 若已有显式注册的 alias,保留其覆盖权
272
+ for (const [alias, reg] of this.antigravityTokens.entries()) {
273
+ if (!next.has(alias)) {
274
+ next.set(alias, reg);
275
+ }
276
+ }
277
+ this.antigravityTokens = next;
278
+ }
279
+ resolveStatePath() {
280
+ const baseDir = path.join(homedir(), '.routecodex', 'state', 'quota');
281
+ try {
282
+ fs.mkdirSync(baseDir, { recursive: true });
283
+ }
284
+ catch {
285
+ // best effort
286
+ }
287
+ return path.join(baseDir, 'antigravity.json');
288
+ }
289
+ loadSnapshotFromDisk() {
290
+ const filePath = this.resolveStatePath();
291
+ try {
292
+ if (!fs.existsSync(filePath)) {
293
+ return {};
294
+ }
295
+ const content = fs.readFileSync(filePath, 'utf8');
296
+ const parsed = content.trim() ? JSON.parse(content) : {};
297
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
298
+ return {};
299
+ }
300
+ const raw = parsed;
301
+ const result = {};
302
+ for (const [key, value] of Object.entries(raw)) {
303
+ if (!value || typeof value !== 'object') {
304
+ continue;
305
+ }
306
+ let remainingFraction = null;
307
+ if (typeof value.remainingFraction === 'number') {
308
+ remainingFraction = value.remainingFraction ?? null;
309
+ }
310
+ let resetAt;
311
+ if (typeof value.resetAt === 'number') {
312
+ resetAt = value.resetAt;
313
+ }
314
+ const fetchedAt = typeof value.fetchedAt === 'number'
315
+ ? value.fetchedAt
316
+ : Date.now();
317
+ result[key] = { remainingFraction, resetAt, fetchedAt };
318
+ }
319
+ return result;
320
+ }
321
+ catch {
322
+ return {};
323
+ }
324
+ }
325
+ saveSnapshotToDisk() {
326
+ const filePath = this.resolveStatePath();
327
+ try {
328
+ fs.writeFileSync(filePath, `${JSON.stringify(this.snapshot, null, 2)}\n`, 'utf8');
329
+ }
330
+ catch {
331
+ // best effort
332
+ }
333
+ }
334
+ async getProviderErrorCenterInstance() {
335
+ if (this.providerErrorCenter) {
336
+ return this.providerErrorCenter;
337
+ }
338
+ try {
339
+ const center = await getProviderErrorCenter();
340
+ if (center && typeof center.emit === 'function') {
341
+ this.providerErrorCenter = center;
342
+ }
343
+ else {
344
+ this.providerErrorCenter = null;
345
+ }
346
+ }
347
+ catch {
348
+ this.providerErrorCenter = null;
349
+ }
350
+ return this.providerErrorCenter;
351
+ }
352
+ async emitQuotaRecoveryEvent(providerKey, modelId) {
353
+ if (!providerKey || !modelId) {
354
+ return;
355
+ }
356
+ const center = await this.getProviderErrorCenterInstance();
357
+ if (!center) {
358
+ return;
359
+ }
360
+ const now = Date.now();
361
+ const event = {
362
+ code: 'QUOTA_RECOVERY',
363
+ message: 'Quota manager: provider quota refreshed',
364
+ stage: 'quota',
365
+ status: 200,
366
+ recoverable: true,
367
+ runtime: {
368
+ requestId: `quota_${now}`,
369
+ providerKey,
370
+ providerId: 'antigravity'
371
+ },
372
+ timestamp: now,
373
+ details: {
374
+ virtualRouterQuotaRecovery: {
375
+ providerKey,
376
+ reason: `quota>0 for model ${modelId}`,
377
+ source: 'quota-manager'
378
+ }
379
+ }
380
+ };
381
+ try {
382
+ center.emit(event);
383
+ }
384
+ catch {
385
+ // 忽略 error center 失败,避免影响配额刷新流程
386
+ }
387
+ }
388
+ async emitQuotaDepletedEvent(providerKey, modelId, cooldownMs) {
389
+ if (!providerKey || !modelId) {
390
+ return;
391
+ }
392
+ const center = await this.getProviderErrorCenterInstance();
393
+ if (!center) {
394
+ return;
395
+ }
396
+ const now = Date.now();
397
+ const detail = {
398
+ virtualRouterQuotaDepleted: {
399
+ providerKey,
400
+ reason: `quota<=0 for model ${modelId}`,
401
+ ...(typeof cooldownMs === 'number' && cooldownMs > 0 ? { cooldownMs } : {})
402
+ }
403
+ };
404
+ const event = {
405
+ code: 'QUOTA_DEPLETED',
406
+ message: 'Quota manager: provider quota exhausted',
407
+ stage: 'quota',
408
+ status: 429,
409
+ recoverable: false,
410
+ runtime: {
411
+ requestId: `quota_${now}`,
412
+ providerKey,
413
+ providerId: 'antigravity'
414
+ },
415
+ timestamp: now,
416
+ details: detail
417
+ };
418
+ try {
419
+ center.emit(event);
420
+ }
421
+ catch {
422
+ // ignore emit errors
423
+ }
424
+ }
425
+ }
426
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/manager/modules/quota/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { ManagerContext, ManagerModule } from '../../types.js';
2
+ type RoutingInstructionState = unknown;
3
+ export interface RoutingInstructionStateStore {
4
+ loadSync(key: string): RoutingInstructionState | null;
5
+ saveAsync(key: string, state: RoutingInstructionState | null): void;
6
+ }
7
+ export declare class RoutingStateManagerModule implements ManagerModule {
8
+ readonly id = "routing";
9
+ private stateStore;
10
+ private stickyEnabled;
11
+ private isStickyEnabled;
12
+ init(_context: ManagerContext): Promise<void>;
13
+ start(): Promise<void>;
14
+ stop(): Promise<void>;
15
+ getRoutingStateStore(): RoutingInstructionStateStore | null;
16
+ }
17
+ export {};
@@ -0,0 +1,61 @@
1
+ export class RoutingStateManagerModule {
2
+ id = 'routing';
3
+ stateStore = null;
4
+ stickyEnabled = null;
5
+ isStickyEnabled() {
6
+ if (this.stickyEnabled !== null) {
7
+ return this.stickyEnabled;
8
+ }
9
+ const raw = process.env.ROUTECODEX_ENABLE_STICKY ??
10
+ process.env.RCC_ENABLE_STICKY ??
11
+ '';
12
+ const normalized = typeof raw === 'string' ? raw.trim().toLowerCase() : '';
13
+ const enabled = normalized === '1' ||
14
+ normalized === 'true' ||
15
+ normalized === 'yes' ||
16
+ normalized === 'on';
17
+ this.stickyEnabled = enabled;
18
+ return enabled;
19
+ }
20
+ async init(_context) {
21
+ if (!this.isStickyEnabled()) {
22
+ this.stateStore = null;
23
+ return;
24
+ }
25
+ // 初始版本:通过 require 动态加载 llmswitch-core 的 sticky-session 存取函数,
26
+ // 并包装为 VirtualRouterEngine 所需的 routingStateStore 接口。
27
+ try {
28
+ // eslint-disable-next-line @typescript-eslint/no-var-requires,global-require
29
+ const mod = require('@jsonstudio/llms/dist/router/virtual-router/sticky-session-store.js');
30
+ const loadFn = typeof mod?.loadRoutingInstructionStateSync === 'function'
31
+ ? mod.loadRoutingInstructionStateSync
32
+ : undefined;
33
+ const saveFn = typeof mod?.saveRoutingInstructionStateAsync === 'function'
34
+ ? mod.saveRoutingInstructionStateAsync
35
+ : undefined;
36
+ if (!loadFn || !saveFn) {
37
+ this.stateStore = null;
38
+ return;
39
+ }
40
+ this.stateStore = {
41
+ loadSync: (key) => loadFn(key),
42
+ saveAsync: (key, state) => {
43
+ saveFn(key, state);
44
+ }
45
+ };
46
+ }
47
+ catch {
48
+ this.stateStore = null;
49
+ }
50
+ }
51
+ async start() {
52
+ // 当前 RoutingStateManager 仅提供 routingStateStore,不需要后台任务。
53
+ }
54
+ async stop() {
55
+ // 未来如需 compact/迁移 sticky 状态,可在此添加逻辑;当前为 no-op。
56
+ }
57
+ getRoutingStateStore() {
58
+ return this.stateStore;
59
+ }
60
+ }
61
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/manager/modules/routing/index.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,yBAAyB;IAC3B,EAAE,GAAG,SAAS,CAAC;IAEhB,UAAU,GAAwC,IAAI,CAAC;IACvD,aAAa,GAAmB,IAAI,CAAC;IAErC,eAAe;QACrB,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC,aAAa,CAAC;QAC5B,CAAC;QACD,MAAM,GAAG,GACP,OAAO,CAAC,GAAG,CAAC,wBAAwB;YACpC,OAAO,CAAC,GAAG,CAAC,iBAAiB;YAC7B,EAAE,CAAC;QACL,MAAM,UAAU,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3E,MAAM,OAAO,GACX,UAAU,KAAK,GAAG;YAClB,UAAU,KAAK,MAAM;YACrB,UAAU,KAAK,KAAK;YACpB,UAAU,KAAK,IAAI,CAAC;QACtB,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;QAC7B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAwB;QACjC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACvB,OAAO;QACT,CAAC;QACD,6DAA6D;QAC7D,qDAAqD;QACrD,IAAI,CAAC;YACH,6EAA6E;YAC7E,MAAM,GAAG,GAAG,OAAO,CAAC,qEAAqE,CAGxF,CAAC;YACF,MAAM,MAAM,GAAG,OAAO,GAAG,EAAE,+BAA+B,KAAK,UAAU;gBACvE,CAAC,CAAC,GAAG,CAAC,+BAA+B;gBACrC,CAAC,CAAC,SAAS,CAAC;YACd,MAAM,MAAM,GAAG,OAAO,GAAG,EAAE,gCAAgC,KAAK,UAAU;gBACxE,CAAC,CAAC,GAAG,CAAC,gCAAgC;gBACtC,CAAC,CAAC,SAAS,CAAC;YACd,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;gBACvB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;gBACvB,OAAO;YACT,CAAC;YACD,IAAI,CAAC,UAAU,GAAG;gBAChB,QAAQ,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC;gBACtC,SAAS,EAAE,CAAC,GAAW,EAAE,KAAqC,EAAE,EAAE;oBAChE,MAAM,CAAC,GAAG,EAAE,KAAY,CAAC,CAAC;gBAC5B,CAAC;aACF,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,wDAAwD;IAC1D,CAAC;IAED,KAAK,CAAC,IAAI;QACR,+CAA+C;IACjD,CAAC;IAED,oBAAoB;QAClB,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;CACF"}