@jsonstudio/rcc 0.89.164 → 0.89.333

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 +18 -15
  2. package/dist/build-info.js +3 -3
  3. package/dist/build-info.js.map +1 -1
  4. package/dist/cli.js +32 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/client/gemini-cli/gemini-cli-protocol-client.js +28 -5
  7. package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -1
  8. package/dist/error-handling/quiet-error-handling-center.d.ts +9 -0
  9. package/dist/error-handling/quiet-error-handling-center.js +141 -0
  10. package/dist/error-handling/quiet-error-handling-center.js.map +1 -0
  11. package/dist/error-handling/route-error-hub.js +8 -2
  12. package/dist/error-handling/route-error-hub.js.map +1 -1
  13. package/dist/modules/pipeline/utils/colored-logger.d.ts +2 -0
  14. package/dist/modules/pipeline/utils/colored-logger.js +20 -3
  15. package/dist/modules/pipeline/utils/colored-logger.js.map +1 -1
  16. package/dist/providers/auth/antigravity-userinfo-helper.d.ts +10 -0
  17. package/dist/providers/auth/antigravity-userinfo-helper.js +140 -0
  18. package/dist/providers/auth/antigravity-userinfo-helper.js.map +1 -0
  19. package/dist/providers/auth/oauth-lifecycle.js +140 -8
  20. package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
  21. package/dist/providers/auth/token-scanner/index.d.ts +32 -0
  22. package/dist/providers/auth/token-scanner/index.js +86 -0
  23. package/dist/providers/auth/token-scanner/index.js.map +1 -0
  24. package/dist/providers/auth/tokenfile-auth.d.ts +17 -0
  25. package/dist/providers/auth/tokenfile-auth.js +27 -5
  26. package/dist/providers/auth/tokenfile-auth.js.map +1 -1
  27. package/dist/providers/core/api/provider-types.d.ts +10 -0
  28. package/dist/providers/core/config/oauth-flows.d.ts +2 -0
  29. package/dist/providers/core/config/oauth-flows.js.map +1 -1
  30. package/dist/providers/core/config/provider-oauth-configs.js +85 -0
  31. package/dist/providers/core/config/provider-oauth-configs.js.map +1 -1
  32. package/dist/providers/core/config/service-profiles.js +15 -1
  33. package/dist/providers/core/config/service-profiles.js.map +1 -1
  34. package/dist/providers/core/runtime/base-provider.d.ts +8 -1
  35. package/dist/providers/core/runtime/base-provider.js +176 -108
  36. package/dist/providers/core/runtime/base-provider.js.map +1 -1
  37. package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +9 -5
  38. package/dist/providers/core/runtime/gemini-cli-http-provider.js +271 -69
  39. package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
  40. package/dist/providers/core/runtime/gemini-http-provider.d.ts +1 -2
  41. package/dist/providers/core/runtime/gemini-http-provider.js +0 -12
  42. package/dist/providers/core/runtime/gemini-http-provider.js.map +1 -1
  43. package/dist/providers/core/runtime/http-request-executor.d.ts +42 -0
  44. package/dist/providers/core/runtime/http-request-executor.js +133 -0
  45. package/dist/providers/core/runtime/http-request-executor.js.map +1 -0
  46. package/dist/providers/core/runtime/http-transport-provider.d.ts +32 -12
  47. package/dist/providers/core/runtime/http-transport-provider.js +464 -426
  48. package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
  49. package/dist/providers/core/runtime/provider-error-classifier.d.ts +25 -0
  50. package/dist/providers/core/runtime/provider-error-classifier.js +149 -0
  51. package/dist/providers/core/runtime/provider-error-classifier.js.map +1 -0
  52. package/dist/providers/core/runtime/provider-error-types.d.ts +23 -0
  53. package/dist/providers/core/runtime/provider-error-types.js +2 -0
  54. package/dist/providers/core/runtime/provider-error-types.js.map +1 -0
  55. package/dist/providers/core/runtime/provider-factory.d.ts +1 -0
  56. package/dist/providers/core/runtime/provider-factory.js +43 -8
  57. package/dist/providers/core/runtime/provider-factory.js.map +1 -1
  58. package/dist/providers/core/runtime/responses-provider.d.ts +3 -3
  59. package/dist/providers/core/runtime/responses-provider.js +48 -114
  60. package/dist/providers/core/runtime/responses-provider.js.map +1 -1
  61. package/dist/providers/core/strategies/oauth-auth-code-flow.js +11 -3
  62. package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
  63. package/dist/providers/core/utils/http-client.d.ts +5 -0
  64. package/dist/providers/core/utils/http-client.js +29 -3
  65. package/dist/providers/core/utils/http-client.js.map +1 -1
  66. package/dist/providers/core/utils/provider-error-reporter.js +8 -2
  67. package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
  68. package/dist/providers/core/utils/snapshot-writer.js +5 -1
  69. package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
  70. package/dist/providers/profile/provider-profile-loader.js +8 -4
  71. package/dist/providers/profile/provider-profile-loader.js.map +1 -1
  72. package/dist/runtime/runtime-flags.d.ts +4 -0
  73. package/dist/runtime/runtime-flags.js +32 -0
  74. package/dist/runtime/runtime-flags.js.map +1 -0
  75. package/dist/server/handlers/handler-utils.js +29 -2
  76. package/dist/server/handlers/handler-utils.js.map +1 -1
  77. package/dist/server/handlers/messages-handler.js +27 -26
  78. package/dist/server/handlers/messages-handler.js.map +1 -1
  79. package/dist/server/handlers/responses-handler.js +35 -1
  80. package/dist/server/handlers/responses-handler.js.map +1 -1
  81. package/dist/server/runtime/http-server/index.d.ts +1 -0
  82. package/dist/server/runtime/http-server/index.js +39 -4
  83. package/dist/server/runtime/http-server/index.js.map +1 -1
  84. package/dist/server/runtime/http-server/request-executor.d.ts +4 -0
  85. package/dist/server/runtime/http-server/request-executor.js +99 -4
  86. package/dist/server/runtime/http-server/request-executor.js.map +1 -1
  87. package/dist/server/utils/sse-request-parser.d.ts +1 -0
  88. package/dist/server/utils/sse-request-parser.js +17 -6
  89. package/dist/server/utils/sse-request-parser.js.map +1 -1
  90. package/dist/server/utils/warmup-detector.d.ts +7 -0
  91. package/dist/server/utils/warmup-detector.js +125 -0
  92. package/dist/server/utils/warmup-detector.js.map +1 -0
  93. package/dist/server/utils/warmup-storm-tracker.d.ts +9 -0
  94. package/dist/server/utils/warmup-storm-tracker.js +61 -0
  95. package/dist/server/utils/warmup-storm-tracker.js.map +1 -0
  96. package/dist/utils/debug-utils.js +14 -0
  97. package/dist/utils/debug-utils.js.map +1 -1
  98. package/dist/utils/error-handler-registry.js +6 -5
  99. package/dist/utils/error-handler-registry.js.map +1 -1
  100. package/dist/utils/error-handling-utils.js +4 -3
  101. package/dist/utils/error-handling-utils.js.map +1 -1
  102. package/dist/utils/log-helpers.d.ts +6 -0
  103. package/dist/utils/log-helpers.js +90 -0
  104. package/dist/utils/log-helpers.js.map +1 -0
  105. package/dist/utils/logger.d.ts +8 -0
  106. package/dist/utils/logger.js +55 -2
  107. package/dist/utils/logger.js.map +1 -1
  108. package/dist/utils/snapshot-writer.js +2 -6
  109. package/dist/utils/snapshot-writer.js.map +1 -1
  110. package/node_modules/@jsonstudio/llms/dist/conversion/codecs/gemini-openai-codec.js +15 -1
  111. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/auto-thinking.d.ts +6 -0
  112. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/auto-thinking.js +25 -0
  113. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/field-mapping.d.ts +14 -0
  114. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/field-mapping.js +155 -0
  115. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-tool-extraction.d.ts +2 -0
  116. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-tool-extraction.js +264 -0
  117. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/qwen-transform.d.ts +3 -0
  118. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/qwen-transform.js +209 -0
  119. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/request-rules.d.ts +24 -0
  120. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/request-rules.js +63 -0
  121. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-blacklist.d.ts +14 -0
  122. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-blacklist.js +85 -0
  123. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-normalize.d.ts +5 -0
  124. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-normalize.js +121 -0
  125. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-validate.d.ts +5 -0
  126. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-validate.js +76 -0
  127. package/{dist/providers/compat/utils/snapshot-writer.d.ts → node_modules/@jsonstudio/llms/dist/conversion/compat/actions/snapshot.d.ts} +2 -2
  128. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/snapshot.js +21 -0
  129. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/tool-schema.d.ts +6 -0
  130. package/{dist/providers/compat/glm/utils/tool-schema-helpers.js → node_modules/@jsonstudio/llms/dist/conversion/compat/actions/tool-schema.js} +6 -1
  131. package/{dist/providers/compat/filters → node_modules/@jsonstudio/llms/dist/conversion/compat/actions}/universal-shape-filter.d.ts +17 -22
  132. package/{dist/providers/compat/filters → node_modules/@jsonstudio/llms/dist/conversion/compat/actions}/universal-shape-filter.js +35 -99
  133. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-glm.json +187 -13
  134. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-iflow.json +177 -9
  135. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-lmstudio.json +10 -2
  136. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-qwen.json +14 -10
  137. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.d.ts +7 -2
  138. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.js +5 -665
  139. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.d.ts +9 -0
  140. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +845 -0
  141. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-types.d.ts +47 -0
  142. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.d.ts +2 -0
  143. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.js +35 -1
  144. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +2 -2
  145. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/target-utils.js +3 -0
  146. package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/response-runtime.js +19 -2
  147. package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-host-policy.d.ts +6 -0
  148. package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-host-policy.js +14 -0
  149. package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.js +51 -2
  150. package/node_modules/@jsonstudio/llms/dist/conversion/shared/anthropic-message-utils.js +6 -0
  151. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-reasoning-registry.d.ts +4 -0
  152. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-reasoning-registry.js +62 -1
  153. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-response-utils.js +23 -1
  154. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-canonicalizer.d.ts +2 -0
  155. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-filter-pipeline.js +11 -0
  156. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/bootstrap.js +251 -12
  157. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/classifier.js +11 -4
  158. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/context-advisor.d.ts +21 -0
  159. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/context-advisor.js +76 -0
  160. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.d.ts +11 -0
  161. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.js +187 -28
  162. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/features.js +22 -457
  163. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/health-manager.js +2 -7
  164. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/message-utils.d.ts +7 -0
  165. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/message-utils.js +66 -0
  166. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/provider-registry.js +6 -2
  167. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-estimator.d.ts +2 -0
  168. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-estimator.js +16 -0
  169. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-file-scanner.d.ts +15 -0
  170. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-file-scanner.js +56 -0
  171. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/tool-signals.d.ts +13 -0
  172. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/tool-signals.js +403 -0
  173. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.d.ts +21 -1
  174. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.js +1 -0
  175. package/node_modules/@jsonstudio/llms/package.json +2 -2
  176. package/package.json +13 -11
  177. package/scripts/README.md +26 -12
  178. package/scripts/auth-antigravity-token.mjs +64 -0
  179. package/scripts/auth-gemini-cli-token.mjs +96 -0
  180. package/scripts/auth-iflow-manual.mjs +81 -0
  181. package/scripts/auth-iflow-token-direct.mjs +87 -0
  182. package/scripts/auth-iflow-token.mjs +77 -0
  183. package/scripts/copy-compat-assets.mjs +3 -15
  184. package/scripts/install-verify.mjs +1 -0
  185. package/scripts/pack-mode.mjs +30 -1
  186. package/scripts/publish-rcc.mjs +31 -0
  187. package/scripts/replay-codex-sample.mjs +13 -8
  188. package/scripts/tests/chat-pipeline-blackbox.mjs +1 -1
  189. package/scripts/tools/capture-provider-goldens.mjs +8 -7
  190. package/scripts/verify-client-headers.mjs +224 -0
  191. package/dist/providers/compat/base-compatibility.d.ts +0 -27
  192. package/dist/providers/compat/base-compatibility.js +0 -143
  193. package/dist/providers/compat/base-compatibility.js.map +0 -1
  194. package/dist/providers/compat/compat-directory-loader.d.ts +0 -4
  195. package/dist/providers/compat/compat-directory-loader.js +0 -85
  196. package/dist/providers/compat/compat-directory-loader.js.map +0 -1
  197. package/dist/providers/compat/compatibility-adapter.d.ts +0 -18
  198. package/dist/providers/compat/compatibility-adapter.js +0 -104
  199. package/dist/providers/compat/compatibility-adapter.js.map +0 -1
  200. package/dist/providers/compat/compatibility-factory.d.ts +0 -57
  201. package/dist/providers/compat/compatibility-factory.js +0 -155
  202. package/dist/providers/compat/compatibility-factory.js.map +0 -1
  203. package/dist/providers/compat/compatibility-interface.d.ts +0 -35
  204. package/dist/providers/compat/compatibility-interface.js +0 -2
  205. package/dist/providers/compat/compatibility-interface.js.map +0 -1
  206. package/dist/providers/compat/compatibility-manager.d.ts +0 -85
  207. package/dist/providers/compat/compatibility-manager.js +0 -368
  208. package/dist/providers/compat/compatibility-manager.js.map +0 -1
  209. package/dist/providers/compat/config/config-compatibility.d.ts +0 -28
  210. package/dist/providers/compat/config/config-compatibility.js +0 -95
  211. package/dist/providers/compat/config/config-compatibility.js.map +0 -1
  212. package/dist/providers/compat/field-mapping.d.ts +0 -102
  213. package/dist/providers/compat/field-mapping.js +0 -447
  214. package/dist/providers/compat/field-mapping.js.map +0 -1
  215. package/dist/providers/compat/filters/blacklist-sanitizer.d.ts +0 -45
  216. package/dist/providers/compat/filters/blacklist-sanitizer.js +0 -133
  217. package/dist/providers/compat/filters/blacklist-sanitizer.js.map +0 -1
  218. package/dist/providers/compat/filters/response-blacklist-sanitizer.d.ts +0 -28
  219. package/dist/providers/compat/filters/response-blacklist-sanitizer.js +0 -138
  220. package/dist/providers/compat/filters/response-blacklist-sanitizer.js.map +0 -1
  221. package/dist/providers/compat/filters/universal-shape-filter.js.map +0 -1
  222. package/dist/providers/compat/glm/config/blacklist-rules.json +0 -22
  223. package/dist/providers/compat/glm/config/field-mappings.json +0 -92
  224. package/dist/providers/compat/glm/config/response-blacklist.json +0 -7
  225. package/dist/providers/compat/glm/config/shape-filters.json +0 -37
  226. package/dist/providers/compat/glm/field-mapping/field-mapping-processor.d.ts +0 -28
  227. package/dist/providers/compat/glm/field-mapping/field-mapping-processor.js +0 -306
  228. package/dist/providers/compat/glm/field-mapping/field-mapping-processor.js.map +0 -1
  229. package/dist/providers/compat/glm/functions/glm-processor.d.ts +0 -50
  230. package/dist/providers/compat/glm/functions/glm-processor.js +0 -134
  231. package/dist/providers/compat/glm/functions/glm-processor.js.map +0 -1
  232. package/dist/providers/compat/glm/glm-compatibility.d.ts +0 -34
  233. package/dist/providers/compat/glm/glm-compatibility.js +0 -117
  234. package/dist/providers/compat/glm/glm-compatibility.js.map +0 -1
  235. package/dist/providers/compat/glm/hooks/base-hook.d.ts +0 -21
  236. package/dist/providers/compat/glm/hooks/base-hook.js +0 -53
  237. package/dist/providers/compat/glm/hooks/base-hook.js.map +0 -1
  238. package/dist/providers/compat/glm/hooks/glm-request-validation-hook.d.ts +0 -24
  239. package/dist/providers/compat/glm/hooks/glm-request-validation-hook.js +0 -268
  240. package/dist/providers/compat/glm/hooks/glm-request-validation-hook.js.map +0 -1
  241. package/dist/providers/compat/glm/hooks/glm-response-normalization-hook.d.ts +0 -21
  242. package/dist/providers/compat/glm/hooks/glm-response-normalization-hook.js +0 -171
  243. package/dist/providers/compat/glm/hooks/glm-response-normalization-hook.js.map +0 -1
  244. package/dist/providers/compat/glm/hooks/glm-response-validation-hook.d.ts +0 -25
  245. package/dist/providers/compat/glm/hooks/glm-response-validation-hook.js +0 -236
  246. package/dist/providers/compat/glm/hooks/glm-response-validation-hook.js.map +0 -1
  247. package/dist/providers/compat/glm/hooks/glm-tool-cleaning-hook.d.ts +0 -26
  248. package/dist/providers/compat/glm/hooks/glm-tool-cleaning-hook.js +0 -186
  249. package/dist/providers/compat/glm/hooks/glm-tool-cleaning-hook.js.map +0 -1
  250. package/dist/providers/compat/glm/index.d.ts +0 -24
  251. package/dist/providers/compat/glm/index.js +0 -29
  252. package/dist/providers/compat/glm/index.js.map +0 -1
  253. package/dist/providers/compat/glm/utils/tool-schema-helpers.d.ts +0 -3
  254. package/dist/providers/compat/glm/utils/tool-schema-helpers.js.map +0 -1
  255. package/dist/providers/compat/iflow/config/field-mappings.json +0 -92
  256. package/dist/providers/compat/iflow/config/shape-filters.json +0 -37
  257. package/dist/providers/compat/iflow/field-mapping/iflow-field-mapping-processor.d.ts +0 -34
  258. package/dist/providers/compat/iflow/field-mapping/iflow-field-mapping-processor.js +0 -386
  259. package/dist/providers/compat/iflow/field-mapping/iflow-field-mapping-processor.js.map +0 -1
  260. package/dist/providers/compat/iflow/functions/iflow-processor.d.ts +0 -53
  261. package/dist/providers/compat/iflow/functions/iflow-processor.js +0 -215
  262. package/dist/providers/compat/iflow/functions/iflow-processor.js.map +0 -1
  263. package/dist/providers/compat/iflow/hooks/base-hook.d.ts +0 -23
  264. package/dist/providers/compat/iflow/hooks/base-hook.js +0 -59
  265. package/dist/providers/compat/iflow/hooks/base-hook.js.map +0 -1
  266. package/dist/providers/compat/iflow/hooks/iflow-request-validation-hook.d.ts +0 -23
  267. package/dist/providers/compat/iflow/hooks/iflow-request-validation-hook.js +0 -279
  268. package/dist/providers/compat/iflow/hooks/iflow-request-validation-hook.js.map +0 -1
  269. package/dist/providers/compat/iflow/hooks/iflow-response-normalization-hook.d.ts +0 -20
  270. package/dist/providers/compat/iflow/hooks/iflow-response-normalization-hook.js +0 -180
  271. package/dist/providers/compat/iflow/hooks/iflow-response-normalization-hook.js.map +0 -1
  272. package/dist/providers/compat/iflow/hooks/iflow-response-validation-hook.d.ts +0 -23
  273. package/dist/providers/compat/iflow/hooks/iflow-response-validation-hook.js +0 -232
  274. package/dist/providers/compat/iflow/hooks/iflow-response-validation-hook.js.map +0 -1
  275. package/dist/providers/compat/iflow/hooks/iflow-tool-cleaning-hook.d.ts +0 -25
  276. package/dist/providers/compat/iflow/hooks/iflow-tool-cleaning-hook.js +0 -216
  277. package/dist/providers/compat/iflow/hooks/iflow-tool-cleaning-hook.js.map +0 -1
  278. package/dist/providers/compat/iflow/iflow-compatibility.d.ts +0 -24
  279. package/dist/providers/compat/iflow/iflow-compatibility.js +0 -94
  280. package/dist/providers/compat/iflow/iflow-compatibility.js.map +0 -1
  281. package/dist/providers/compat/index.d.ts +0 -59
  282. package/dist/providers/compat/index.js +0 -83
  283. package/dist/providers/compat/index.js.map +0 -1
  284. package/dist/providers/compat/lmstudio-compatibility.d.ts +0 -44
  285. package/dist/providers/compat/lmstudio-compatibility.js +0 -193
  286. package/dist/providers/compat/lmstudio-compatibility.js.map +0 -1
  287. package/dist/providers/compat/passthrough-compatibility.d.ts +0 -29
  288. package/dist/providers/compat/passthrough-compatibility.js +0 -83
  289. package/dist/providers/compat/passthrough-compatibility.js.map +0 -1
  290. package/dist/providers/compat/profiles/chat/glm/index.d.ts +0 -6
  291. package/dist/providers/compat/profiles/chat/glm/index.js +0 -6
  292. package/dist/providers/compat/profiles/chat/glm/index.js.map +0 -1
  293. package/dist/providers/compat/profiles/chat/iflow/index.d.ts +0 -6
  294. package/dist/providers/compat/profiles/chat/iflow/index.js +0 -6
  295. package/dist/providers/compat/profiles/chat/iflow/index.js.map +0 -1
  296. package/dist/providers/compat/profiles/chat/lmstudio/index.d.ts +0 -6
  297. package/dist/providers/compat/profiles/chat/lmstudio/index.js +0 -6
  298. package/dist/providers/compat/profiles/chat/lmstudio/index.js.map +0 -1
  299. package/dist/providers/compat/profiles/chat/qwen/index.d.ts +0 -6
  300. package/dist/providers/compat/profiles/chat/qwen/index.js +0 -6
  301. package/dist/providers/compat/profiles/chat/qwen/index.js.map +0 -1
  302. package/dist/providers/compat/profiles/compat/passthrough/index.d.ts +0 -6
  303. package/dist/providers/compat/profiles/compat/passthrough/index.js +0 -6
  304. package/dist/providers/compat/profiles/compat/passthrough/index.js.map +0 -1
  305. package/dist/providers/compat/profiles/responses/c4m/index.d.ts +0 -6
  306. package/dist/providers/compat/profiles/responses/c4m/index.js +0 -6
  307. package/dist/providers/compat/profiles/responses/c4m/index.js.map +0 -1
  308. package/dist/providers/compat/profiles/responses/default/index.d.ts +0 -6
  309. package/dist/providers/compat/profiles/responses/default/index.js +0 -6
  310. package/dist/providers/compat/profiles/responses/default/index.js.map +0 -1
  311. package/dist/providers/compat/profiles/responses/fai/index.d.ts +0 -6
  312. package/dist/providers/compat/profiles/responses/fai/index.js +0 -6
  313. package/dist/providers/compat/profiles/responses/fai/index.js.map +0 -1
  314. package/dist/providers/compat/profiles/responses/fc/index.d.ts +0 -6
  315. package/dist/providers/compat/profiles/responses/fc/index.js +0 -6
  316. package/dist/providers/compat/profiles/responses/fc/index.js.map +0 -1
  317. package/dist/providers/compat/qwen/index.d.ts +0 -4
  318. package/dist/providers/compat/qwen/index.js +0 -6
  319. package/dist/providers/compat/qwen/index.js.map +0 -1
  320. package/dist/providers/compat/qwen-compatibility.d.ts +0 -52
  321. package/dist/providers/compat/qwen-compatibility.js +0 -330
  322. package/dist/providers/compat/qwen-compatibility.js.map +0 -1
  323. package/dist/providers/compat/register-compat-module.d.ts +0 -8
  324. package/dist/providers/compat/register-compat-module.js +0 -53
  325. package/dist/providers/compat/register-compat-module.js.map +0 -1
  326. package/dist/providers/compat/responses/c4m-responses-compatibility.d.ts +0 -27
  327. package/dist/providers/compat/responses/c4m-responses-compatibility.js +0 -197
  328. package/dist/providers/compat/responses/c4m-responses-compatibility.js.map +0 -1
  329. package/dist/providers/compat/standard-compatibility-utils.d.ts +0 -1
  330. package/dist/providers/compat/standard-compatibility-utils.js +0 -77
  331. package/dist/providers/compat/standard-compatibility-utils.js.map +0 -1
  332. package/dist/providers/compat/standard-compatibility.d.ts +0 -31
  333. package/dist/providers/compat/standard-compatibility.js +0 -118
  334. package/dist/providers/compat/standard-compatibility.js.map +0 -1
  335. package/dist/providers/compat/utils/snapshot-writer.js +0 -62
  336. package/dist/providers/compat/utils/snapshot-writer.js.map +0 -1
  337. package/scripts/check-glm-compat.mjs +0 -47
