@jsonstudio/rcc 0.89.1803 → 0.89.1959

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 (283) hide show
  1. package/configsamples/config.json +19 -0
  2. package/configsamples/provider/deepseek/config.v1.json +59 -0
  3. package/dist/build-info.js +2 -2
  4. package/dist/cli/commands/claude.d.ts +4 -0
  5. package/dist/cli/commands/claude.js +56 -0
  6. package/dist/cli/commands/claude.js.map +1 -0
  7. package/dist/cli/commands/clock-admin.d.ts +20 -0
  8. package/dist/cli/commands/clock-admin.js +234 -0
  9. package/dist/cli/commands/clock-admin.js.map +1 -0
  10. package/dist/cli/commands/code.d.ts +0 -42
  11. package/dist/cli/commands/code.js +4 -414
  12. package/dist/cli/commands/code.js.map +1 -1
  13. package/dist/cli/commands/codex.d.ts +4 -0
  14. package/dist/cli/commands/codex.js +43 -0
  15. package/dist/cli/commands/codex.js.map +1 -0
  16. package/dist/cli/commands/examples.js +13 -16
  17. package/dist/cli/commands/examples.js.map +1 -1
  18. package/dist/cli/commands/init/basic.d.ts +40 -0
  19. package/dist/cli/commands/init/basic.js +482 -0
  20. package/dist/cli/commands/init/basic.js.map +1 -0
  21. package/dist/cli/commands/init/camoufox.d.ts +7 -0
  22. package/dist/cli/commands/init/camoufox.js +59 -0
  23. package/dist/cli/commands/init/camoufox.js.map +1 -0
  24. package/dist/cli/commands/init/interactive.d.ts +18 -0
  25. package/dist/cli/commands/init/interactive.js +223 -0
  26. package/dist/cli/commands/init/interactive.js.map +1 -0
  27. package/dist/cli/commands/init/shared.d.ts +66 -0
  28. package/dist/cli/commands/init/shared.js +9 -0
  29. package/dist/cli/commands/init/shared.js.map +1 -0
  30. package/dist/cli/commands/init/workflows.d.ts +29 -0
  31. package/dist/cli/commands/init/workflows.js +341 -0
  32. package/dist/cli/commands/init/workflows.js.map +1 -0
  33. package/dist/cli/commands/init.d.ts +2 -26
  34. package/dist/cli/commands/init.js +220 -53
  35. package/dist/cli/commands/init.js.map +1 -1
  36. package/dist/cli/commands/launcher-kernel.d.ts +78 -0
  37. package/dist/cli/commands/launcher-kernel.js +1194 -0
  38. package/dist/cli/commands/launcher-kernel.js.map +1 -0
  39. package/dist/cli/commands/start.js +27 -1
  40. package/dist/cli/commands/start.js.map +1 -1
  41. package/dist/cli/commands/status.d.ts +2 -0
  42. package/dist/cli/commands/status.js +24 -1
  43. package/dist/cli/commands/status.js.map +1 -1
  44. package/dist/cli/commands/stop.d.ts +1 -0
  45. package/dist/cli/commands/stop.js +201 -4
  46. package/dist/cli/commands/stop.js.map +1 -1
  47. package/dist/cli/commands/tmux-inject.d.ts +20 -0
  48. package/dist/cli/commands/tmux-inject.js +212 -0
  49. package/dist/cli/commands/tmux-inject.js.map +1 -0
  50. package/dist/cli/config/init-provider-catalog.js +34 -0
  51. package/dist/cli/config/init-provider-catalog.js.map +1 -1
  52. package/dist/cli/register/claude-command.d.ts +3 -0
  53. package/dist/cli/register/claude-command.js +5 -0
  54. package/dist/cli/register/claude-command.js.map +1 -0
  55. package/dist/cli/register/clock-admin-command.d.ts +3 -0
  56. package/dist/cli/register/clock-admin-command.js +5 -0
  57. package/dist/cli/register/clock-admin-command.js.map +1 -0
  58. package/dist/cli/register/codex-command.d.ts +3 -0
  59. package/dist/cli/register/codex-command.js +5 -0
  60. package/dist/cli/register/codex-command.js.map +1 -0
  61. package/dist/cli/register/status-config-commands.d.ts +2 -0
  62. package/dist/cli/register/status-config-commands.js.map +1 -1
  63. package/dist/cli/register/tmux-inject-command.d.ts +3 -0
  64. package/dist/cli/register/tmux-inject-command.js +5 -0
  65. package/dist/cli/register/tmux-inject-command.js.map +1 -0
  66. package/dist/cli/server/port-utils.d.ts +3 -2
  67. package/dist/cli/server/port-utils.js +171 -32
  68. package/dist/cli/server/port-utils.js.map +1 -1
  69. package/dist/cli.js +45 -6
  70. package/dist/cli.js.map +1 -1
  71. package/dist/client/gemini/gemini-protocol-client.js +56 -5
  72. package/dist/client/gemini/gemini-protocol-client.js.map +1 -1
  73. package/dist/commands/token-daemon.js +59 -7
  74. package/dist/commands/token-daemon.js.map +1 -1
  75. package/dist/commands/validate.js +87 -15
  76. package/dist/commands/validate.js.map +1 -1
  77. package/dist/config/routecodex-config-loader.js +31 -2
  78. package/dist/config/routecodex-config-loader.js.map +1 -1
  79. package/dist/docs/daemon-admin-ui.html +948 -74
  80. package/dist/index.d.ts +1 -0
  81. package/dist/index.js +325 -37
  82. package/dist/index.js.map +1 -1
  83. package/dist/manager/quota/provider-quota-center.js +8 -14
  84. package/dist/manager/quota/provider-quota-center.js.map +1 -1
  85. package/dist/modules/llmswitch/bridge.d.ts +39 -0
  86. package/dist/modules/llmswitch/bridge.js +169 -0
  87. package/dist/modules/llmswitch/bridge.js.map +1 -1
  88. package/dist/modules/pipeline/utils/colored-logger.js +1 -1
  89. package/dist/modules/pipeline/utils/colored-logger.js.map +1 -1
  90. package/dist/providers/auth/deepseek-account-auth.d.ts +39 -0
  91. package/dist/providers/auth/deepseek-account-auth.js +329 -0
  92. package/dist/providers/auth/deepseek-account-auth.js.map +1 -0
  93. package/dist/providers/auth/deepseek-account-token-acquirer.d.ts +15 -0
  94. package/dist/providers/auth/deepseek-account-token-acquirer.js +644 -0
  95. package/dist/providers/auth/deepseek-account-token-acquirer.js.map +1 -0
  96. package/dist/providers/auth/oauth-lifecycle.js +26 -4
  97. package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
  98. package/dist/providers/auth/oauth-repair-cooldown.d.ts +5 -0
  99. package/dist/providers/auth/oauth-repair-cooldown.js +39 -0
  100. package/dist/providers/auth/oauth-repair-cooldown.js.map +1 -1
  101. package/dist/providers/auth/token-scanner/index.d.ts +6 -0
  102. package/dist/providers/auth/token-scanner/index.js +53 -0
  103. package/dist/providers/auth/token-scanner/index.js.map +1 -1
  104. package/dist/providers/core/api/provider-config.d.ts +17 -2
  105. package/dist/providers/core/api/provider-types.d.ts +6 -0
  106. package/dist/providers/core/api/provider-types.js.map +1 -1
  107. package/dist/providers/core/config/camoufox-launcher.d.ts +7 -0
  108. package/dist/providers/core/config/camoufox-launcher.js +68 -21
  109. package/dist/providers/core/config/camoufox-launcher.js.map +1 -1
  110. package/dist/providers/core/config/service-profiles.js +19 -0
  111. package/dist/providers/core/config/service-profiles.js.map +1 -1
  112. package/dist/providers/core/contracts/deepseek-provider-contract.d.ts +34 -0
  113. package/dist/providers/core/contracts/deepseek-provider-contract.js +100 -0
  114. package/dist/providers/core/contracts/deepseek-provider-contract.js.map +1 -0
  115. package/dist/providers/core/runtime/anthropic-http-provider.d.ts +0 -5
  116. package/dist/providers/core/runtime/anthropic-http-provider.js +0 -26
  117. package/dist/providers/core/runtime/anthropic-http-provider.js.map +1 -1
  118. package/dist/providers/core/runtime/deepseek-http-provider.d.ts +35 -0
  119. package/dist/providers/core/runtime/deepseek-http-provider.js +373 -0
  120. package/dist/providers/core/runtime/deepseek-http-provider.js.map +1 -0
  121. package/dist/providers/core/runtime/deepseek-session-pow.d.ts +55 -0
  122. package/dist/providers/core/runtime/deepseek-session-pow.js +422 -0
  123. package/dist/providers/core/runtime/deepseek-session-pow.js.map +1 -0
  124. package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +0 -3
  125. package/dist/providers/core/runtime/gemini-cli-http-provider.js +0 -72
  126. package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
  127. package/dist/providers/core/runtime/gemini-http-provider.d.ts +1 -7
  128. package/dist/providers/core/runtime/gemini-http-provider.js +3 -110
  129. package/dist/providers/core/runtime/gemini-http-provider.js.map +1 -1
  130. package/dist/providers/core/runtime/http-request-executor.d.ts +1 -0
  131. package/dist/providers/core/runtime/http-request-executor.js +4 -0
  132. package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
  133. package/dist/providers/core/runtime/http-transport-provider.d.ts +10 -4
  134. package/dist/providers/core/runtime/http-transport-provider.js +308 -82
  135. package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
  136. package/dist/providers/core/runtime/iflow-http-provider.d.ts +0 -4
  137. package/dist/providers/core/runtime/iflow-http-provider.js +0 -28
  138. package/dist/providers/core/runtime/iflow-http-provider.js.map +1 -1
  139. package/dist/providers/core/runtime/provider-factory.d.ts +5 -0
  140. package/dist/providers/core/runtime/provider-factory.js +59 -6
  141. package/dist/providers/core/runtime/provider-factory.js.map +1 -1
  142. package/dist/providers/core/runtime/responses-provider.d.ts +0 -2
  143. package/dist/providers/core/runtime/responses-provider.js +0 -11
  144. package/dist/providers/core/runtime/responses-provider.js.map +1 -1
  145. package/dist/providers/core/strategies/oauth-device-flow.js +16 -1
  146. package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
  147. package/dist/providers/core/utils/provider-type-utils.js +2 -1
  148. package/dist/providers/core/utils/provider-type-utils.js.map +1 -1
  149. package/dist/providers/profile/families/anthropic-profile.d.ts +2 -0
  150. package/dist/providers/profile/families/anthropic-profile.js +32 -0
  151. package/dist/providers/profile/families/anthropic-profile.js.map +1 -0
  152. package/dist/providers/profile/families/antigravity-profile.d.ts +2 -0
  153. package/dist/providers/profile/families/antigravity-profile.js +109 -0
  154. package/dist/providers/profile/families/antigravity-profile.js.map +1 -0
  155. package/dist/providers/profile/families/glm-profile.d.ts +2 -0
  156. package/dist/providers/profile/families/glm-profile.js +48 -0
  157. package/dist/providers/profile/families/glm-profile.js.map +1 -0
  158. package/dist/providers/profile/families/iflow-profile.d.ts +2 -0
  159. package/dist/providers/profile/families/iflow-profile.js +232 -0
  160. package/dist/providers/profile/families/iflow-profile.js.map +1 -0
  161. package/dist/providers/profile/families/qwen-profile.d.ts +2 -0
  162. package/dist/providers/profile/families/qwen-profile.js +14 -0
  163. package/dist/providers/profile/families/qwen-profile.js.map +1 -0
  164. package/dist/providers/profile/families/responses-profile.d.ts +2 -0
  165. package/dist/providers/profile/families/responses-profile.js +28 -0
  166. package/dist/providers/profile/families/responses-profile.js.map +1 -0
  167. package/dist/providers/profile/profile-contracts.d.ts +74 -0
  168. package/dist/providers/profile/profile-contracts.js +2 -0
  169. package/dist/providers/profile/profile-contracts.js.map +1 -0
  170. package/dist/providers/profile/profile-registry.d.ts +3 -0
  171. package/dist/providers/profile/profile-registry.js +40 -0
  172. package/dist/providers/profile/profile-registry.js.map +1 -0
  173. package/dist/providers/profile/provider-directory.d.ts +2 -0
  174. package/dist/providers/profile/provider-directory.js +55 -0
  175. package/dist/providers/profile/provider-directory.js.map +1 -0
  176. package/dist/providers/profile/provider-profile-loader.js +43 -3
  177. package/dist/providers/profile/provider-profile-loader.js.map +1 -1
  178. package/dist/providers/profile/provider-profile.d.ts +8 -0
  179. package/dist/scripts/deepseek/pow-solver.mjs +146 -0
  180. package/dist/scripts/deepseek/sha3_wasm_bg.7b9ca65ddd.wasm +0 -0
  181. package/dist/server/handlers/config-admin-handler.js +27 -0
  182. package/dist/server/handlers/config-admin-handler.js.map +1 -1
  183. package/dist/server/runtime/http-server/clock-client-registry.d.ts +113 -0
  184. package/dist/server/runtime/http-server/clock-client-registry.js +592 -0
  185. package/dist/server/runtime/http-server/clock-client-registry.js.map +1 -0
  186. package/dist/server/runtime/http-server/clock-client-routes.d.ts +2 -0
  187. package/dist/server/runtime/http-server/clock-client-routes.js +481 -0
  188. package/dist/server/runtime/http-server/clock-client-routes.js.map +1 -0
  189. package/dist/server/runtime/http-server/clock-daemon-inject-config.d.ts +1 -0
  190. package/dist/server/runtime/http-server/clock-daemon-inject-config.js +11 -0
  191. package/dist/server/runtime/http-server/clock-daemon-inject-config.js.map +1 -0
  192. package/dist/server/runtime/http-server/daemon-admin/auth-handler.js +3 -3
  193. package/dist/server/runtime/http-server/daemon-admin/auth-handler.js.map +1 -1
  194. package/dist/server/runtime/http-server/daemon-admin/auth-session.d.ts +1 -0
  195. package/dist/server/runtime/http-server/daemon-admin/auth-session.js +18 -2
  196. package/dist/server/runtime/http-server/daemon-admin/auth-session.js.map +1 -1
  197. package/dist/server/runtime/http-server/daemon-admin/control-handler.js +2 -15
  198. package/dist/server/runtime/http-server/daemon-admin/control-handler.js.map +1 -1
  199. package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js +65 -7
  200. package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js.map +1 -1
  201. package/dist/server/runtime/http-server/executor-metadata.js +37 -1
  202. package/dist/server/runtime/http-server/executor-metadata.js.map +1 -1
  203. package/dist/server/runtime/http-server/executor-provider.js +55 -0
  204. package/dist/server/runtime/http-server/executor-provider.js.map +1 -1
  205. package/dist/server/runtime/http-server/executor-response.js +49 -1
  206. package/dist/server/runtime/http-server/executor-response.js.map +1 -1
  207. package/dist/server/runtime/http-server/index.d.ts +10 -0
  208. package/dist/server/runtime/http-server/index.js +534 -9
  209. package/dist/server/runtime/http-server/index.js.map +1 -1
  210. package/dist/server/runtime/http-server/managed-process-probe.d.ts +6 -0
  211. package/dist/server/runtime/http-server/managed-process-probe.js +294 -0
  212. package/dist/server/runtime/http-server/managed-process-probe.js.map +1 -0
  213. package/dist/server/runtime/http-server/middleware.js +16 -1
  214. package/dist/server/runtime/http-server/middleware.js.map +1 -1
  215. package/dist/server/runtime/http-server/provider-utils.js +6 -2
  216. package/dist/server/runtime/http-server/provider-utils.js.map +1 -1
  217. package/dist/server/runtime/http-server/request-executor.d.ts +1 -0
  218. package/dist/server/runtime/http-server/request-executor.js +360 -35
  219. package/dist/server/runtime/http-server/request-executor.js.map +1 -1
  220. package/dist/server/runtime/http-server/routes.js +95 -3
  221. package/dist/server/runtime/http-server/routes.js.map +1 -1
  222. package/dist/server/runtime/http-server/stats-manager.d.ts +10 -0
  223. package/dist/server/runtime/http-server/stats-manager.js +119 -16
  224. package/dist/server/runtime/http-server/stats-manager.js.map +1 -1
  225. package/dist/server/runtime/http-server/tmux-session-probe.d.ts +3 -0
  226. package/dist/server/runtime/http-server/tmux-session-probe.js +101 -0
  227. package/dist/server/runtime/http-server/tmux-session-probe.js.map +1 -0
  228. package/dist/server/utils/stage-logger.js +21 -5
  229. package/dist/server/utils/stage-logger.js.map +1 -1
  230. package/dist/token-daemon/index.js +59 -10
  231. package/dist/token-daemon/index.js.map +1 -1
  232. package/dist/token-daemon/server-utils.d.ts +1 -0
  233. package/dist/token-daemon/server-utils.js +4 -1
  234. package/dist/token-daemon/server-utils.js.map +1 -1
  235. package/dist/token-daemon/token-daemon.js +38 -4
  236. package/dist/token-daemon/token-daemon.js.map +1 -1
  237. package/dist/token-daemon/token-types.d.ts +1 -1
  238. package/dist/token-daemon/token-types.js +2 -1
  239. package/dist/token-daemon/token-types.js.map +1 -1
  240. package/dist/token-daemon/token-utils.js +5 -2
  241. package/dist/token-daemon/token-utils.js.map +1 -1
  242. package/dist/utils/clock-client-token.d.ts +3 -0
  243. package/dist/utils/clock-client-token.js +54 -0
  244. package/dist/utils/clock-client-token.js.map +1 -0
  245. package/dist/utils/managed-server-pids.d.ts +25 -0
  246. package/dist/utils/managed-server-pids.js +176 -0
  247. package/dist/utils/managed-server-pids.js.map +1 -0
  248. package/dist/utils/process-lifecycle-logger.d.ts +8 -0
  249. package/dist/utils/process-lifecycle-logger.js +151 -0
  250. package/dist/utils/process-lifecycle-logger.js.map +1 -0
  251. package/dist/utils/runtime-exit-forensics.d.ts +30 -0
  252. package/dist/utils/runtime-exit-forensics.js +101 -0
  253. package/dist/utils/runtime-exit-forensics.js.map +1 -0
  254. package/dist/utils/shutdown-caller-context.d.ts +22 -0
  255. package/dist/utils/shutdown-caller-context.js +25 -0
  256. package/dist/utils/shutdown-caller-context.js.map +1 -0
  257. package/docs/PROVIDERS_BUILTIN.md +8 -0
  258. package/docs/PROVIDER_TYPES.md +3 -1
  259. package/docs/SERVERTOOL_PRE_COMMAND_HOOKS.md +85 -0
  260. package/docs/clock-client-daemon-design.md +343 -0
  261. package/docs/daemon-admin-ui.html +948 -74
  262. package/docs/providers/deepseek-web-provider-design.md +192 -0
  263. package/docs/routing-instructions.md +4 -1
  264. package/docs/stop-message-auto.md +4 -3
  265. package/docs/v2-architecture/PROVIDER-V2-CHANGESET-RELEASE-CHECKLIST.md +80 -0
  266. package/docs/v2-architecture/PROVIDER-V2-LAYERING-ADR-DRAFT.md +225 -0
  267. package/docs/v2-architecture/PROVIDER-V2-MIGRATION-MATRIX-DRAFT.md +88 -0
  268. package/docs/v2-architecture/PROVIDER-V2-PHASED-MIGRATION-ROLLBACK-DRAFT.md +164 -0
  269. package/docs/v2-architecture/PROVIDER-V2-PROFILE-API-REGISTRY-DRAFT.md +201 -0
  270. package/docs/v2-architecture/PROVIDER-V2-PROFILE-GEMINI-DRAFT.md +56 -0
  271. package/docs/v2-architecture/PROVIDER-V2-REFACTOR-OVERVIEW-DRAFT.md +102 -0
  272. package/docs/v2-architecture/PROVIDER-V2-VERIFICATION-MATRIX-DRAFT.md +163 -0
  273. package/package.json +10 -9
  274. package/scripts/copy-compat-assets.mjs +18 -0
  275. package/scripts/copy-modules-config.mjs +1 -0
  276. package/scripts/deepseek/pow-solver.mjs +146 -0
  277. package/scripts/deepseek/sha3_wasm_bg.7b9ca65ddd.wasm +0 -0
  278. package/scripts/ensure-cli-executable.mjs +64 -0
  279. package/scripts/install-global.sh +5 -2
  280. package/scripts/install.sh +1 -1
  281. package/scripts/monitor/daemon-kill-watch.mjs +184 -0
  282. package/scripts/monitor/port-kill-watch.sh +74 -0
  283. package/scripts/quick-install.sh +1 -1
@@ -4,12 +4,69 @@ import { attachProviderRuntimeMetadata } from '../../../providers/core/runtime/p
4
4
  import { extractAnthropicToolAliasMap } from './anthropic-tool-alias.js';
5
5
  import { enhanceProviderRequestId } from '../../utils/request-id-manager.js';
6
6
  import { buildRequestMetadata, cloneClientHeaders, decorateMetadataForAttempt, ensureClientHeadersOnPayload, resolveClientRequestId } from './executor-metadata.js';
7
- import { describeRetryReason, isNetworkTransportError, shouldRetryProviderError, waitBeforeRetry } from './executor-provider.js';
7
+ import { describeRetryReason, shouldRetryProviderError, waitBeforeRetry } from './executor-provider.js';
8
8
  import { convertProviderResponse as bridgeConvertProviderResponse, createSnapshotRecorder as bridgeCreateSnapshotRecorder, } from '../../../modules/llmswitch/bridge.js';
9
+ import { getClockClientRegistry, injectClockClientPrompt } from './clock-client-registry.js';
9
10
  import { ensureHubPipeline, runHubPipeline } from './executor-pipeline.js';
10
11
  import { buildInfo } from '../../../build-info.js';
11
12
  const DEFAULT_MAX_PROVIDER_ATTEMPTS = 6;