@@ -8,6 +8,8 @@
8
8
  *
9
9
  * 各协议具体行为(OpenAI Chat、Responses、Anthropic、Gemini 等)通过子类覆写钩子实现。
10
10
  */
11
+ import { createHash } from 'node:crypto';
12
+ import fs from 'node:fs/promises';
11
13
  import { BaseProvider } from './base-provider.js';
12
14
  import { HttpClient } from '../utils/http-client.js';
13
15
  import { DynamicProfileLoader, ServiceProfileValidator } from '../config/service-profiles.js';
@@ -16,83 +18,35 @@ import { OAuthAuthProvider } from '../../auth/oauth-auth.js';
16
18
  import { logOAuthDebug } from '../../auth/oauth-logger.js';
17
19
  import { TokenFileAuthProvider } from '../../auth/tokenfile-auth.js';
18
20
  import { ensureValidOAuthToken, handleUpstreamInvalidOAuthToken } from '../../auth/oauth-lifecycle.js';
19
- import { createHookSystemIntegration, HookSystemIntegration } from '../hooks/hooks-integration.js';
20
- import { attachProviderSseSnapshotStream, shouldCaptureProviderStreamSnapshots, writeProviderSnapshot } from '../utils/snapshot-writer.js';
21
- import { attachProviderRuntimeMetadata } from './provider-runtime-metadata.js';
21
+ import { fetchAntigravityProjectId } from '../../auth/antigravity-userinfo-helper.js';
22
+ import { attachProviderSseSnapshotStream, writeProviderSnapshot } from '../utils/snapshot-writer.js';
23
+ import { attachProviderRuntimeMetadata, extractProviderRuntimeMetadata } from './provider-runtime-metadata.js';
22
24
  import { OpenAIChatProtocolClient } from '../../../client/openai/chat-protocol-client.js';
23
- const ENABLE_PROVIDER_HOOKS = process.env.ROUTECODEX_ENABLE_PROVIDER_HOOKS === '1';
25
+ import { HttpRequestExecutor } from './http-request-executor.js';
26
+ import { extractStatusCodeFromError } from './provider-error-classifier.js';
24
27
  const isRecord = (value) => typeof value === 'object' && value !== null;
25
- function createNoopHookSystemIntegration() {
26
- const passthrough = async (_stage, _target, data) => ({
27
- data,
28
- metrics: {
29
- executionTime: 0,
30
- hookCount: 0,
31
- successCount: 0,
32
- readCount: 0,
33
- writeCount: 0,
34
- transformCount: 0
35
- }
36
- });
37
- return {
38
- getBidirectionalHookManager: () => ({
39
- registerHook: () => { },
40
- unregisterHook: () => { },
41
- executeHookChain: passthrough,
42
- setDebugConfig: () => { }
43
- }),
44
- setDebugConfig: () => { },
45
- initialize: async () => { },
46
- getStats: () => ({ enabled: false }),
47
- healthCheck: async () => ({ healthy: true }),
48
- start: async () => { },
49
- stop: async () => { },
50
- shutdown: async () => { }
51
- };
52
- }
53
- const readStatusCodeFromResponse = (error) => {
54
- const response = error?.response;
55
- const directStatus = typeof response?.status === 'number' ? response.status : undefined;
56
- const directStatusCode = typeof response?.statusCode === 'number'
57
- ? response.statusCode
58
- : undefined;
59
- const nestedStatus = response &&
60
- typeof response === 'object' &&
61
- typeof response?.data?.status === 'number'
62
- ? response.data.status
63
- : undefined;
64
- const nestedErrorStatus = response &&
65
- typeof response === 'object' &&
66
- typeof response?.data?.error?.status === 'number'
67
- ? response.data.error.status
68
- : undefined;
69
- return [directStatus, directStatusCode, nestedStatus, nestedErrorStatus].find((candidate) => typeof candidate === 'number' && Number.isFinite(candidate));
70
- };
71
- const DEFAULT_USER_AGENT = 'RouteCodex/2.0';
28
+ const DEFAULT_USER_AGENT = 'codex_cli_rs/0.73.0 (Mac OS 15.6.1; arm64) iTerm.app/3.6.5';
72
29
  export class HttpTransportProvider extends BaseProvider {
73
30
  type;
74
31
  authProvider = null;
75
32
  httpClient;
76
33
  serviceProfile;
77
- hookSystemIntegration;
78
34
  protocolClient;
35
+ requestExecutor;
79
36
  injectedConfig = null;
80
- hooksEnabled;
81
37
  constructor(config, dependencies, moduleType, protocolClient) {
82
38
  super(config, dependencies);
83
39
  this.type = moduleType;
84
40
  this.protocolClient = protocolClient ?? new OpenAIChatProtocolClient();
85
- this.hooksEnabled = ENABLE_PROVIDER_HOOKS;
86
41
  // 获取服务配置档案
87
42
  this.serviceProfile = this.getServiceProfile();
88
43
  // 验证配置
89
44
  this.validateConfig();
90
45
  // 创建HTTP客户端
91
46
  this.createHttpClient();
47
+ this.requestExecutor = new HttpRequestExecutor(this.httpClient, this.createRequestExecutorDeps());
92
48
  // 创建认证提供者
93
49
  this.authProvider = this.createAuthProvider();
94
- // 初始化Hook系统集成
95
- this.hookSystemIntegration = this.initializeHookSystem();
96
50
  }
97
51
  /**
98
52
  * 确保认证提供者完成初始化(避免 ApiKeyAuthProvider 未初始化导致的报错)
@@ -104,9 +58,10 @@ export class HttpTransportProvider extends BaseProvider {
104
58
  const providerConfig = this.config.config;
105
59
  const extensions = this.getConfigExtensions();
106
60
  const auth = providerConfig.auth;
61
+ const usesTokenFile = this.authProvider instanceof TokenFileAuthProvider;
107
62
  if (this.normalizeAuthMode(auth.type) === 'oauth') {
108
63
  const oauthAuth = auth;
109
- const oauthProviderId = this.ensureOAuthProviderId(oauthAuth, extensions);
64
+ const oauthProviderId = this.oauthProviderId || this.ensureOAuthProviderId(oauthAuth, extensions);
110
65
  const forceReauthorize = false;
111
66
  const tokenFileHint = oauthAuth.tokenFile ?? '(default)';
112
67
  logOAuthDebug(`[OAuth] [init] provider=${oauthProviderId} type=${auth.type} tokenFile=${tokenFileHint} forceReauth=${forceReauthorize}`);
@@ -121,9 +76,13 @@ export class HttpTransportProvider extends BaseProvider {
121
76
  openBrowser: true,
122
77
  forceReauthorize
123
78
  });
79
+ if (this.oauthProviderId === 'antigravity') {
80
+ await this.ensureAntigravityProjectMetadata(oauthAuth);
81
+ }
124
82
  logOAuthDebug('[OAuth] [init] ensureValid OK');
125
83
  try {
126
84
  if (this.authProvider instanceof TokenFileAuthProvider) {
85
+ // 令牌文件可能在 ensureValidOAuthToken 中被创建/更新,重新加载一次
127
86
  await this.authProvider.initialize();
128
87
  }
129
88
  else {
@@ -142,17 +101,11 @@ export class HttpTransportProvider extends BaseProvider {
142
101
  const msg = err?.message ? String(err.message) : String(error);
143
102
  console.error(`[OAuth] [init] ensureValid ERROR: ${msg}`);
144
103
  this.dependencies.logger?.logModule?.(this.id, 'oauth-init-error', {
145
- providerType: this.providerType,
104
+ providerType: oauthProviderId,
146
105
  error: msg
147
106
  });
148
107
  throw error;
149
108
  }
150
- try {
151
- this.authProvider.getOAuthClient?.()?.loadToken?.();
152
- }
153
- catch {
154
- // ignore
155
- }
156
109
  }
157
110
  else {
158
111
  try {
@@ -163,14 +116,6 @@ export class HttpTransportProvider extends BaseProvider {
163
116
  }
164
117
  }
165
118
  }
166
- if (this.hooksEnabled) {
167
- await this.hookSystemIntegration.initialize();
168
- this.configureHookDebugging();
169
- this.dependencies.logger?.logModule(this.id, 'provider-hook-system-initialized', {
170
- providerType: this.providerType,
171
- integrationEnabled: true
172
- });
173
- }
174
119
  }
175
120
  catch (error) {
176
121
  // 暴露问题,快速失败,便于定位凭证问题
@@ -200,62 +145,6 @@ export class HttpTransportProvider extends BaseProvider {
200
145
  getConfig() {
201
146
  return this.injectedConfig ?? this.config.config ?? null;
202
147
  }
203
- /**
204
- * 初始化Hook系统集成
205
- */
206
- initializeHookSystem() {
207
- if (!this.hooksEnabled) {
208
- return createNoopHookSystemIntegration();
209
- }
210
- return createHookSystemIntegration(this.dependencies, this.id, {
211
- enabled: true,
212
- debugMode: true,
213
- snapshotEnabled: true,
214
- migrationMode: true
215
- });
216
- }
217
- /**
218
- * 配置Hook调试(保持向后兼容)
219
- */
220
- configureHookDebugging() {
221
- if (!this.hooksEnabled) {
222
- return;
223
- }
224
- try {
225
- // 设置调试配置(使用统一Hook系统的阶段字符串)
226
- const debugConfig = {
227
- enabled: true,
228
- level: 'verbose',
229
- maxDataSize: 1024 * 64, // 64KB 单次输出上限,避免过大控制台噪声
230
- stages: [
231
- 'request_preprocessing',
232
- 'request_validation',
233
- 'authentication',
234
- 'http_request',
235
- 'http_response',
236
- 'response_validation',
237
- 'response_postprocessing',
238
- 'error_handling'
239
- ],
240
- outputFormat: 'structured',
241
- outputTargets: ['console'],
242
- performanceThresholds: {
243
- maxHookExecutionTime: 500, // 单个Hook 500ms告警
244
- maxTotalExecutionTime: 5000, // 阶段总时长 5s 告警
245
- maxDataSize: 1024 * 256 // 256KB 数据告警
246
- }
247
- };
248
- this.hookSystemIntegration.setDebugConfig(debugConfig);
249
- this.dependencies.logger?.logModule(this.id, 'provider-debug-hooks-configured', {
250
- providerType: this.providerType
251
- });
252
- }
253
- catch (error) {
254
- this.dependencies.logger?.logModule(this.id, 'provider-debug-hooks-error', {
255
- error: error instanceof Error ? error.message : String(error)
256
- });
257
- }
258
- }
259
148
  getServiceProfile() {
260
149
  const cfg = this.config.config;
261
150
  const profileKey = this.resolveProfileKey(cfg);
@@ -349,15 +238,16 @@ export class HttpTransportProvider extends BaseProvider {
349
238
  const auth = this.config.config.auth;
350
239
  const extensions = this.getConfigExtensions();
351
240
  const authMode = this.normalizeAuthMode(auth.type);
352
- const providerIdForAuth = authMode === 'oauth'
241
+ this.authMode = authMode;
242
+ const resolvedOAuthProviderId = authMode === 'oauth'
353
243
  ? this.ensureOAuthProviderId(auth, extensions)
354
- : this.providerType;
355
- // 验证认证配置(按 providerIdForAuth 选择服务档案)
356
- // 对于 gemini-cli 这类变体,provider 行为归入 gemini 协议族
357
- const profileKeyForValidation = providerIdForAuth === 'gemini-cli' ? 'gemini' : providerIdForAuth;
358
- const validation = ServiceProfileValidator.validateServiceProfile(profileKeyForValidation, authMode);
244
+ : undefined;
245
+ const serviceProfileKey = this.type === 'gemini-cli-http-provider'
246
+ ? 'gemini-cli'
247
+ : (resolvedOAuthProviderId ?? this.providerType);
248
+ const validation = ServiceProfileValidator.validateServiceProfile(serviceProfileKey, authMode);
359
249
  if (!validation.isValid) {
360
- throw new Error(`Invalid auth configuration for ${providerIdForAuth}: ${validation.errors.join(', ')}`);
250
+ throw new Error(`Invalid auth configuration for ${serviceProfileKey}: ${validation.errors.join(', ')}`);
361
251
  }
362
252
  // 根据认证类型创建对应的认证提供者
363
253
  if (authMode === 'apikey') {
@@ -365,16 +255,20 @@ export class HttpTransportProvider extends BaseProvider {
365
255
  }
366
256
  else if (authMode === 'oauth') {
367
257
  const oauthAuth = auth;
258
+ const oauthProviderId = resolvedOAuthProviderId ?? serviceProfileKey;
259
+ this.oauthProviderId = oauthProviderId;
368
260
  // For providers like Qwen/iflow/Gemini CLI where public OAuth client may not be available,
369
261
  // allow reading tokens produced by external login tools (CLIProxyAPI) via token file.
370
- const useTokenFile = (providerIdForAuth === 'qwen' || providerIdForAuth === 'iflow' || providerIdForAuth === 'gemini-cli') &&
262
+ const useTokenFile = (oauthProviderId === 'qwen' ||
263
+ oauthProviderId === 'iflow' ||
264
+ this.type === 'gemini-cli-http-provider') &&
371
265
  !oauthAuth.clientId &&
372
266
  !oauthAuth.tokenUrl &&
373
267
  !oauthAuth.deviceCodeUrl;
374
268
  if (useTokenFile) {
375
269
  return new TokenFileAuthProvider(oauthAuth);
376
270
  }
377
- return new OAuthAuthProvider(oauthAuth, providerIdForAuth);
271
+ return new OAuthAuthProvider(oauthAuth, oauthProviderId);
378
272
  }
379
273
  else {
380
274
  throw new Error(`Unsupported auth type: ${auth.type}`);
@@ -405,9 +299,43 @@ export class HttpTransportProvider extends BaseProvider {
405
299
  }
406
300
  });
407
301
  }
302
+ createRequestExecutorDeps() {
303
+ return {
304
+ wantsUpstreamSse: this.wantsUpstreamSse.bind(this),
305
+ getEffectiveEndpoint: () => this.getEffectiveEndpoint(),
306
+ resolveRequestEndpoint: this.resolveRequestEndpoint.bind(this),
307
+ buildRequestHeaders: this.buildRequestHeaders.bind(this),
308
+ finalizeRequestHeaders: this.finalizeRequestHeaders.bind(this),
309
+ applyStreamModeHeaders: this.applyStreamModeHeaders.bind(this),
310
+ getEffectiveBaseUrl: () => this.getEffectiveBaseUrl(),
311
+ buildHttpRequestBody: this.buildHttpRequestBody.bind(this),
312
+ prepareSseRequestBody: this.prepareSseRequestBody.bind(this),
313
+ getEntryEndpointFromPayload: this.getEntryEndpointFromPayload.bind(this),
314
+ getClientRequestIdFromContext: this.getClientRequestIdFromContext.bind(this),
315
+ wrapUpstreamSseResponse: this.wrapUpstreamSseResponse.bind(this),
316
+ getHttpRetryLimit: () => this.getHttpRetryLimit(),
317
+ shouldRetryHttpError: this.shouldRetryHttpError.bind(this),
318
+ delayBeforeHttpRetry: this.delayBeforeHttpRetry.bind(this),
319
+ tryRecoverOAuthAndReplay: this.tryRecoverOAuthAndReplay.bind(this),
320
+ normalizeHttpError: this.normalizeHttpError.bind(this)
321
+ };
322
+ }
408
323
  async preprocessRequest(request) {
409
324
  const context = this.createProviderContext();
410
325
  const runtimeMetadata = context.runtimeMetadata;
326
+ const headersFromRequest = this.normalizeClientHeaders(request?.metadata?.clientHeaders);
327
+ const headersFromRuntime = this.normalizeClientHeaders(runtimeMetadata?.metadata && typeof runtimeMetadata.metadata === 'object'
328
+ ? runtimeMetadata.metadata.clientHeaders
329
+ : undefined);
330
+ const effectiveClientHeaders = headersFromRequest ?? headersFromRuntime;
331
+ if (effectiveClientHeaders) {
332
+ if (runtimeMetadata) {
333
+ if (!runtimeMetadata.metadata || typeof runtimeMetadata.metadata !== 'object') {
334
+ runtimeMetadata.metadata = {};
335
+ }
336
+ runtimeMetadata.metadata.clientHeaders = effectiveClientHeaders;
337
+ }
338
+ }
411
339
  const ensureRuntimeMetadata = (payload) => {
412
340
  if (!runtimeMetadata || !payload || typeof payload !== 'object') {
413
341
  return;
@@ -433,50 +361,17 @@ export class HttpTransportProvider extends BaseProvider {
433
361
  ...processedMetadata,
434
362
  ...(entryEndpoint ? { entryEndpoint } : {}),
435
363
  ...(typeof streamFlag === 'boolean' ? { stream: !!streamFlag } : {}),
364
+ ...(effectiveClientHeaders ? { clientHeaders: effectiveClientHeaders } : {}),
436
365
  __origModel: inboundModel
437
366
  };
438
367
  }
439
368
  catch { /* ignore */ }
440
- // 流式开关:基础 Provider 统一移除入口层的 stream 标记,
441
- // 具体协议(如 Responses/Anthropic)的真实流控由各自独立 Provider 处理
442
- try {
443
- // 统一:所有入口均移除 stream=true(Provider 始终走非流式),SSE 由上层合成
444
- const requestBody = processedRequest;
445
- if (requestBody.stream === true) {
446
- delete requestBody.stream;
447
- }
448
- }
449
- catch { /* ignore */ }
450
- // 获取Hook管理器(新的统一系统)
451
- const hookManager = this.getHookManager();
452
- // 🔍 Hook 1: 请求预处理阶段
453
- const preprocessResult = await hookManager.executeHookChain('request_preprocessing', 'request', processedRequest, context);
454
- processedRequest = preprocessResult.data;
455
- ensureRuntimeMetadata(processedRequest);
456
- // 🔍 Hook 2: 请求验证阶段
457
- const validationResult = await hookManager.executeHookChain('request_validation', 'request', processedRequest, context);
458
- processedRequest = validationResult.data;
459
- ensureRuntimeMetadata(processedRequest);
460
- // Provider 层不再修改工具 schema;统一入口在 llmswitch-core/兼容层
461
- // Provider 层不做协议兼容改写:compatibility 由 llmswitch-core Hub Pipeline 统一处理。
462
369
  return processedRequest;
463
370
  }
464
371
  async postprocessResponse(response, context) {
465
372
  const runtime = this.getRuntimeProfile();
466
373
  const processingTime = Date.now() - context.startTime;
467
374
  let processedResponse = response;
468
- // 获取Hook管理器(新的统一系统)
469
- const hookManager = this.getHookManager();
470
- // 🔍 Hook 3: HTTP响应阶段
471
- const httpResponseResult = await hookManager.executeHookChain('http_response', 'response', processedResponse, context);
472
- processedResponse = httpResponseResult.data;
473
- // 🔍 Hook 4: 响应验证阶段
474
- const validationResult = await hookManager.executeHookChain('response_validation', 'response', processedResponse, context);
475
- processedResponse = validationResult.data;
476
- // 🔍 Hook 5: 响应后处理阶段
477
- const postprocessResult = await hookManager.executeHookChain('response_postprocessing', 'response', processedResponse, context);
478
- processedResponse = postprocessResult.data;
479
- // Provider 层不做协议兼容改写:compatibility 由 llmswitch-core Hub Pipeline 统一处理。
480
375
  const originalRecord = this.asResponseRecord(response);
481
376
  const processedRecord = this.asResponseRecord(processedResponse);
482
377
  const sseStream = processedRecord.__sse_responses ||
@@ -494,221 +389,13 @@ export class HttpTransportProvider extends BaseProvider {
494
389
  providerType: this.providerType,
495
390
  // 对外暴露的 model 统一为入站模型
496
391
  model: context.model ?? this.extractModel(processedRecord) ?? this.extractModel(originalRecord),
497
- usage: this.extractUsage(processedRecord) ?? this.extractUsage(originalRecord),
498
- hookMetrics: {
499
- httpResponse: httpResponseResult.metrics,
500
- validation: validationResult.metrics,
501
- postprocess: postprocessResult.metrics
502
- }
392
+ usage: this.extractUsage(processedRecord) ?? this.extractUsage(originalRecord)
503
393
  }
504
394
  };
505
395
  }
506
396
  async sendRequestInternal(request) {
507
397
  const context = this.createProviderContext();
508
- // 获取Hook管理器(新的统一系统)
509
- const hookManager = this.getHookManager();
510
- // 🔍 Hook 8: HTTP请求阶段
511
- const httpRequestResult = await hookManager.executeHookChain('http_request', 'request', request, context);
512
- const processedRequest = httpRequestResult.data;
513
- const wantsSse = this.wantsUpstreamSse(processedRequest, context);
514
- // 仅传入 endpoint,让 HttpClient 按 baseUrl 进行拼接;避免 full URL 再次拼接导致 /https:/ 重复
515
- const defaultEndpoint = this.getEffectiveEndpoint();
516
- const endpoint = this.resolveRequestEndpoint(processedRequest, defaultEndpoint);
517
- const headers = await this.buildRequestHeaders();
518
- let finalHeaders = await this.finalizeRequestHeaders(headers, processedRequest);
519
- finalHeaders = this.applyStreamModeHeaders(finalHeaders, wantsSse);
520
- const targetUrl = `${this.getEffectiveBaseUrl().replace(/\/$/, '')}/${endpoint.startsWith('/') ? endpoint.slice(1) : endpoint}`;
521
- // Flatten request body to standard OpenAI Chat JSON
522
- const finalBody = this.buildHttpRequestBody(processedRequest);
523
- if (wantsSse) {
524
- this.prepareSseRequestBody(finalBody, context);
525
- }
526
- const entryEndpoint = this.getEntryEndpointFromPayload(processedRequest);
527
- const clientRequestId = this.getClientRequestIdFromContext(context);
528
- // 快照:provider-request(默认开启,脱敏headers)
529
- try {
530
- await writeProviderSnapshot({
531
- phase: 'provider-request',
532
- requestId: context.requestId,
533
- data: finalBody,
534
- headers: finalHeaders,
535
- url: targetUrl,
536
- entryEndpoint,
537
- clientRequestId
538
- });
539
- }
540
- catch { /* non-blocking */ }
541
- // 发送HTTP请求(根据是否需要 SSE 决定传输模式)
542
- let response;
543
- const captureSse = shouldCaptureProviderStreamSnapshots();
544
- try {
545
- if (wantsSse) {
546
- const upstreamStream = await this.httpClient.postStream(endpoint, finalBody, finalHeaders);
547
- const streamForHost = captureSse
548
- ? attachProviderSseSnapshotStream(upstreamStream, {
549
- requestId: context.requestId,
550
- headers: finalHeaders,
551
- url: targetUrl,
552
- entryEndpoint,
553
- clientRequestId
554
- })
555
- : upstreamStream;
556
- response = await this.wrapUpstreamSseResponse(streamForHost, context);
557
- if (!captureSse) {
558
- try {
559
- await writeProviderSnapshot({
560
- phase: 'provider-response',
561
- requestId: context.requestId,
562
- data: { mode: 'sse' },
563
- headers: finalHeaders,
564
- url: targetUrl,
565
- entryEndpoint,
566
- clientRequestId
567
- });
568
- }
569
- catch { /* non-blocking */ }
570
- }
571
- }
572
- else {
573
- response = await this.httpClient.post(endpoint, finalBody, finalHeaders);
574
- try {
575
- await writeProviderSnapshot({
576
- phase: 'provider-response',
577
- requestId: context.requestId,
578
- data: response,
579
- headers: finalHeaders,
580
- url: targetUrl,
581
- entryEndpoint,
582
- clientRequestId
583
- });
584
- }
585
- catch { /* non-blocking */ }
586
- }
587
- }
588
- catch (error) {
589
- // OAuth token 失效:尝试刷新/重获并重试一次
590
- try {
591
- const providerAuth = this.config.config.auth;
592
- if (this.normalizeAuthMode(providerAuth.type) === 'oauth') {
593
- const shouldRetry = await handleUpstreamInvalidOAuthToken(this.providerType, providerAuth, error);
594
- if (shouldRetry) {
595
- const retryHeaders = await this.buildRequestHeaders();
596
- let finalRetryHeaders = await this.finalizeRequestHeaders(retryHeaders, processedRequest);
597
- finalRetryHeaders = this.applyStreamModeHeaders(finalRetryHeaders, wantsSse);
598
- if (wantsSse) {
599
- const upstreamStream = await this.httpClient.postStream(endpoint, finalBody, finalRetryHeaders);
600
- const streamForHost = captureSse
601
- ? attachProviderSseSnapshotStream(upstreamStream, {
602
- requestId: context.requestId,
603
- headers: finalRetryHeaders,
604
- url: targetUrl,
605
- entryEndpoint,
606
- clientRequestId,
607
- extra: { retry: true }
608
- })
609
- : upstreamStream;
610
- const wrapped = await this.wrapUpstreamSseResponse(streamForHost, context);
611
- if (!captureSse) {
612
- try {
613
- await writeProviderSnapshot({
614
- phase: 'provider-response',
615
- requestId: context.requestId,
616
- data: { mode: 'sse', retry: true },
617
- headers: finalRetryHeaders,
618
- url: targetUrl,
619
- entryEndpoint,
620
- clientRequestId
621
- });
622
- }
623
- catch { /* non-blocking */ }
624
- }
625
- return wrapped;
626
- }
627
- response = await this.httpClient.post(endpoint, finalBody, finalRetryHeaders);
628
- try {
629
- await writeProviderSnapshot({
630
- phase: 'provider-response',
631
- requestId: context.requestId,
632
- data: response,
633
- headers: finalRetryHeaders,
634
- url: targetUrl,
635
- entryEndpoint,
636
- clientRequestId
637
- });
638
- }
639
- catch { /* non-blocking */ }
640
- return response;
641
- }
642
- }
643
- }
644
- catch { /* ignore and fallthrough */ }
645
- // 🔍 Hook 9: 错误处理阶段
646
- const errorResult = await hookManager.executeHookChain('error_handling', 'error', { error, request: processedRequest, url: targetUrl, headers: finalHeaders }, context);
647
- // 如果Hook处理了错误,使用Hook的返回结果
648
- const hookErrorData = errorResult.data;
649
- if (hookErrorData && hookErrorData.error === false) {
650
- return hookErrorData;
651
- }
652
- // 规范化错误:补充结构化字段,移除仅文本填充的旧做法
653
- const normalized = error;
654
- try {
655
- const msg = typeof normalized.message === 'string' ? normalized.message : String(normalized || '');
656
- const m = msg.match(/HTTP\s+(\d{3})/i);
657
- const parsedStatus = m ? parseInt(m[1], 10) : undefined;
658
- const responseStatus = readStatusCodeFromResponse(normalized);
659
- const statusCode = Number.isFinite(normalized.statusCode)
660
- ? Number(normalized.statusCode)
661
- : Number.isFinite(normalized.status)
662
- ? Number(normalized.status)
663
- : responseStatus ?? parsedStatus ?? undefined;
664
- if (statusCode && !Number.isNaN(statusCode)) {
665
- normalized.statusCode = statusCode;
666
- if (!normalized.status) {
667
- normalized.status = statusCode;
668
- }
669
- if (!normalized.code) {
670
- normalized.code = `HTTP_${statusCode}`;
671
- }
672
- }
673
- // 兼容 Manager 的 code 路径(response.data.error.code)
674
- if (!normalized.response) {
675
- normalized.response = {};
676
- }
677
- if (!normalized.response.data) {
678
- normalized.response.data = {};
679
- }
680
- if (!normalized.response.data.error) {
681
- normalized.response.data.error = {};
682
- }
683
- if (normalized.code && !normalized.response.data.error.code) {
684
- normalized.response.data.error.code = normalized.code;
685
- }
686
- }
687
- catch { /* keep original */ }
688
- // 快照:provider-error(结构化写入)
689
- try {
690
- await writeProviderSnapshot({
691
- phase: 'provider-error',
692
- requestId: context.requestId,
693
- data: {
694
- status: normalized?.statusCode ?? normalized?.status ?? null,
695
- code: normalized?.code ?? null,
696
- error: typeof normalized?.message === 'string' ? normalized.message : String(normalized || '')
697
- },
698
- headers: finalHeaders,
699
- url: targetUrl,
700
- entryEndpoint,
701
- clientRequestId
702
- });
703
- }
704
- catch { /* non-blocking */ }
705
- throw normalized;
706
- }
707
- // Provider 不处理工具修复/注入逻辑:统一收敛到 llmswitch-core 与兼容层
708
- // 此处不做任何自动修复/重试,保持单次请求的幂等与可观测性
709
- try { /* no-op */ }
710
- catch { /* ignore */ }
711
- return response;
398
+ return this.requestExecutor.execute(request, context);
712
399
  }
713
400
  wantsUpstreamSse(_request, _context) {
714
401
  return false;
@@ -744,6 +431,135 @@ export class HttpTransportProvider extends BaseProvider {
744
431
  return false;
745
432
  }
746
433
  }
434
+ getHttpRetryLimit() {
435
+ return 3;
436
+ }
437
+ async delayBeforeHttpRetry(attempt) {
438
+ const delay = Math.min(500 * attempt, 2000);
439
+ await new Promise((resolve) => setTimeout(resolve, delay));
440
+ }
441
+ shouldRetryHttpError(error, attempt, maxAttempts) {
442
+ if (attempt >= maxAttempts) {
443
+ return false;
444
+ }
445
+ const normalized = error;
446
+ const statusCode = extractStatusCodeFromError(normalized);
447
+ if (statusCode && statusCode >= 500) {
448
+ return true;
449
+ }
450
+ return false;
451
+ }
452
+ async tryRecoverOAuthAndReplay(error, requestInfo, processedRequest, captureSse, context) {
453
+ try {
454
+ const providerAuth = this.config.config.auth;
455
+ if (this.normalizeAuthMode(providerAuth.type) !== 'oauth') {
456
+ return undefined;
457
+ }
458
+ const shouldRetry = await handleUpstreamInvalidOAuthToken(this.oauthProviderId || this.providerType, providerAuth, error);
459
+ if (!shouldRetry) {
460
+ return undefined;
461
+ }
462
+ const retryHeaders = await this.buildRequestHeaders();
463
+ let finalRetryHeaders = await this.finalizeRequestHeaders(retryHeaders, processedRequest);
464
+ finalRetryHeaders = this.applyStreamModeHeaders(finalRetryHeaders, requestInfo.wantsSse);
465
+ if (requestInfo.wantsSse) {
466
+ const upstreamStream = await this.httpClient.postStream(requestInfo.endpoint, requestInfo.body, finalRetryHeaders);
467
+ const streamForHost = captureSse
468
+ ? attachProviderSseSnapshotStream(upstreamStream, {
469
+ requestId: context.requestId,
470
+ headers: finalRetryHeaders,
471
+ url: requestInfo.targetUrl,
472
+ entryEndpoint: requestInfo.entryEndpoint,
473
+ clientRequestId: requestInfo.clientRequestId,
474
+ extra: { retry: true }
475
+ })
476
+ : upstreamStream;
477
+ const wrapped = await this.wrapUpstreamSseResponse(streamForHost, context);
478
+ if (!captureSse) {
479
+ try {
480
+ await writeProviderSnapshot({
481
+ phase: 'provider-response',
482
+ requestId: context.requestId,
483
+ data: { mode: 'sse', retry: true },
484
+ headers: finalRetryHeaders,
485
+ url: requestInfo.targetUrl,
486
+ entryEndpoint: requestInfo.entryEndpoint,
487
+ clientRequestId: requestInfo.clientRequestId
488
+ });
489
+ }
490
+ catch { /* non-blocking */ }
491
+ }
492
+ return wrapped;
493
+ }
494
+ const response = await this.httpClient.post(requestInfo.endpoint, requestInfo.body, finalRetryHeaders);
495
+ try {
496
+ await writeProviderSnapshot({
497
+ phase: 'provider-response',
498
+ requestId: context.requestId,
499
+ data: response,
500
+ headers: finalRetryHeaders,
501
+ url: requestInfo.targetUrl,
502
+ entryEndpoint: requestInfo.entryEndpoint,
503
+ clientRequestId: requestInfo.clientRequestId
504
+ });
505
+ }
506
+ catch { /* non-blocking */ }
507
+ return response;
508
+ }
509
+ catch {
510
+ return undefined;
511
+ }
512
+ }
513
+ async normalizeHttpError(error, processedRequest, requestInfo, context) {
514
+ const normalized = error;
515
+ try {
516
+ const statusCode = extractStatusCodeFromError(normalized);
517
+ if (statusCode && !Number.isNaN(statusCode)) {
518
+ normalized.statusCode = statusCode;
519
+ if (!normalized.status) {
520
+ normalized.status = statusCode;
521
+ }
522
+ if (!normalized.code) {
523
+ normalized.code = `HTTP_${statusCode}`;
524
+ }
525
+ }
526
+ if (!normalized.response) {
527
+ normalized.response = {};
528
+ }
529
+ if (!normalized.response.data) {
530
+ normalized.response.data = {};
531
+ }
532
+ if (!normalized.response.data.error) {
533
+ normalized.response.data.error = {};
534
+ }
535
+ if (normalized.code && !normalized.response.data.error.code) {
536
+ normalized.response.data.error.code = normalized.code;
537
+ }
538
+ if (normalized.message && !normalized.response.data.error.message) {
539
+ normalized.response.data.error.message = normalized.message;
540
+ }
541
+ }
542
+ catch {
543
+ /* ignore */
544
+ }
545
+ try {
546
+ await writeProviderSnapshot({
547
+ phase: 'provider-error',
548
+ requestId: context.requestId,
549
+ data: {
550
+ status: normalized?.statusCode ?? normalized?.status ?? null,
551
+ code: normalized?.code ?? null,
552
+ error: typeof normalized?.message === 'string' ? normalized.message : String(error || '')
553
+ },
554
+ headers: requestInfo.headers,
555
+ url: requestInfo.targetUrl,
556
+ entryEndpoint: requestInfo.entryEndpoint ?? this.getEntryEndpointFromPayload(processedRequest),
557
+ clientRequestId: requestInfo.clientRequestId ?? this.getClientRequestIdFromContext(context)
558
+ });
559
+ }
560
+ catch { /* non-blocking */ }
561
+ return normalized;
562
+ }
747
563
  /**
748
564
  * 为特定请求确定最终 endpoint(默认使用配置值,可由子类覆写)
749
565
  */
@@ -793,6 +609,8 @@ export class HttpTransportProvider extends BaseProvider {
793
609
  const inboundOriginator = typeof inboundMetadata?.clientOriginator === 'string' && inboundMetadata.clientOriginator.trim()
794
610
  ? inboundMetadata.clientOriginator.trim()
795
611
  : undefined;
612
+ const inboundClientHeaders = this.extractClientHeaders(runtimeMetadata);
613
+ const normalizedClientHeaders = this.normalizeCodexClientHeaders(inboundClientHeaders);
796
614
  // 服务特定头部
797
615
  const serviceHeaders = this.serviceProfile.headers || {};
798
616
  // 配置覆盖头部
@@ -803,7 +621,7 @@ export class HttpTransportProvider extends BaseProvider {
803
621
  const auth = this.config.config.auth;
804
622
  if (this.normalizeAuthMode(auth.type) === 'oauth') {
805
623
  const oauthAuth = auth;
806
- const oauthProviderId = this.ensureOAuthProviderId(oauthAuth);
624
+ const oauthProviderId = this.oauthProviderId || this.ensureOAuthProviderId(oauthAuth);
807
625
  logOAuthDebug('[OAuth] [headers] ensureValid start (openBrowser=true, forceReauth=false)');
808
626
  try {
809
627
  await ensureValidOAuthToken(oauthProviderId, oauthAuth, {
@@ -848,55 +666,146 @@ export class HttpTransportProvider extends BaseProvider {
848
666
  ...runtimeHeaders,
849
667
  ...authHeaders
850
668
  };
851
- // 禁用上游SSE:设置 Accept application/json(若未被显式覆盖)
852
- if (!('Accept' in finalHeaders) && !('accept' in finalHeaders)) {
853
- finalHeaders['Accept'] = 'application/json';
854
- }
855
- const getHeader = (headers, target) => {
856
- const lowered = target.toLowerCase();
857
- for (const [key, value] of Object.entries(headers)) {
858
- if (key.toLowerCase() === lowered && typeof value === 'string' && value.trim()) {
859
- return value.trim();
860
- }
861
- }
862
- return undefined;
863
- };
864
- const setHeader = (headers, target, value) => {
865
- if (!value || !value.trim())
866
- return;
867
- const lowered = target.toLowerCase();
868
- for (const key of Object.keys(headers)) {
869
- if (key.toLowerCase() === lowered) {
870
- headers[key] = value;
871
- return;
872
- }
873
- }
874
- headers[target] = value;
875
- };
669
+ // 保留客户端 Accept;无则默认为 application/json
670
+ const clientAccept = normalizedClientHeaders ? this.findHeaderValue(normalizedClientHeaders, 'Accept') : undefined;
671
+ if (clientAccept) {
672
+ this.assignHeader(finalHeaders, 'Accept', clientAccept);
673
+ }
674
+ else if (!this.findHeaderValue(finalHeaders, 'Accept')) {
675
+ this.assignHeader(finalHeaders, 'Accept', 'application/json');
676
+ }
876
677
  // Header priority:
877
678
  // - user/provider config (overrides/runtime) wins
878
679
  // - otherwise inherit from inbound client headers
879
680
  // - otherwise fall back to defaults
880
- const uaFromConfig = getHeader({ ...overrideHeaders, ...runtimeHeaders }, 'User-Agent');
881
- const uaFromService = getHeader(serviceHeaders, 'User-Agent');
681
+ const uaFromConfig = this.findHeaderValue({ ...overrideHeaders, ...runtimeHeaders }, 'User-Agent');
682
+ const uaFromService = this.findHeaderValue(serviceHeaders, 'User-Agent');
882
683
  const resolvedUa = uaFromConfig ?? inboundUserAgent ?? uaFromService ?? DEFAULT_USER_AGENT;
883
- setHeader(finalHeaders, 'User-Agent', resolvedUa);
684
+ this.assignHeader(finalHeaders, 'User-Agent', resolvedUa);
884
685
  // originator: do not invent one; only forward from config or inbound client
885
- const originatorFromConfig = getHeader({ ...overrideHeaders, ...runtimeHeaders }, 'originator');
886
- const originatorFromService = getHeader(serviceHeaders, 'originator');
686
+ const originatorFromConfig = this.findHeaderValue({ ...overrideHeaders, ...runtimeHeaders }, 'originator');
687
+ const originatorFromService = this.findHeaderValue(serviceHeaders, 'originator');
887
688
  const resolvedOriginator = originatorFromConfig ?? inboundOriginator ?? originatorFromService;
888
689
  if (resolvedOriginator) {
889
- setHeader(finalHeaders, 'originator', resolvedOriginator);
890
- }
891
- // 获取Hook管理器(新的统一系统)
892
- const hookManager = this.getHookManager();
893
- // 🔍 Hook 6: 认证阶段
894
- await hookManager.executeHookChain('authentication', 'auth', authHeaders, this.createProviderContext());
895
- // 🔍 Hook 7: Headers处理阶段
896
- const headersResult = await hookManager.executeHookChain('request_preprocessing', 'headers', finalHeaders, this.createProviderContext());
897
- finalHeaders = headersResult.data;
690
+ this.assignHeader(finalHeaders, 'originator', resolvedOriginator);
691
+ }
692
+ if (normalizedClientHeaders) {
693
+ const conversationId = this.findHeaderValue(normalizedClientHeaders, 'conversation_id');
694
+ if (conversationId) {
695
+ this.assignHeader(finalHeaders, 'conversation_id', conversationId);
696
+ }
697
+ const sessionId = this.findHeaderValue(normalizedClientHeaders, 'session_id');
698
+ if (sessionId) {
699
+ this.assignHeader(finalHeaders, 'session_id', sessionId);
700
+ }
701
+ }
702
+ if (this.isCodexUaMode()) {
703
+ this.ensureCodexSessionHeaders(finalHeaders, runtimeMetadata);
704
+ }
898
705
  return finalHeaders;
899
706
  }
707
+ isCodexUaMode() {
708
+ const raw = process.env.ROUTECODEX_UA_MODE ??
709
+ process.env.RCC_UA_MODE ??
710
+ '';
711
+ const normalized = typeof raw === 'string' ? raw.trim().toLowerCase() : '';
712
+ const runtime = this.getCurrentRuntimeMetadata();
713
+ if (!runtime) {
714
+ return false;
715
+ }
716
+ const providerType = runtime.providerType || this.providerType;
717
+ const entryEndpoint = this.getEntryEndpointFromRuntime(runtime);
718
+ // 显式 UA 模式(--codex / --ua codex):对所有 provider 激活
719
+ if (normalized === 'codex') {
720
+ return true;
721
+ }
722
+ // 隐式模式:未显式设置 UA 时,仅在 responses provider 且入口不是 /v1/responses 时激活
723
+ if (providerType === 'responses' && entryEndpoint) {
724
+ const lowered = entryEndpoint.trim().toLowerCase();
725
+ if (!lowered.includes('/responses')) {
726
+ return true;
727
+ }
728
+ }
729
+ return false;
730
+ }
731
+ normalizeCodexClientHeaders(headers) {
732
+ if (!headers) {
733
+ return undefined;
734
+ }
735
+ if (!this.isCodexUaMode()) {
736
+ return headers;
737
+ }
738
+ const normalizedHeaders = { ...headers };
739
+ this.copyHeaderValue(normalizedHeaders, headers, 'anthropic-session-id', 'session_id');
740
+ this.copyHeaderValue(normalizedHeaders, headers, 'anthropic-conversation-id', 'conversation_id');
741
+ this.copyHeaderValue(normalizedHeaders, headers, 'anthropic-user-agent', 'User-Agent');
742
+ this.copyHeaderValue(normalizedHeaders, headers, 'anthropic-originator', 'originator');
743
+ return normalizedHeaders;
744
+ }
745
+ copyHeaderValue(target, source, from, to) {
746
+ if (this.findHeaderValue(target, to)) {
747
+ return;
748
+ }
749
+ const value = this.findHeaderValue(source, from);
750
+ if (value) {
751
+ target[to] = value;
752
+ }
753
+ }
754
+ findHeaderValue(headers, target) {
755
+ const lowered = target.toLowerCase();
756
+ for (const [key, value] of Object.entries(headers)) {
757
+ if (key.toLowerCase() === lowered && typeof value === 'string' && value.trim()) {
758
+ return value.trim();
759
+ }
760
+ }
761
+ return undefined;
762
+ }
763
+ assignHeader(headers, target, value) {
764
+ if (!value || !value.trim()) {
765
+ return;
766
+ }
767
+ const lowered = target.toLowerCase();
768
+ for (const key of Object.keys(headers)) {
769
+ if (key.toLowerCase() === lowered) {
770
+ headers[key] = value;
771
+ return;
772
+ }
773
+ }
774
+ headers[target] = value;
775
+ }
776
+ ensureCodexSessionHeaders(headers, runtimeMetadata) {
777
+ this.setHeaderIfMissing(headers, 'session_id', this.buildCodexIdentifier('session', runtimeMetadata));
778
+ this.setHeaderIfMissing(headers, 'conversation_id', this.buildCodexIdentifier('conversation', runtimeMetadata));
779
+ }
780
+ setHeaderIfMissing(headers, target, value) {
781
+ if (this.findHeaderValue(headers, target)) {
782
+ return;
783
+ }
784
+ this.assignHeader(headers, target, value);
785
+ }
786
+ buildCodexIdentifier(kind, runtimeMetadata) {
787
+ const fallbackId = runtimeMetadata?.metadata && typeof runtimeMetadata.metadata === 'object'
788
+ ? runtimeMetadata.metadata.clientRequestId
789
+ : undefined;
790
+ const requestId = runtimeMetadata?.requestId ?? fallbackId;
791
+ const routeName = runtimeMetadata?.routeName;
792
+ const suffix = (requestId ?? `req-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`)
793
+ .toString()
794
+ .replace(/[^A-Za-z0-9_-]/g, '_');
795
+ const parts = ['codex_cli', kind, suffix];
796
+ if (routeName) {
797
+ parts.push(routeName.replace(/[^A-Za-z0-9_-]/g, '_'));
798
+ }
799
+ return this.enforceCodexIdentifierLength(parts.join('_'));
800
+ }
801
+ enforceCodexIdentifierLength(value) {
802
+ if (value.length <= CODEX_IDENTIFIER_MAX_LENGTH) {
803
+ return value;
804
+ }
805
+ const hash = createHash('sha256').update(value).digest('hex').slice(0, 10);
806
+ const keep = Math.max(1, CODEX_IDENTIFIER_MAX_LENGTH - hash.length - 1);
807
+ return `${value.slice(0, keep)}_${hash}`;
808
+ }
900
809
  getEffectiveBaseUrl() {
901
810
  const runtime = this.getRuntimeProfile();
902
811
  const runtimeEndpoint = this.pickRuntimeBaseUrl(runtime);
@@ -934,9 +843,6 @@ export class HttpTransportProvider extends BaseProvider {
934
843
  const trimmed = value.trim();
935
844
  return /^https?:\/\//i.test(trimmed) || trimmed.startsWith('//');
936
845
  }
937
- getHookManager() {
938
- return this.hookSystemIntegration.getBidirectionalHookManager();
939
- }
940
846
  // (工具自动修复辅助函数已删除)
941
847
  getConfigExtensions() {
942
848
  const extensions = this.config.config.extensions;
@@ -945,12 +851,23 @@ export class HttpTransportProvider extends BaseProvider {
945
851
  : {};
946
852
  }
947
853
  getEntryEndpointFromPayload(payload) {
948
- const metadata = payload.metadata;
949
- if (metadata && typeof metadata.entryEndpoint === 'string') {
854
+ const runtimeMeta = extractProviderRuntimeMetadata(payload);
855
+ const metadata = (runtimeMeta && typeof runtimeMeta.metadata === 'object')
856
+ ? runtimeMeta.metadata
857
+ : payload.metadata;
858
+ if (metadata && typeof metadata.entryEndpoint === 'string' && metadata.entryEndpoint.trim()) {
950
859
  return metadata.entryEndpoint;
951
860
  }
952
861
  return undefined;
953
862
  }
863
+ getEntryEndpointFromRuntime(runtime) {
864
+ if (!runtime || !runtime.metadata || typeof runtime.metadata !== 'object') {
865
+ return undefined;
866
+ }
867
+ const meta = runtime.metadata;
868
+ const value = meta.entryEndpoint;
869
+ return typeof value === 'string' && value.trim().length ? value : undefined;
870
+ }
954
871
  asResponseRecord(value) {
955
872
  if (isRecord(value)) {
956
873
  return value;
@@ -1056,5 +973,126 @@ export class HttpTransportProvider extends BaseProvider {
1056
973
  }
1057
974
  return providerId;
1058
975
  }
976
+ extractClientHeaders(source) {
977
+ const normalize = (value) => {
978
+ return this.normalizeClientHeaders(value);
979
+ };
980
+ if (!source || typeof source !== 'object') {
981
+ return undefined;
982
+ }
983
+ const candidates = [];
984
+ const metadataNode = source.metadata;
985
+ if (metadataNode && typeof metadataNode === 'object') {
986
+ const headersNode = metadataNode.clientHeaders;
987
+ if (headersNode) {
988
+ candidates.push(headersNode);
989
+ }
990
+ }
991
+ const directNode = source.clientHeaders;
992
+ if (directNode) {
993
+ candidates.push(directNode);
994
+ }
995
+ for (const candidate of candidates) {
996
+ const normalized = normalize(candidate);
997
+ if (normalized) {
998
+ return normalized;
999
+ }
1000
+ }
1001
+ return undefined;
1002
+ }
1003
+ normalizeClientHeaders(value) {
1004
+ if (!value || typeof value !== 'object') {
1005
+ return undefined;
1006
+ }
1007
+ const normalized = {};
1008
+ for (const [key, raw] of Object.entries(value)) {
1009
+ if (typeof raw === 'string' && raw.trim()) {
1010
+ normalized[key] = raw;
1011
+ }
1012
+ }
1013
+ return Object.keys(normalized).length ? normalized : undefined;
1014
+ }
1015
+ async ensureAntigravityProjectMetadata(oauthAuth) {
1016
+ const tokenFile = typeof oauthAuth?.tokenFile === 'string' ? oauthAuth.tokenFile.trim() : '';
1017
+ if (!tokenFile) {
1018
+ return;
1019
+ }
1020
+ const tokenPath = tokenFile.startsWith('~/')
1021
+ ? tokenFile.replace(/^~\//, `${process.env.HOME || ''}/`)
1022
+ : tokenFile;
1023
+ let raw;
1024
+ try {
1025
+ raw = await fs.readFile(tokenPath, 'utf-8');
1026
+ }
1027
+ catch {
1028
+ return;
1029
+ }
1030
+ let parsed;
1031
+ try {
1032
+ parsed = JSON.parse(raw);
1033
+ }
1034
+ catch {
1035
+ return;
1036
+ }
1037
+ if (this.extractProjectIdFromTokenSnapshot(parsed)) {
1038
+ return;
1039
+ }
1040
+ const accessToken = this.extractAccessTokenFromSnapshot(parsed);
1041
+ if (!accessToken) {
1042
+ return;
1043
+ }
1044
+ const baseOverride = oauthAuth.antigravityApiBase;
1045
+ const apiBaseHint = baseOverride || this.getEffectiveBaseUrl();
1046
+ const projectId = await fetchAntigravityProjectId(accessToken, apiBaseHint);
1047
+ if (!projectId) {
1048
+ logOAuthDebug('[OAuth] Antigravity: unable to resolve project_id for token file');
1049
+ return;
1050
+ }
1051
+ parsed.project_id = projectId;
1052
+ parsed.projectId = projectId;
1053
+ const projectsNode = parsed.projects;
1054
+ if (!Array.isArray(projectsNode) || !projectsNode.length) {
1055
+ parsed.projects = [{ projectId }];
1056
+ }
1057
+ await fs.writeFile(tokenPath, JSON.stringify(parsed, null, 2));
1058
+ logOAuthDebug(`[OAuth] Antigravity: persisted project_id=${projectId} for ${tokenPath}`);
1059
+ }
1060
+ extractAccessTokenFromSnapshot(snapshot) {
1061
+ const lower = snapshot.access_token;
1062
+ const upper = snapshot.AccessToken;
1063
+ const value = typeof lower === 'string'
1064
+ ? lower
1065
+ : typeof upper === 'string'
1066
+ ? upper
1067
+ : undefined;
1068
+ if (value && value.trim()) {
1069
+ return value.trim();
1070
+ }
1071
+ return undefined;
1072
+ }
1073
+ extractProjectIdFromTokenSnapshot(snapshot) {
1074
+ const directNode = snapshot.project_id;
1075
+ const direct = typeof directNode === 'string' ? directNode : undefined;
1076
+ if (direct && direct.trim()) {
1077
+ return direct.trim();
1078
+ }
1079
+ const camelNode = snapshot.projectId;
1080
+ const camel = typeof camelNode === 'string' ? camelNode : undefined;
1081
+ if (camel && camel.trim()) {
1082
+ return camel.trim();
1083
+ }
1084
+ if (Array.isArray(snapshot.projects)) {
1085
+ for (const entry of snapshot.projects ?? []) {
1086
+ if (entry && typeof entry === 'object' && typeof entry.projectId === 'string') {
1087
+ const candidate = String(entry.projectId);
1088
+ if (candidate.trim()) {
1089
+ return candidate.trim();
1090
+ }
1091
+ }
1092
+ }
1093
+ }
1094
+ return undefined;
1095
+ }
1059
1096
  }
1097
+ const CODEX_IDENTIFIER_MAX_LENGTH = 64;
1060
1098
  //# sourceMappingURL=http-transport-provider.js.map