12
13
  const DEFAULT_ANTIGRAVITY_MAX_PROVIDER_ATTEMPTS = 20;
14
+ const RETRYABLE_SSE_ERROR_CODE_HINTS = [
15
+ 'internal_network_failure',
16
+ 'network_error',
17
+ 'api_connection_error',
18
+ 'service_unavailable',
19
+ 'internal_server_error',
20
+ 'overloaded_error',
21
+ 'rate_limit_error',
22
+ 'request_timeout',
23
+ 'timeout'
24
+ ];
25
+ const RETRYABLE_SSE_MESSAGE_HINTS = [
26
+ 'internal network failure',
27
+ 'network failure',
28
+ 'network error',
29
+ 'temporarily unavailable',
30
+ 'temporarily unreachable',
31
+ 'upstream disconnected',
32
+ 'connection reset',
33
+ 'connection closed',
34
+ 'timed out',
35
+ 'timeout'
36
+ ];
37
+ function firstNonEmptyString(candidates) {
38
+ for (const candidate of candidates) {
39
+ if (typeof candidate !== 'string') {
40
+ continue;
41
+ }
42
+ const trimmed = candidate.trim();
43
+ if (trimmed) {
44
+ return trimmed;
45
+ }
46
+ }
47
+ return undefined;
48
+ }
49
+ function firstFiniteNumber(candidates) {
50
+ for (const candidate of candidates) {
51
+ if (typeof candidate === 'number' && Number.isFinite(candidate)) {
52
+ return candidate;
53
+ }
54
+ }
55
+ return undefined;
56
+ }
57
+ function isRetryableSseWrapperError(message, errorCode, status) {
58
+ if (typeof status === 'number' && Number.isFinite(status)) {
59
+ if (status === 408 || status === 425 || status === 429 || status >= 500) {
60
+ return true;
61
+ }
62
+ }
63
+ const normalizedCode = typeof errorCode === 'string' ? errorCode.trim().toLowerCase() : '';
64
+ if (normalizedCode && RETRYABLE_SSE_ERROR_CODE_HINTS.some((hint) => normalizedCode.includes(hint))) {
65
+ return true;
66
+ }
67
+ const loweredMessage = message.toLowerCase();
68
+ return RETRYABLE_SSE_MESSAGE_HINTS.some((hint) => loweredMessage.includes(hint));
69
+ }
13
70
  function resolveBoolFromEnv(value, fallback) {
14
71
  if (!value) {
15
72
  return fallback;
@@ -143,6 +200,48 @@ function injectAntigravityRetrySignal(metadata, signal) {
143
200
  ...(signal.avoidAllOnRetry === true ? { antigravityAvoidAllOnRetry: true } : {})
144
201
  };
145
202
  }
203
+ function normalizeSessionToken(value) {
204
+ if (typeof value !== 'string') {
205
+ return undefined;
206
+ }
207
+ const trimmed = value.trim();
208
+ return trimmed || undefined;
209
+ }
210
+ function inferClockClientTypeFromMetadata(metadata) {
211
+ const direct = normalizeSessionToken(metadata.clockClientType) ?? normalizeSessionToken(metadata.clientType);
212
+ if (direct) {
213
+ return direct;
214
+ }
215
+ const userAgent = normalizeSessionToken(metadata.userAgent)?.toLowerCase() ?? '';
216
+ if (userAgent.includes('codex')) {
217
+ return 'codex';
218
+ }
219
+ if (userAgent.includes('claude')) {
220
+ return 'claude';
221
+ }
222
+ return undefined;
223
+ }
224
+ function bindClockConversationSession(metadata) {
225
+ const conversationSessionId = normalizeSessionToken(metadata.sessionId);
226
+ if (!conversationSessionId) {
227
+ return;
228
+ }
229
+ const tmuxSessionId = normalizeSessionToken(metadata.tmuxSessionId);
230
+ const daemonId = normalizeSessionToken(metadata.clockDaemonId)
231
+ ?? normalizeSessionToken(metadata.clockClientDaemonId);
232
+ const clientType = inferClockClientTypeFromMetadata(metadata);
233
+ try {
234
+ getClockClientRegistry().bindConversationSession({
235
+ conversationSessionId,
236
+ ...(tmuxSessionId ? { tmuxSessionId } : {}),
237
+ ...(daemonId ? { daemonId } : {}),
238
+ ...(clientType ? { clientType } : {})
239
+ });
240
+ }
241
+ catch {
242
+ // best-effort only
243
+ }
244
+ }
146
245
  export class HubRequestExecutor {
147
246
  deps;
148
247
  constructor(deps) {
@@ -161,6 +260,7 @@ export class HubRequestExecutor {
161
260
  try {
162
261
  const hubPipeline = ensureHubPipeline(this.deps.getHubPipeline);
163
262
  const initialMetadata = buildRequestMetadata(input);
263
+ bindClockConversationSession(initialMetadata);
164
264
  const inboundClientHeaders = cloneClientHeaders(initialMetadata?.clientHeaders);
165
265
  const providerRequestId = input.requestId;
166
266
  const clientRequestId = resolveClientRequestId(initialMetadata, providerRequestId);
@@ -217,7 +317,26 @@ export class HubRequestExecutor {
217
317
  stream: metadataForAttempt.stream,
218
318
  attempt
219
319
  });
220
- const pipelineResult = await runHubPipeline(hubPipeline, input, metadataForAttempt);
320
+ let pipelineResult;
321
+ try {
322
+ pipelineResult = await runHubPipeline(hubPipeline, input, metadataForAttempt);
323
+ }
324
+ catch (pipelineError) {
325
+ const pipelineErrorCode = typeof pipelineError.code === 'string'
326
+ ? String(pipelineError.code).trim()
327
+ : '';
328
+ const pipelineErrorMessage = pipelineError instanceof Error
329
+ ? pipelineError.message
330
+ : String(pipelineError ?? 'Unknown error');
331
+ const isPoolExhaustedError = pipelineErrorCode === 'PROVIDER_NOT_AVAILABLE' ||
332
+ pipelineErrorCode === 'ERR_NO_PROVIDER_TARGET' ||
333
+ /all providers unavailable/i.test(pipelineErrorMessage) ||
334
+ /virtual router did not produce a provider target/i.test(pipelineErrorMessage);
335
+ if (lastError && isPoolExhaustedError) {
336
+ throw lastError;
337
+ }
338
+ throw pipelineError;
339
+ }
221
340
  const pipelineMetadata = pipelineResult.metadata ?? {};
222
341
  const mergedMetadata = { ...metadataForAttempt, ...pipelineMetadata };
223
342
  const mergedClientHeaders = cloneClientHeaders(mergedMetadata?.clientHeaders) || clientHeadersForAttempt;
@@ -251,6 +370,38 @@ export class HubRequestExecutor {
251
370
  }
252
371
  const runtimeKey = target.runtimeKey || this.deps.runtimeManager.resolveRuntimeKey(target.providerKey);
253
372
  if (!runtimeKey) {
373
+ const runtimeResolveError = Object.assign(new Error(`Runtime for provider ${target.providerKey} not initialized`), {
374
+ code: 'ERR_RUNTIME_NOT_FOUND',
375
+ requestId: input.requestId,
376
+ retryable: true
377
+ });
378
+ try {
379
+ const { emitProviderError } = await import('../../../providers/core/utils/provider-error-reporter.js');
380
+ emitProviderError({
381
+ error: runtimeResolveError,
382
+ stage: 'provider.runtime.resolve',
383
+ runtime: {
384
+ requestId: input.requestId,
385
+ providerKey: target.providerKey,
386
+ providerId: target.providerKey.split('.')[0],
387
+ providerType: String(target.providerType || 'unknown'),
388
+ providerProtocol: String(target.outboundProfile || ''),
389
+ routeName: pipelineResult.routingDecision?.routeName,
390
+ pipelineId: target.providerKey,
391
+ target
392
+ },
393
+ dependencies: this.deps.getModuleDependencies(),
394
+ recoverable: false,
395
+ affectsHealth: true,
396
+ details: {
397
+ reason: 'runtime_not_initialized',
398
+ providerKey: target.providerKey
399
+ }
400
+ });
401
+ }
402
+ catch {
403
+ // best-effort
404
+ }
254
405
  throw Object.assign(new Error(`Runtime for provider ${target.providerKey} not initialized`), {
255
406
  code: 'ERR_RUNTIME_NOT_FOUND',
256
407
  requestId: input.requestId
@@ -258,6 +409,40 @@ export class HubRequestExecutor {
258
409
  }
259
410
  const handle = this.deps.runtimeManager.getHandleByRuntimeKey(runtimeKey);
260
411
  if (!handle) {
412
+ const runtimeMissingError = Object.assign(new Error(`Provider runtime ${runtimeKey} not found`), {
413
+ code: 'ERR_PROVIDER_NOT_FOUND',
414
+ requestId: input.requestId,
415
+ retryable: true
416
+ });
417
+ try {
418
+ const { emitProviderError } = await import('../../../providers/core/utils/provider-error-reporter.js');
419
+ emitProviderError({
420
+ error: runtimeMissingError,
421
+ stage: 'provider.runtime.resolve',
422
+ runtime: {
423
+ requestId: input.requestId,
424
+ providerKey: target.providerKey,
425
+ providerId: target.providerKey.split('.')[0],
426
+ providerType: String(target.providerType || 'unknown'),
427
+ providerProtocol: String(target.outboundProfile || ''),
428
+ routeName: pipelineResult.routingDecision?.routeName,
429
+ pipelineId: target.providerKey,
430
+ runtimeKey,
431
+ target
432
+ },
433
+ dependencies: this.deps.getModuleDependencies(),
434
+ recoverable: false,
435
+ affectsHealth: true,
436
+ details: {
437
+ reason: 'runtime_handle_missing',
438
+ providerKey: target.providerKey,
439
+ runtimeKey
440
+ }
441
+ });
442
+ }
443
+ catch {
444
+ // best-effort
445
+ }
261
446
  throw Object.assign(new Error(`Provider runtime ${runtimeKey} not found`), {
262
447
  code: 'ERR_PROVIDER_NOT_FOUND',
263
448
  requestId: input.requestId
@@ -364,22 +549,57 @@ export class HubRequestExecutor {
364
549
  response: normalized,
365
550
  pipelineMetadata: mergedMetadata
366
551
  });
367
- // For Antigravity/Gemini, we may receive an error-shaped response (status=429/400) instead of a thrown error,
368
- // so llmswitch-core servertool can attempt thoughtSignature bootstrap + replay.
369
- // If it is still an error after conversion, treat it as a provider failure and continue the retry loop.
370
- if (typeof converted.status === 'number' &&
371
- converted.status >= 400 &&
552
+ // Treat upstream 429 as provider failure across protocols to avoid
553
+ // silently returning success and to let Virtual Router failover to other candidates.
554
+ // Keep existing Gemini compatibility behavior for 400/4xx thoughtSignature-like failures.
555
+ const convertedStatus = typeof converted.status === 'number' ? converted.status : undefined;
556
+ const isGlobalRetryable429 = convertedStatus === 429;
557
+ const isGeminiCompatFailure = typeof convertedStatus === 'number' &&
558
+ convertedStatus >= 400 &&
372
559
  (isAntigravityProviderKey(target.providerKey) ||
373
560
  (typeof target.providerKey === 'string' && target.providerKey.startsWith('gemini-cli.'))) &&
374
- providerProtocol === 'gemini-chat') {
561
+ providerProtocol === 'gemini-chat';
562
+ if (isGlobalRetryable429 || isGeminiCompatFailure) {
375
563
  const bodyForError = converted.body && typeof converted.body === 'object' ? converted.body : undefined;
376
564
  const errMsg = bodyForError && bodyForError.error && typeof bodyForError.error === 'object'
377
565
  ? String(bodyForError.error.message || bodyForError.error || '')
378
566
  : '';
379
- const errorToThrow = new Error(errMsg && errMsg.trim().length ? errMsg : `HTTP ${converted.status}`);
380
- errorToThrow.statusCode = converted.status;
381
- errorToThrow.status = converted.status;
567
+ const statusCode = typeof convertedStatus === 'number' ? convertedStatus : 500;
568
+ const errorToThrow = new Error(errMsg && errMsg.trim().length ? errMsg : `HTTP ${statusCode}`);
569
+ errorToThrow.statusCode = statusCode;
570
+ errorToThrow.status = statusCode;
382
571
  errorToThrow.response = { data: bodyForError };
572
+ try {
573
+ const { emitProviderError } = await import('../../../providers/core/utils/provider-error-reporter.js');
574
+ emitProviderError({
575
+ error: errorToThrow,
576
+ stage: 'provider.http',
577
+ runtime: {
578
+ requestId: input.requestId,
579
+ providerKey: target.providerKey,
580
+ providerId: handle.providerId,
581
+ providerType: handle.providerType,
582
+ providerFamily: handle.providerFamily,
583
+ providerProtocol,
584
+ routeName: pipelineResult.routingDecision?.routeName,
585
+ pipelineId: target.providerKey,
586
+ target,
587
+ runtimeKey
588
+ },
589
+ dependencies: this.deps.getModuleDependencies(),
590
+ statusCode,
591
+ recoverable: statusCode === 429,
592
+ affectsHealth: true,
593
+ details: {
594
+ source: 'converted_response_status',
595
+ convertedStatus: statusCode,
596
+ wrappedErrorResponse: true
597
+ }
598
+ });
599
+ }
600
+ catch {
601
+ // best-effort; never block retry/failover path
602
+ }
383
603
  throw errorToThrow;
384
604
  }
385
605
  const usage = this.extractUsageFromResult(converted, mergedMetadata);
@@ -434,11 +654,9 @@ export class HubRequestExecutor {
434
654
  recordAttempt({ error: true });
435
655
  const singleProviderPool = Boolean(initialRoutePool && initialRoutePool.length === 1 && initialRoutePool[0] === target.providerKey);
436
656
  if (singleProviderPool) {
437
- if (isNetworkTransportError(error)) {
438
- await waitBeforeRetry(error);
439
- }
657
+ await waitBeforeRetry(error);
440
658
  }
441
- else if (target.providerKey) {
659
+ if (!singleProviderPool && target.providerKey) {
442
660
  const is429 = status === 429;
443
661
  if (isAntigravityProviderKey(target.providerKey) && (isVerify || is429)) {
444
662
  // For Antigravity 403 verify / 429 states:
@@ -515,12 +733,21 @@ export class HubRequestExecutor {
515
733
  if (body && typeof body === 'object') {
516
734
  const wrapperError = this.extractSseWrapperError(body);
517
735
  if (wrapperError) {
518
- const error = new Error(`[RequestExecutor] Upstream SSE terminated: ${wrapperError}`);
736
+ const codeSuffix = wrapperError.errorCode ? ` [${wrapperError.errorCode}]` : '';
737
+ const error = new Error(`Upstream SSE error event${codeSuffix}: ${wrapperError.message}`);
519
738
  error.code = 'SSE_DECODE_ERROR';
739
+ if (wrapperError.errorCode) {
740
+ error.upstreamCode = wrapperError.errorCode;
741
+ }
742
+ error.retryable = wrapperError.retryable;
743
+ if (wrapperError.retryable) {
744
+ error.status = 503;
745
+ error.statusCode = 503;
746
+ }
520
747
  throw error;
521
748
  }
522
749
  }
523
- if (options.processMode === 'passthrough') {
750
+ if (options.processMode === 'passthrough' && !options.wantsStream) {
524
751
  return options.response;
525
752
  }
526
753
  const entry = (options.entryEndpoint || '').toLowerCase();
@@ -550,6 +777,12 @@ export class HubRequestExecutor {
550
777
  const baseContext = {
551
778
  ...(metadataBag ?? {})
552
779
  };
780
+ if (baseContext.capturedChatRequest === undefined &&
781
+ options.originalRequest &&
782
+ typeof options.originalRequest === 'object' &&
783
+ !Array.isArray(options.originalRequest)) {
784
+ baseContext.capturedChatRequest = options.originalRequest;
785
+ }
553
786
  if (typeof metadataBag?.routeName === 'string') {
554
787
  baseContext.routeId = metadataBag.routeName;
555
788
  }
@@ -636,6 +869,7 @@ export class HubRequestExecutor {
636
869
  delete nestedMetadata.clientHeaders;
637
870
  delete nestedMetadata.clientRequestId;
638
871
  }
872
+ bindClockConversationSession(nestedMetadata);
639
873
  const nestedInput = {
640
874
  entryEndpoint: nestedEntry,
641
875
  method: 'POST',
@@ -645,6 +879,26 @@ export class HubRequestExecutor {
645
879
  body: reenterOpts.body,
646
880
  metadata: nestedMetadata
647
881
  };
882
+ try {
883
+ const requestBody = reenterOpts.body;
884
+ const messages = Array.isArray(requestBody.messages) ? requestBody.messages : [];
885
+ const lastUser = [...messages]
886
+ .reverse()
887
+ .find((entry) => entry && typeof entry === 'object' && entry.role === 'user');
888
+ const text = typeof lastUser?.content === 'string' ? String(lastUser.content) : '';
889
+ if (text.includes('<**clock:{') && text.includes('}**>')) {
890
+ await injectClockClientPrompt({
891
+ tmuxSessionId: typeof nestedMetadata.tmuxSessionId === 'string' ? nestedMetadata.tmuxSessionId : undefined,
892
+ sessionId: typeof nestedMetadata.sessionId === 'string' ? nestedMetadata.sessionId : undefined,
893
+ text,
894
+ requestId: reenterOpts.requestId,
895
+ source: 'servertool.reenter'
896
+ });
897
+ }
898
+ }
899
+ catch {
900
+ // best-effort only
901
+ }
648
902
  const nestedResult = await this.execute(nestedInput);
649
903
  const nestedBody = nestedResult.body && typeof nestedResult.body === 'object'
650
904
  ? nestedResult.body
@@ -668,23 +922,10 @@ export class HubRequestExecutor {
668
922
  body: { __sse_responses: converted.__sse_responses }
669
923
  };
670
924
  }
671
- const merged = {
925
+ return {
672
926
  ...options.response,
673
927
  body: converted.body ?? body
674
928
  };
675
- // Special case: some Antigravity/Gemini upstream failures are intentionally passed through as
676
- // an error-shaped response (status=429/400) so llmswitch-core servertool can recover via followup.
677
- // If recovery succeeded, the final client payload will NOT contain an error envelope.
678
- if (typeof options.response.status === 'number' && options.response.status >= 400) {
679
- const out = merged.body;
680
- if (out && typeof out === 'object' && !Array.isArray(out)) {
681
- const hasError = Object.prototype.hasOwnProperty.call(out, 'error');
682
- if (!hasError) {
683
- merged.status = 200;
684
- }
685
- }
686
- }
687
- return merged;
688
929
  }
689
930
  catch (error) {
690
931
  const err = error;
@@ -714,10 +955,11 @@ export class HubRequestExecutor {
714
955
  if (!record || typeof record !== 'object' || depth < 0) {
715
956
  return undefined;
716
957
  }
717
- const mode = record.mode;
718
- const errVal = record.error;
719
- if (mode === 'sse' && typeof errVal === 'string' && errVal.trim()) {
720
- return errVal.trim();
958
+ if (record.mode === 'sse') {
959
+ const normalized = this.normalizeSseWrapperErrorValue(record.error, depth);
960
+ if (normalized) {
961
+ return normalized;
962
+ }
721
963
  }
722
964
  const nestedKeys = ['body', 'data', 'payload', 'response'];
723
965
  for (const key of nestedKeys) {
@@ -732,6 +974,89 @@ export class HubRequestExecutor {
732
974
  }
733
975
  return undefined;
734
976
  }
977
+ normalizeSseWrapperErrorValue(value, depth) {
978
+ if (value === undefined || value === null || depth < 0) {
979
+ return undefined;
980
+ }
981
+ if (typeof value === 'string') {
982
+ const trimmed = value.trim();
983
+ if (!trimmed) {
984
+ return undefined;
985
+ }
986
+ if (depth > 0 && (trimmed.startsWith('{') || trimmed.startsWith('['))) {
987
+ try {
988
+ const parsed = JSON.parse(trimmed);
989
+ const parsedInfo = this.normalizeSseWrapperErrorValue(parsed, depth - 1);
990
+ if (parsedInfo) {
991
+ return parsedInfo;
992
+ }
993
+ }
994
+ catch {
995
+ // fallback to raw string
996
+ }
997
+ }
998
+ return {
999
+ message: trimmed,
1000
+ retryable: isRetryableSseWrapperError(trimmed)
1001
+ };
1002
+ }
1003
+ if (typeof value !== 'object' || Array.isArray(value)) {
1004
+ return undefined;
1005
+ }
1006
+ const record = value;
1007
+ const directMessage = firstNonEmptyString([
1008
+ record.message,
1009
+ record.error_message,
1010
+ record.errorMessage
1011
+ ]);
1012
+ const directCode = firstNonEmptyString([
1013
+ record.code,
1014
+ record.error_code,
1015
+ record.errorCode,
1016
+ record.type
1017
+ ]);
1018
+ const directStatus = firstFiniteNumber([
1019
+ record.status,
1020
+ record.statusCode,
1021
+ record.status_code,
1022
+ record.http_status
1023
+ ]);
1024
+ if (depth > 0) {
1025
+ for (const key of ['error', 'data', 'payload', 'details', 'body', 'response']) {
1026
+ const nestedInfo = this.normalizeSseWrapperErrorValue(record[key], depth - 1);
1027
+ if (nestedInfo) {
1028
+ const mergedCode = nestedInfo.errorCode ?? directCode;
1029
+ const retryable = nestedInfo.retryable || isRetryableSseWrapperError(nestedInfo.message, mergedCode, directStatus);
1030
+ return {
1031
+ message: nestedInfo.message,
1032
+ ...(mergedCode ? { errorCode: mergedCode } : {}),
1033
+ retryable
1034
+ };
1035
+ }
1036
+ }
1037
+ }
1038
+ if (directMessage) {
1039
+ return {
1040
+ message: directMessage,
1041
+ ...(directCode ? { errorCode: directCode } : {}),
1042
+ retryable: isRetryableSseWrapperError(directMessage, directCode, directStatus)
1043
+ };
1044
+ }
1045
+ try {
1046
+ const serialized = JSON.stringify(record);
1047
+ if (serialized && serialized !== '{}') {
1048
+ return {
1049
+ message: serialized,
1050
+ ...(directCode ? { errorCode: directCode } : {}),
1051
+ retryable: isRetryableSseWrapperError(serialized, directCode, directStatus)
1052
+ };
1053
+ }
1054
+ }
1055
+ catch {
1056
+ // ignore stringify failures
1057
+ }
1058
+ return undefined;
1059
+ }
735
1060
  extractClientModelId(metadata, originalRequest) {
736
1061
  const candidates = [
737
1062
  metadata.clientModelId,