@jsonstudio/rcc 0.89.168 → 0.89.524

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 (431) 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 +94 -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/commands/token-daemon.d.ts +2 -0
  9. package/dist/commands/token-daemon.js +183 -0
  10. package/dist/commands/token-daemon.js.map +1 -0
  11. package/dist/error-handling/quiet-error-handling-center.d.ts +9 -0
  12. package/dist/error-handling/quiet-error-handling-center.js +141 -0
  13. package/dist/error-handling/quiet-error-handling-center.js.map +1 -0
  14. package/dist/error-handling/route-error-hub.js +8 -2
  15. package/dist/error-handling/route-error-hub.js.map +1 -1
  16. package/dist/index.js +4 -3
  17. package/dist/index.js.map +1 -1
  18. package/dist/modules/llmswitch/bridge.d.ts +1 -1
  19. package/dist/modules/llmswitch/bridge.js +3 -2
  20. package/dist/modules/llmswitch/bridge.js.map +1 -1
  21. package/dist/modules/pipeline/utils/colored-logger.d.ts +2 -0
  22. package/dist/modules/pipeline/utils/colored-logger.js +22 -3
  23. package/dist/modules/pipeline/utils/colored-logger.js.map +1 -1
  24. package/dist/providers/auth/antigravity-userinfo-helper.d.ts +10 -0
  25. package/dist/providers/auth/antigravity-userinfo-helper.js +140 -0
  26. package/dist/providers/auth/antigravity-userinfo-helper.js.map +1 -0
  27. package/dist/providers/auth/gemini-cli-userinfo-helper.js +12 -2
  28. package/dist/providers/auth/gemini-cli-userinfo-helper.js.map +1 -1
  29. package/dist/providers/auth/oauth-lifecycle.js +395 -24
  30. package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
  31. package/dist/providers/auth/token-scanner/index.d.ts +32 -0
  32. package/dist/providers/auth/token-scanner/index.js +86 -0
  33. package/dist/providers/auth/token-scanner/index.js.map +1 -0
  34. package/dist/providers/auth/tokenfile-auth.d.ts +17 -0
  35. package/dist/providers/auth/tokenfile-auth.js +27 -5
  36. package/dist/providers/auth/tokenfile-auth.js.map +1 -1
  37. package/dist/providers/core/api/provider-types.d.ts +10 -0
  38. package/dist/providers/core/config/oauth-flows.d.ts +25 -0
  39. package/dist/providers/core/config/oauth-flows.js +92 -5
  40. package/dist/providers/core/config/oauth-flows.js.map +1 -1
  41. package/dist/providers/core/config/provider-oauth-configs.js +93 -2
  42. package/dist/providers/core/config/provider-oauth-configs.js.map +1 -1
  43. package/dist/providers/core/config/service-profiles.js +18 -10
  44. package/dist/providers/core/config/service-profiles.js.map +1 -1
  45. package/dist/providers/core/runtime/base-provider.d.ts +2 -0
  46. package/dist/providers/core/runtime/base-provider.js +135 -15
  47. package/dist/providers/core/runtime/base-provider.js.map +1 -1
  48. package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +8 -3
  49. package/dist/providers/core/runtime/gemini-cli-http-provider.js +332 -67
  50. package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
  51. package/dist/providers/core/runtime/http-request-executor.d.ts +1 -0
  52. package/dist/providers/core/runtime/http-request-executor.js +41 -1
  53. package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
  54. package/dist/providers/core/runtime/http-transport-provider.d.ts +27 -0
  55. package/dist/providers/core/runtime/http-transport-provider.js +342 -69
  56. package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
  57. package/dist/providers/core/runtime/provider-error-classifier.d.ts +2 -2
  58. package/dist/providers/core/runtime/provider-error-classifier.js +14 -4
  59. package/dist/providers/core/runtime/provider-error-classifier.js.map +1 -1
  60. package/dist/providers/core/runtime/provider-factory.d.ts +1 -0
  61. package/dist/providers/core/runtime/provider-factory.js +37 -8
  62. package/dist/providers/core/runtime/provider-factory.js.map +1 -1
  63. package/dist/providers/core/runtime/responses-provider.d.ts +3 -3
  64. package/dist/providers/core/runtime/responses-provider.js +56 -117
  65. package/dist/providers/core/runtime/responses-provider.js.map +1 -1
  66. package/dist/providers/core/runtime/vision-debug-utils.d.ts +13 -0
  67. package/dist/providers/core/runtime/vision-debug-utils.js +114 -0
  68. package/dist/providers/core/runtime/vision-debug-utils.js.map +1 -0
  69. package/dist/providers/core/strategies/oauth-auth-code-flow.js +82 -25
  70. package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
  71. package/dist/providers/core/utils/http-client.d.ts +5 -0
  72. package/dist/providers/core/utils/http-client.js +31 -4
  73. package/dist/providers/core/utils/http-client.js.map +1 -1
  74. package/dist/providers/core/utils/provider-error-reporter.js +8 -2
  75. package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
  76. package/dist/providers/core/utils/snapshot-writer.d.ts +1 -1
  77. package/dist/providers/core/utils/snapshot-writer.js +5 -1
  78. package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
  79. package/dist/providers/profile/provider-profile-loader.js +8 -4
  80. package/dist/providers/profile/provider-profile-loader.js.map +1 -1
  81. package/dist/runtime/runtime-flags.d.ts +4 -0
  82. package/dist/runtime/runtime-flags.js +32 -0
  83. package/dist/runtime/runtime-flags.js.map +1 -0
  84. package/dist/server/handlers/handler-utils.js +29 -2
  85. package/dist/server/handlers/handler-utils.js.map +1 -1
  86. package/dist/server/handlers/messages-handler.js +27 -26
  87. package/dist/server/handlers/messages-handler.js.map +1 -1
  88. package/dist/server/handlers/responses-handler.js +35 -1
  89. package/dist/server/handlers/responses-handler.js.map +1 -1
  90. package/dist/server/handlers/sse-dispatcher.js +22 -2
  91. package/dist/server/handlers/sse-dispatcher.js.map +1 -1
  92. package/dist/server/runtime/http-server/index.d.ts +10 -0
  93. package/dist/server/runtime/http-server/index.js +551 -148
  94. package/dist/server/runtime/http-server/index.js.map +1 -1
  95. package/dist/server/runtime/http-server/request-executor.d.ts +14 -0
  96. package/dist/server/runtime/http-server/request-executor.js +638 -149
  97. package/dist/server/runtime/http-server/request-executor.js.map +1 -1
  98. package/dist/server/runtime/http-server/routes.d.ts +5 -0
  99. package/dist/server/runtime/http-server/routes.js +69 -0
  100. package/dist/server/runtime/http-server/routes.js.map +1 -1
  101. package/dist/server/runtime/http-server/runtime-manager.js +18 -0
  102. package/dist/server/runtime/http-server/runtime-manager.js.map +1 -1
  103. package/dist/server/utils/sse-request-parser.d.ts +1 -0
  104. package/dist/server/utils/sse-request-parser.js +17 -6
  105. package/dist/server/utils/sse-request-parser.js.map +1 -1
  106. package/dist/server/utils/utf8-chunk-buffer.d.ts +43 -0
  107. package/dist/server/utils/utf8-chunk-buffer.js +132 -0
  108. package/dist/server/utils/utf8-chunk-buffer.js.map +1 -0
  109. package/dist/server/utils/warmup-detector.d.ts +7 -0
  110. package/dist/server/utils/warmup-detector.js +125 -0
  111. package/dist/server/utils/warmup-detector.js.map +1 -0
  112. package/dist/server/utils/warmup-storm-tracker.d.ts +9 -0
  113. package/dist/server/utils/warmup-storm-tracker.js +61 -0
  114. package/dist/server/utils/warmup-storm-tracker.js.map +1 -0
  115. package/dist/token-daemon/index.d.ts +7 -0
  116. package/dist/token-daemon/index.js +242 -0
  117. package/dist/token-daemon/index.js.map +1 -0
  118. package/dist/token-daemon/server-utils.d.ts +33 -0
  119. package/dist/token-daemon/server-utils.js +155 -0
  120. package/dist/token-daemon/server-utils.js.map +1 -0
  121. package/dist/token-daemon/token-daemon.d.ts +20 -0
  122. package/dist/token-daemon/token-daemon.js +144 -0
  123. package/dist/token-daemon/token-daemon.js.map +1 -0
  124. package/dist/token-daemon/token-types.d.ts +44 -0
  125. package/dist/token-daemon/token-types.js +18 -0
  126. package/dist/token-daemon/token-types.js.map +1 -0
  127. package/dist/token-daemon/token-utils.d.ts +17 -0
  128. package/dist/token-daemon/token-utils.js +153 -0
  129. package/dist/token-daemon/token-utils.js.map +1 -0
  130. package/dist/tools/semantic-replay.js +7 -6
  131. package/dist/tools/semantic-replay.js.map +1 -1
  132. package/dist/utils/debug-utils.js +14 -0
  133. package/dist/utils/debug-utils.js.map +1 -1
  134. package/dist/utils/error-handler-registry.d.ts +36 -0
  135. package/dist/utils/error-handler-registry.js +99 -12
  136. package/dist/utils/error-handler-registry.js.map +1 -1
  137. package/dist/utils/error-handling-utils.js +4 -3
  138. package/dist/utils/error-handling-utils.js.map +1 -1
  139. package/dist/utils/log-helpers.d.ts +6 -0
  140. package/dist/utils/log-helpers.js +90 -0
  141. package/dist/utils/log-helpers.js.map +1 -0
  142. package/dist/utils/logger.d.ts +8 -0
  143. package/dist/utils/logger.js +55 -2
  144. package/dist/utils/logger.js.map +1 -1
  145. package/dist/utils/snapshot-writer.js +2 -6
  146. package/dist/utils/snapshot-writer.js.map +1 -1
  147. package/node_modules/@jsonstudio/llms/README.md +2 -0
  148. package/node_modules/@jsonstudio/llms/dist/conversion/codecs/gemini-openai-codec.js +152 -6
  149. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/auto-thinking.d.ts +6 -0
  150. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/auto-thinking.js +25 -0
  151. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/field-mapping.d.ts +14 -0
  152. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/field-mapping.js +155 -0
  153. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/gemini-web-search.d.ts +17 -0
  154. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/gemini-web-search.js +68 -0
  155. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-image-content.d.ts +2 -0
  156. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-image-content.js +83 -0
  157. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-tool-extraction.d.ts +2 -0
  158. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-tool-extraction.js +264 -0
  159. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-vision-prompt.d.ts +11 -0
  160. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-vision-prompt.js +177 -0
  161. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-web-search.d.ts +2 -0
  162. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/glm-web-search.js +63 -0
  163. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/qwen-transform.d.ts +3 -0
  164. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/qwen-transform.js +209 -0
  165. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/request-rules.d.ts +24 -0
  166. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/request-rules.js +63 -0
  167. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-blacklist.d.ts +14 -0
  168. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-blacklist.js +85 -0
  169. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-normalize.d.ts +5 -0
  170. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-normalize.js +121 -0
  171. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-validate.d.ts +5 -0
  172. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/response-validate.js +76 -0
  173. package/{dist/providers/compat/utils/snapshot-writer.d.ts → node_modules/@jsonstudio/llms/dist/conversion/compat/actions/snapshot.d.ts} +2 -2
  174. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/snapshot.js +21 -0
  175. package/node_modules/@jsonstudio/llms/dist/conversion/compat/actions/tool-schema.d.ts +6 -0
  176. package/{dist/providers/compat/glm/utils/tool-schema-helpers.js → node_modules/@jsonstudio/llms/dist/conversion/compat/actions/tool-schema.js} +6 -1
  177. package/{dist/providers/compat/filters → node_modules/@jsonstudio/llms/dist/conversion/compat/actions}/universal-shape-filter.d.ts +17 -22
  178. package/{dist/providers/compat/filters → node_modules/@jsonstudio/llms/dist/conversion/compat/actions}/universal-shape-filter.js +46 -99
  179. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-gemini.json +17 -0
  180. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-glm.json +196 -13
  181. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-iflow.json +194 -26
  182. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-lmstudio.json +43 -35
  183. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-qwen.json +20 -16
  184. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/responses-c4m.json +42 -42
  185. package/node_modules/@jsonstudio/llms/dist/conversion/config/sample-config.json +1 -1
  186. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.d.ts +7 -2
  187. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.js +5 -665
  188. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.d.ts +9 -0
  189. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +869 -0
  190. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-types.d.ts +55 -0
  191. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.d.ts +2 -0
  192. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.js +74 -5
  193. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +2 -2
  194. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/target-utils.js +9 -0
  195. package/node_modules/@jsonstudio/llms/dist/conversion/hub/process/chat-process.js +213 -1
  196. package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/provider-response.d.ts +34 -0
  197. package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/provider-response.js +84 -24
  198. package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/response-runtime.js +19 -2
  199. package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/server-side-tools.d.ts +26 -0
  200. package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/server-side-tools.js +383 -0
  201. package/node_modules/@jsonstudio/llms/dist/conversion/hub/semantic-mappers/gemini-mapper.js +241 -14
  202. package/node_modules/@jsonstudio/llms/dist/conversion/hub/semantic-mappers/responses-mapper.js +17 -1
  203. package/node_modules/@jsonstudio/llms/dist/conversion/hub/standardized-bridge.js +14 -0
  204. package/node_modules/@jsonstudio/llms/dist/conversion/hub/types/standardized.d.ts +1 -0
  205. package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-host-policy.d.ts +6 -0
  206. package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-host-policy.js +14 -0
  207. package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.js +133 -5
  208. package/node_modules/@jsonstudio/llms/dist/conversion/shared/anthropic-message-utils.js +98 -3
  209. package/node_modules/@jsonstudio/llms/dist/conversion/shared/bridge-message-utils.js +137 -10
  210. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-output-builder.js +43 -2
  211. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-reasoning-registry.d.ts +4 -0
  212. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-reasoning-registry.js +62 -1
  213. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-response-utils.js +23 -1
  214. package/node_modules/@jsonstudio/llms/dist/conversion/shared/snapshot-utils.js +17 -47
  215. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-canonicalizer.d.ts +2 -0
  216. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-filter-pipeline.js +12 -0
  217. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-mapping.js +25 -2
  218. package/node_modules/@jsonstudio/llms/dist/index.d.ts +1 -0
  219. package/node_modules/@jsonstudio/llms/dist/index.js +1 -0
  220. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/bootstrap.js +540 -36
  221. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/classifier.js +12 -11
  222. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/context-advisor.d.ts +19 -0
  223. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/context-advisor.js +64 -0
  224. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.d.ts +26 -0
  225. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.js +450 -54
  226. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/features.js +23 -458
  227. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/health-manager.js +2 -7
  228. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/message-utils.d.ts +7 -0
  229. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/message-utils.js +78 -0
  230. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/provider-registry.js +7 -2
  231. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-counter.js +14 -3
  232. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-estimator.d.ts +2 -0
  233. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-estimator.js +16 -0
  234. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-file-scanner.d.ts +15 -0
  235. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-file-scanner.js +56 -0
  236. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/tool-signals.d.ts +13 -0
  237. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/tool-signals.js +403 -0
  238. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.d.ts +86 -2
  239. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.js +3 -1
  240. package/node_modules/@jsonstudio/llms/dist/servertool/engine.d.ts +27 -0
  241. package/node_modules/@jsonstudio/llms/dist/servertool/engine.js +60 -0
  242. package/node_modules/@jsonstudio/llms/dist/servertool/flow-types.d.ts +40 -0
  243. package/node_modules/@jsonstudio/llms/dist/servertool/flow-types.js +1 -0
  244. package/node_modules/@jsonstudio/llms/dist/servertool/handlers/vision.d.ts +1 -0
  245. package/node_modules/@jsonstudio/llms/dist/servertool/handlers/vision.js +194 -0
  246. package/node_modules/@jsonstudio/llms/dist/servertool/handlers/web-search.d.ts +1 -0
  247. package/node_modules/@jsonstudio/llms/dist/servertool/handlers/web-search.js +638 -0
  248. package/node_modules/@jsonstudio/llms/dist/servertool/orchestration-types.d.ts +33 -0
  249. package/node_modules/@jsonstudio/llms/dist/servertool/orchestration-types.js +1 -0
  250. package/node_modules/@jsonstudio/llms/dist/servertool/registry.d.ts +18 -0
  251. package/node_modules/@jsonstudio/llms/dist/servertool/registry.js +27 -0
  252. package/node_modules/@jsonstudio/llms/dist/servertool/server-side-tools.d.ts +8 -0
  253. package/node_modules/@jsonstudio/llms/dist/servertool/server-side-tools.js +208 -0
  254. package/node_modules/@jsonstudio/llms/dist/servertool/types.d.ts +88 -0
  255. package/node_modules/@jsonstudio/llms/dist/servertool/types.js +1 -0
  256. package/node_modules/@jsonstudio/llms/dist/servertool/vision-tool.d.ts +2 -0
  257. package/node_modules/@jsonstudio/llms/dist/servertool/vision-tool.js +185 -0
  258. package/node_modules/@jsonstudio/llms/dist/sse/json-to-sse/event-generators/responses.js +15 -3
  259. package/node_modules/@jsonstudio/llms/dist/sse/sse-to-json/builders/response-builder.js +6 -3
  260. package/node_modules/@jsonstudio/llms/dist/sse/sse-to-json/gemini-sse-to-json-converter.js +27 -1
  261. package/node_modules/@jsonstudio/llms/dist/sse/types/gemini-types.d.ts +20 -1
  262. package/node_modules/@jsonstudio/llms/dist/sse/types/responses-types.js +1 -1
  263. package/node_modules/@jsonstudio/llms/dist/telemetry/stats-center.d.ts +73 -0
  264. package/node_modules/@jsonstudio/llms/dist/telemetry/stats-center.js +280 -0
  265. package/node_modules/@jsonstudio/llms/package.json +2 -2
  266. package/package.json +11 -10
  267. package/scripts/README.md +26 -12
  268. package/scripts/auth-antigravity-token.mjs +64 -0
  269. package/scripts/auth-gemini-cli-token.mjs +96 -0
  270. package/scripts/auth-iflow-manual.mjs +81 -0
  271. package/scripts/auth-iflow-token-direct.mjs +87 -0
  272. package/scripts/auth-iflow-token.mjs +77 -0
  273. package/scripts/copy-compat-assets.mjs +3 -15
  274. package/scripts/install-verify.mjs +1 -0
  275. package/scripts/pack-mode.mjs +2 -1
  276. package/scripts/publish-rcc.mjs +20 -4
  277. package/scripts/replay-codex-sample.mjs +13 -8
  278. package/scripts/tests/chat-pipeline-blackbox.mjs +1 -1
  279. package/scripts/tests/virtual-router-health.mjs +141 -6
  280. package/scripts/tools/capture-provider-goldens.mjs +8 -7
  281. package/scripts/verify-client-headers.mjs +224 -0
  282. package/dist/providers/compat/base-compatibility.d.ts +0 -27
  283. package/dist/providers/compat/base-compatibility.js +0 -143
  284. package/dist/providers/compat/base-compatibility.js.map +0 -1
  285. package/dist/providers/compat/compat-directory-loader.d.ts +0 -4
  286. package/dist/providers/compat/compat-directory-loader.js +0 -85
  287. package/dist/providers/compat/compat-directory-loader.js.map +0 -1
  288. package/dist/providers/compat/compatibility-adapter.d.ts +0 -18
  289. package/dist/providers/compat/compatibility-adapter.js +0 -104
  290. package/dist/providers/compat/compatibility-adapter.js.map +0 -1
  291. package/dist/providers/compat/compatibility-factory.d.ts +0 -57
  292. package/dist/providers/compat/compatibility-factory.js +0 -155
  293. package/dist/providers/compat/compatibility-factory.js.map +0 -1
  294. package/dist/providers/compat/compatibility-interface.d.ts +0 -35
  295. package/dist/providers/compat/compatibility-interface.js +0 -2
  296. package/dist/providers/compat/compatibility-interface.js.map +0 -1
  297. package/dist/providers/compat/compatibility-manager.d.ts +0 -85
  298. package/dist/providers/compat/compatibility-manager.js +0 -368
  299. package/dist/providers/compat/compatibility-manager.js.map +0 -1
  300. package/dist/providers/compat/config/config-compatibility.d.ts +0 -28
  301. package/dist/providers/compat/config/config-compatibility.js +0 -95
  302. package/dist/providers/compat/config/config-compatibility.js.map +0 -1
  303. package/dist/providers/compat/field-mapping.d.ts +0 -102
  304. package/dist/providers/compat/field-mapping.js +0 -447
  305. package/dist/providers/compat/field-mapping.js.map +0 -1
  306. package/dist/providers/compat/filters/blacklist-sanitizer.d.ts +0 -45
  307. package/dist/providers/compat/filters/blacklist-sanitizer.js +0 -133
  308. package/dist/providers/compat/filters/blacklist-sanitizer.js.map +0 -1
  309. package/dist/providers/compat/filters/response-blacklist-sanitizer.d.ts +0 -28
  310. package/dist/providers/compat/filters/response-blacklist-sanitizer.js +0 -138
  311. package/dist/providers/compat/filters/response-blacklist-sanitizer.js.map +0 -1
  312. package/dist/providers/compat/filters/universal-shape-filter.js.map +0 -1
  313. package/dist/providers/compat/glm/config/blacklist-rules.json +0 -22
  314. package/dist/providers/compat/glm/config/field-mappings.json +0 -92
  315. package/dist/providers/compat/glm/config/response-blacklist.json +0 -7
  316. package/dist/providers/compat/glm/config/shape-filters.json +0 -37
  317. package/dist/providers/compat/glm/field-mapping/field-mapping-processor.d.ts +0 -28
  318. package/dist/providers/compat/glm/field-mapping/field-mapping-processor.js +0 -306
  319. package/dist/providers/compat/glm/field-mapping/field-mapping-processor.js.map +0 -1
  320. package/dist/providers/compat/glm/functions/glm-processor.d.ts +0 -50
  321. package/dist/providers/compat/glm/functions/glm-processor.js +0 -134
  322. package/dist/providers/compat/glm/functions/glm-processor.js.map +0 -1
  323. package/dist/providers/compat/glm/glm-compatibility.d.ts +0 -34
  324. package/dist/providers/compat/glm/glm-compatibility.js +0 -117
  325. package/dist/providers/compat/glm/glm-compatibility.js.map +0 -1
  326. package/dist/providers/compat/glm/hooks/base-hook.d.ts +0 -21
  327. package/dist/providers/compat/glm/hooks/base-hook.js +0 -53
  328. package/dist/providers/compat/glm/hooks/base-hook.js.map +0 -1
  329. package/dist/providers/compat/glm/hooks/glm-request-validation-hook.d.ts +0 -24
  330. package/dist/providers/compat/glm/hooks/glm-request-validation-hook.js +0 -268
  331. package/dist/providers/compat/glm/hooks/glm-request-validation-hook.js.map +0 -1
  332. package/dist/providers/compat/glm/hooks/glm-response-normalization-hook.d.ts +0 -21
  333. package/dist/providers/compat/glm/hooks/glm-response-normalization-hook.js +0 -171
  334. package/dist/providers/compat/glm/hooks/glm-response-normalization-hook.js.map +0 -1
  335. package/dist/providers/compat/glm/hooks/glm-response-validation-hook.d.ts +0 -25
  336. package/dist/providers/compat/glm/hooks/glm-response-validation-hook.js +0 -236
  337. package/dist/providers/compat/glm/hooks/glm-response-validation-hook.js.map +0 -1
  338. package/dist/providers/compat/glm/hooks/glm-tool-cleaning-hook.d.ts +0 -26
  339. package/dist/providers/compat/glm/hooks/glm-tool-cleaning-hook.js +0 -186
  340. package/dist/providers/compat/glm/hooks/glm-tool-cleaning-hook.js.map +0 -1
  341. package/dist/providers/compat/glm/index.d.ts +0 -24
  342. package/dist/providers/compat/glm/index.js +0 -29
  343. package/dist/providers/compat/glm/index.js.map +0 -1
  344. package/dist/providers/compat/glm/utils/tool-schema-helpers.d.ts +0 -3
  345. package/dist/providers/compat/glm/utils/tool-schema-helpers.js.map +0 -1
  346. package/dist/providers/compat/iflow/config/field-mappings.json +0 -92
  347. package/dist/providers/compat/iflow/config/shape-filters.json +0 -37
  348. package/dist/providers/compat/iflow/field-mapping/iflow-field-mapping-processor.d.ts +0 -34
  349. package/dist/providers/compat/iflow/field-mapping/iflow-field-mapping-processor.js +0 -386
  350. package/dist/providers/compat/iflow/field-mapping/iflow-field-mapping-processor.js.map +0 -1
  351. package/dist/providers/compat/iflow/functions/iflow-processor.d.ts +0 -53
  352. package/dist/providers/compat/iflow/functions/iflow-processor.js +0 -215
  353. package/dist/providers/compat/iflow/functions/iflow-processor.js.map +0 -1
  354. package/dist/providers/compat/iflow/hooks/base-hook.d.ts +0 -23
  355. package/dist/providers/compat/iflow/hooks/base-hook.js +0 -59
  356. package/dist/providers/compat/iflow/hooks/base-hook.js.map +0 -1
  357. package/dist/providers/compat/iflow/hooks/iflow-request-validation-hook.d.ts +0 -23
  358. package/dist/providers/compat/iflow/hooks/iflow-request-validation-hook.js +0 -279
  359. package/dist/providers/compat/iflow/hooks/iflow-request-validation-hook.js.map +0 -1
  360. package/dist/providers/compat/iflow/hooks/iflow-response-normalization-hook.d.ts +0 -20
  361. package/dist/providers/compat/iflow/hooks/iflow-response-normalization-hook.js +0 -180
  362. package/dist/providers/compat/iflow/hooks/iflow-response-normalization-hook.js.map +0 -1
  363. package/dist/providers/compat/iflow/hooks/iflow-response-validation-hook.d.ts +0 -23
  364. package/dist/providers/compat/iflow/hooks/iflow-response-validation-hook.js +0 -232
  365. package/dist/providers/compat/iflow/hooks/iflow-response-validation-hook.js.map +0 -1
  366. package/dist/providers/compat/iflow/hooks/iflow-tool-cleaning-hook.d.ts +0 -25
  367. package/dist/providers/compat/iflow/hooks/iflow-tool-cleaning-hook.js +0 -216
  368. package/dist/providers/compat/iflow/hooks/iflow-tool-cleaning-hook.js.map +0 -1
  369. package/dist/providers/compat/iflow/iflow-compatibility.d.ts +0 -24
  370. package/dist/providers/compat/iflow/iflow-compatibility.js +0 -94
  371. package/dist/providers/compat/iflow/iflow-compatibility.js.map +0 -1
  372. package/dist/providers/compat/index.d.ts +0 -59
  373. package/dist/providers/compat/index.js +0 -83
  374. package/dist/providers/compat/index.js.map +0 -1
  375. package/dist/providers/compat/lmstudio-compatibility.d.ts +0 -44
  376. package/dist/providers/compat/lmstudio-compatibility.js +0 -193
  377. package/dist/providers/compat/lmstudio-compatibility.js.map +0 -1
  378. package/dist/providers/compat/passthrough-compatibility.d.ts +0 -29
  379. package/dist/providers/compat/passthrough-compatibility.js +0 -83
  380. package/dist/providers/compat/passthrough-compatibility.js.map +0 -1
  381. package/dist/providers/compat/profiles/chat/glm/index.d.ts +0 -6
  382. package/dist/providers/compat/profiles/chat/glm/index.js +0 -6
  383. package/dist/providers/compat/profiles/chat/glm/index.js.map +0 -1
  384. package/dist/providers/compat/profiles/chat/iflow/index.d.ts +0 -6
  385. package/dist/providers/compat/profiles/chat/iflow/index.js +0 -6
  386. package/dist/providers/compat/profiles/chat/iflow/index.js.map +0 -1
  387. package/dist/providers/compat/profiles/chat/lmstudio/index.d.ts +0 -6
  388. package/dist/providers/compat/profiles/chat/lmstudio/index.js +0 -6
  389. package/dist/providers/compat/profiles/chat/lmstudio/index.js.map +0 -1
  390. package/dist/providers/compat/profiles/chat/qwen/index.d.ts +0 -6
  391. package/dist/providers/compat/profiles/chat/qwen/index.js +0 -6
  392. package/dist/providers/compat/profiles/chat/qwen/index.js.map +0 -1
  393. package/dist/providers/compat/profiles/compat/passthrough/index.d.ts +0 -6
  394. package/dist/providers/compat/profiles/compat/passthrough/index.js +0 -6
  395. package/dist/providers/compat/profiles/compat/passthrough/index.js.map +0 -1
  396. package/dist/providers/compat/profiles/responses/c4m/index.d.ts +0 -6
  397. package/dist/providers/compat/profiles/responses/c4m/index.js +0 -6
  398. package/dist/providers/compat/profiles/responses/c4m/index.js.map +0 -1
  399. package/dist/providers/compat/profiles/responses/default/index.d.ts +0 -6
  400. package/dist/providers/compat/profiles/responses/default/index.js +0 -6
  401. package/dist/providers/compat/profiles/responses/default/index.js.map +0 -1
  402. package/dist/providers/compat/profiles/responses/fai/index.d.ts +0 -6
  403. package/dist/providers/compat/profiles/responses/fai/index.js +0 -6
  404. package/dist/providers/compat/profiles/responses/fai/index.js.map +0 -1
  405. package/dist/providers/compat/profiles/responses/fc/index.d.ts +0 -6
  406. package/dist/providers/compat/profiles/responses/fc/index.js +0 -6
  407. package/dist/providers/compat/profiles/responses/fc/index.js.map +0 -1
  408. package/dist/providers/compat/qwen/index.d.ts +0 -4
  409. package/dist/providers/compat/qwen/index.js +0 -6
  410. package/dist/providers/compat/qwen/index.js.map +0 -1
  411. package/dist/providers/compat/qwen-compatibility.d.ts +0 -52
  412. package/dist/providers/compat/qwen-compatibility.js +0 -330
  413. package/dist/providers/compat/qwen-compatibility.js.map +0 -1
  414. package/dist/providers/compat/register-compat-module.d.ts +0 -8
  415. package/dist/providers/compat/register-compat-module.js +0 -53
  416. package/dist/providers/compat/register-compat-module.js.map +0 -1
  417. package/dist/providers/compat/responses/c4m-responses-compatibility.d.ts +0 -27
  418. package/dist/providers/compat/responses/c4m-responses-compatibility.js +0 -197
  419. package/dist/providers/compat/responses/c4m-responses-compatibility.js.map +0 -1
  420. package/dist/providers/compat/standard-compatibility-utils.d.ts +0 -1
  421. package/dist/providers/compat/standard-compatibility-utils.js +0 -77
  422. package/dist/providers/compat/standard-compatibility-utils.js.map +0 -1
  423. package/dist/providers/compat/standard-compatibility.d.ts +0 -31
  424. package/dist/providers/compat/standard-compatibility.js +0 -118
  425. package/dist/providers/compat/standard-compatibility.js.map +0 -1
  426. package/dist/providers/compat/utils/snapshot-writer.js +0 -62
  427. package/dist/providers/compat/utils/snapshot-writer.js.map +0 -1
  428. package/dist/tools/replay-request.d.ts +0 -0
  429. package/dist/tools/replay-request.js +0 -2
  430. package/dist/tools/replay-request.js.map +0 -1
  431. package/scripts/check-glm-compat.mjs +0 -47
@@ -266,6 +266,7 @@ export function buildOpenAIChatFromAnthropic(payload) {
266
266
  continue;
267
267
  }
268
268
  const textParts = [];
269
+ const imageBlocks = [];
269
270
  const toolCalls = [];
270
271
  const reasoningParts = [];
271
272
  const toolResults = [];
@@ -284,6 +285,29 @@ export function buildOpenAIChatFromAnthropic(payload) {
284
285
  reasoningParts.push(thinkingText);
285
286
  }
286
287
  }
288
+ else if (t === 'image') {
289
+ const source = block.source;
290
+ if (source && typeof source === 'object') {
291
+ const s = source;
292
+ const srcType = typeof s.type === 'string' ? s.type.toLowerCase() : '';
293
+ let url;
294
+ if (srcType === 'url' && typeof s.url === 'string') {
295
+ url = s.url;
296
+ }
297
+ else if (srcType === 'base64' && typeof s.data === 'string') {
298
+ const mediaType = typeof s.media_type === 'string' && s.media_type.trim().length
299
+ ? s.media_type.trim()
300
+ : 'image/png';
301
+ url = `data:${mediaType};base64,${s.data}`;
302
+ }
303
+ if (url && url.trim().length) {
304
+ imageBlocks.push({
305
+ type: 'image_url',
306
+ image_url: { url: url.trim() }
307
+ });
308
+ }
309
+ }
310
+ }
287
311
  else if (t === 'tool_use') {
288
312
  const name = requireTrimmedString(block.name, 'tool_use.name');
289
313
  const id = requireTrimmedString(block.id, 'tool_use.id');
@@ -310,10 +334,22 @@ export function buildOpenAIChatFromAnthropic(payload) {
310
334
  }
311
335
  const hasText = typeof normalized.contentText === 'string' && normalized.contentText.length > 0;
312
336
  const hasReasoning = mergedReasoning.length > 0;
313
- if (hasText || hasRawText || toolCalls.length > 0 || hasReasoning) {
337
+ if (hasText || hasRawText || toolCalls.length > 0 || hasReasoning || imageBlocks.length > 0) {
338
+ let contentNode = (hasText ? normalized.contentText : undefined) ?? combinedText ?? '';
339
+ if (imageBlocks.length > 0) {
340
+ const blocks = [];
341
+ const textPayload = (hasText ? normalized.contentText : undefined) ?? combinedText ?? '';
342
+ if (typeof textPayload === 'string' && textPayload.trim().length) {
343
+ blocks.push({ type: 'text', text: textPayload.trim() });
344
+ }
345
+ for (const img of imageBlocks) {
346
+ blocks.push(jsonClone(img));
347
+ }
348
+ contentNode = blocks;
349
+ }
314
350
  const msg = {
315
351
  role,
316
- content: (hasText ? normalized.contentText : undefined) ?? combinedText ?? ''
352
+ content: contentNode
317
353
  };
318
354
  if (toolCalls.length)
319
355
  msg.tool_calls = toolCalls;
@@ -336,6 +372,12 @@ export function buildOpenAIChatFromAnthropic(payload) {
336
372
  request.top_p = body.top_p;
337
373
  if (typeof body.stream === 'boolean')
338
374
  request.stream = body.stream;
375
+ if (typeof body.id === 'string') {
376
+ request.request_id = body.id;
377
+ }
378
+ else if (typeof body.request_id === 'string') {
379
+ request.request_id = body.request_id;
380
+ }
339
381
  if ('tool_choice' in body)
340
382
  request.tool_choice = body.tool_choice;
341
383
  const normalizedTools = mapAnthropicToolsToChat(body.tools);
@@ -684,7 +726,8 @@ export function buildAnthropicRequestFromOpenAIChat(chatReq) {
684
726
  targetShape = mirrorShapes[mirrorIndex];
685
727
  mirrorIndex += 1;
686
728
  }
687
- const text = collectText(m.content).trim();
729
+ const contentNode = m.content;
730
+ const text = collectText(contentNode).trim();
688
731
  if (role === 'system') {
689
732
  if (!text) {
690
733
  throw new Error('Anthropic bridge constraint violated: Chat system message must contain text');
@@ -709,6 +752,58 @@ export function buildAnthropicRequestFromOpenAIChat(chatReq) {
709
752
  continue;
710
753
  }
711
754
  const blocks = [];
755
+ if (Array.isArray(contentNode)) {
756
+ // Preserve or synthesize image blocks where possible, and fall back to text for the rest.
757
+ for (const entry of contentNode) {
758
+ if (!entry || typeof entry !== 'object')
759
+ continue;
760
+ const node = entry;
761
+ const t = typeof node.type === 'string' ? node.type.toLowerCase() : '';
762
+ if (t === 'image' && node.source && typeof node.source === 'object') {
763
+ // Pass-through Anthropic image block as-is.
764
+ blocks.push({
765
+ type: 'image',
766
+ source: jsonClone(node.source)
767
+ });
768
+ continue;
769
+ }
770
+ if (t === 'image_url') {
771
+ let url = '';
772
+ const imageUrl = node.image_url;
773
+ if (typeof imageUrl === 'string') {
774
+ url = imageUrl;
775
+ }
776
+ else if (imageUrl && typeof imageUrl === 'object' && typeof imageUrl.url === 'string') {
777
+ url = imageUrl.url;
778
+ }
779
+ const trimmed = url.trim();
780
+ if (!trimmed.length)
781
+ continue;
782
+ const source = {};
783
+ if (trimmed.startsWith('data:')) {
784
+ const match = /^data:([^;,]+)?(?:;base64)?,(.*)$/s.exec(trimmed);
785
+ if (match) {
786
+ const mediaType = (match[1] || '').trim() || 'image/png';
787
+ source.type = 'base64';
788
+ source.media_type = mediaType;
789
+ source.data = match[2] || '';
790
+ }
791
+ else {
792
+ source.type = 'url';
793
+ source.url = trimmed;
794
+ }
795
+ }
796
+ else {
797
+ source.type = 'url';
798
+ source.url = trimmed;
799
+ }
800
+ blocks.push({
801
+ type: 'image',
802
+ source
803
+ });
804
+ }
805
+ }
806
+ }
712
807
  if (text) {
713
808
  blocks.push({ type: 'text', text });
714
809
  }
@@ -66,6 +66,59 @@ function collectText(value) {
66
66
  }
67
67
  return '';
68
68
  }
69
+ function extractImageBlocksFromContent(content) {
70
+ const images = [];
71
+ const visit = (value) => {
72
+ if (!value)
73
+ return;
74
+ if (Array.isArray(value)) {
75
+ for (const entry of value)
76
+ visit(entry);
77
+ return;
78
+ }
79
+ if (typeof value !== 'object') {
80
+ return;
81
+ }
82
+ const record = value;
83
+ const typeValue = typeof record.type === 'string' ? record.type.toLowerCase() : '';
84
+ if (typeValue === 'image' || typeValue === 'image_url' || typeValue === 'input_image') {
85
+ let url = '';
86
+ const imageUrl = record.image_url;
87
+ if (typeof imageUrl === 'string') {
88
+ url = imageUrl;
89
+ }
90
+ else if (imageUrl && typeof imageUrl === 'object' && typeof imageUrl.url === 'string') {
91
+ url = imageUrl.url;
92
+ }
93
+ else if (typeof record.url === 'string') {
94
+ url = record.url;
95
+ }
96
+ else if (typeof record.uri === 'string') {
97
+ url = record.uri;
98
+ }
99
+ else if (typeof record.data === 'string') {
100
+ url = record.data;
101
+ }
102
+ const trimmed = url.trim();
103
+ if (trimmed.length) {
104
+ let detail;
105
+ if (imageUrl && typeof imageUrl === 'object' && typeof imageUrl.detail === 'string') {
106
+ detail = imageUrl.detail.trim() || undefined;
107
+ }
108
+ else if (typeof record.detail === 'string') {
109
+ detail = record.detail.trim() || undefined;
110
+ }
111
+ images.push({ url: trimmed, detail });
112
+ }
113
+ return;
114
+ }
115
+ if (Array.isArray(record.content)) {
116
+ visit(record.content);
117
+ }
118
+ };
119
+ visit(content);
120
+ return images;
121
+ }
69
122
  function extractUserTextFromEntry(entry) {
70
123
  if (!entry || typeof entry !== 'object')
71
124
  return '';
@@ -94,6 +147,7 @@ export function convertMessagesToBridgeInput(options) {
94
147
  const role = coerceBridgeRole(m.role || 'user');
95
148
  const content = m.content;
96
149
  const collectedText = collectText(content);
150
+ const imageBlocks = extractImageBlocksFromContent(content);
97
151
  const text = role === 'system' ? collectedText : collectedText.trim();
98
152
  if (role === 'system') {
99
153
  if (collectedText && collectedText.length) {
@@ -170,13 +224,29 @@ export function convertMessagesToBridgeInput(options) {
170
224
  }
171
225
  continue;
172
226
  }
173
- if (typeof text === 'string') {
227
+ if (typeof text === 'string' || imageBlocks.length) {
174
228
  const tRole = role === 'assistant' ? 'output_text' : 'input_text';
175
- const entry = {
176
- role,
177
- content: [{ type: tRole, text }]
178
- };
179
- input.push(entry);
229
+ const blocks = [];
230
+ if (typeof text === 'string' && text.length) {
231
+ blocks.push({ type: tRole, text });
232
+ }
233
+ for (const img of imageBlocks) {
234
+ const block = {
235
+ type: 'input_image',
236
+ image_url: img.url
237
+ };
238
+ if (img.detail) {
239
+ block.detail = img.detail;
240
+ }
241
+ blocks.push(block);
242
+ }
243
+ if (blocks.length) {
244
+ const entry = {
245
+ role,
246
+ content: blocks
247
+ };
248
+ input.push(entry);
249
+ }
180
250
  if (role === 'user') {
181
251
  const trimmed = typeof text === 'string' ? text.trim() : '';
182
252
  if (trimmed.length) {
@@ -260,6 +330,7 @@ function processMessageBlocks(blocks, normalizeFunctionName, tools, toolNameById
260
330
  const toolMessages = [];
261
331
  let currentLastCall = lastToolCallId;
262
332
  const reasoningSegments = [];
333
+ const images = [];
263
334
  for (const block of blocks) {
264
335
  if (!block || typeof block !== 'object')
265
336
  continue;
@@ -282,6 +353,18 @@ function processMessageBlocks(blocks, normalizeFunctionName, tools, toolNameById
282
353
  toolMessages.push(tm);
283
354
  currentLastCall = nested.lastCallId;
284
355
  reasoningSegments.push(...nested.reasoningSegments);
356
+ if (nested.images.length)
357
+ images.push(...nested.images);
358
+ continue;
359
+ }
360
+ if (type === 'input_image') {
361
+ const url = typeof block.image_url === 'string' ? block.image_url.trim() : '';
362
+ if (url) {
363
+ const detail = typeof block.detail === 'string' && block.detail.trim()
364
+ ? block.detail.trim()
365
+ : undefined;
366
+ images.push({ url, detail });
367
+ }
285
368
  continue;
286
369
  }
287
370
  if (type === 'function_call') {
@@ -344,7 +427,7 @@ function processMessageBlocks(blocks, normalizeFunctionName, tools, toolNameById
344
427
  }
345
428
  }
346
429
  const text = textParts.length ? textParts.join('\n').trim() : null;
347
- return { text, toolCalls, toolMessages, lastCallId: currentLastCall, reasoningSegments };
430
+ return { text, images, toolCalls, toolMessages, lastCallId: currentLastCall, reasoningSegments };
348
431
  }
349
432
  export function convertBridgeInputToChatMessages(options) {
350
433
  const { input, tools, normalizeFunctionName, toolResultFallbackText } = options;
@@ -470,7 +553,29 @@ export function convertBridgeInputToChatMessages(options) {
470
553
  for (const msg of nested.toolMessages)
471
554
  messages.push(msg);
472
555
  const normalizedRole = coerceBridgeRole((explicit.role ?? entry.role) || 'user');
473
- if (typeof nested.text === 'string') {
556
+ if (nested.images.length) {
557
+ const contentBlocks = [];
558
+ if (typeof nested.text === 'string' && nested.text.trim().length) {
559
+ contentBlocks.push({ type: 'text', text: nested.text });
560
+ }
561
+ for (const img of nested.images) {
562
+ const imgBlock = { type: 'image_url', image_url: { url: img.url } };
563
+ if (img.detail) {
564
+ imgBlock.image_url.detail = img.detail;
565
+ }
566
+ contentBlocks.push(imgBlock);
567
+ }
568
+ const msg = {
569
+ role: normalizedRole,
570
+ content: contentBlocks
571
+ };
572
+ const combinedReasoning = combineReasoningSegments(consumeEntryReasoning(), nested.reasoningSegments);
573
+ if (combinedReasoning.length) {
574
+ msg.reasoning_content = combinedReasoning.join('\n');
575
+ }
576
+ messages.push(msg);
577
+ }
578
+ else if (typeof nested.text === 'string') {
474
579
  pushNormalizedChatMessage(messages, normalizedRole, nested.text, {
475
580
  reasoningSegments: combineReasoningSegments(consumeEntryReasoning(), nested.reasoningSegments)
476
581
  });
@@ -491,9 +596,31 @@ export function convertBridgeInputToChatMessages(options) {
491
596
  for (const msg of nested.toolMessages)
492
597
  messages.push(msg);
493
598
  const normalizedRole = coerceBridgeRole(entry.role || 'user');
494
- if (typeof nested.text === 'string') {
599
+ if (nested.images.length) {
600
+ const contentBlocks = [];
601
+ if (typeof nested.text === 'string' && nested.text.trim().length) {
602
+ contentBlocks.push({ type: 'text', text: nested.text });
603
+ }
604
+ for (const img of nested.images) {
605
+ const imgBlock = { type: 'image_url', image_url: { url: img.url } };
606
+ if (img.detail) {
607
+ imgBlock.image_url.detail = img.detail;
608
+ }
609
+ contentBlocks.push(imgBlock);
610
+ }
611
+ const msg = {
612
+ role: normalizedRole,
613
+ content: contentBlocks
614
+ };
615
+ const combinedReasoning = combineReasoningSegments(consumeEntryReasoning(), nested.reasoningSegments);
616
+ if (combinedReasoning.length) {
617
+ msg.reasoning_content = combinedReasoning.join('\n');
618
+ }
619
+ messages.push(msg);
620
+ }
621
+ else if (typeof nested.text === 'string') {
495
622
  pushNormalizedChatMessage(messages, normalizedRole, nested.text, {
496
- reasoningSegments: combineReasoningSegments(consumeEntryReasoning(), nested.reasoningSegments)
623
+ reasoningSegments: consumeEntryReasoning()
497
624
  });
498
625
  }
499
626
  lastToolCallId = nested.lastCallId;
@@ -1,6 +1,41 @@
1
1
  import { normalizeFunctionCallId } from './bridge-id-utils.js';
2
2
  import { normalizeContentPart } from './output-content-normalizer.js';
3
3
  import { expandResponsesMessageItem } from '../../sse/shared/responses-output-normalizer.js';
4
+ function buildToolOutputIndex(response) {
5
+ const ids = new Set();
6
+ try {
7
+ const primary = Array.isArray(response.tool_outputs)
8
+ ? response.tool_outputs
9
+ : [];
10
+ for (const entry of primary) {
11
+ if (!entry || typeof entry !== 'object')
12
+ continue;
13
+ const raw = entry.tool_call_id ||
14
+ entry.call_id ||
15
+ entry.id;
16
+ if (typeof raw === 'string' && raw.trim().length) {
17
+ const trimmed = raw.trim();
18
+ // 记录原始 ID(例如 OpenAI 的 toolu_ 前缀),以兼容直接使用
19
+ // tool_call_id 的客户端;同时记录归一化后的 fc_ 形式,保证与
20
+ // buildFunctionCallOutput 中 normalizeFunctionCallId 的结果对齐。
21
+ ids.add(trimmed);
22
+ try {
23
+ const normalized = normalizeFunctionCallId({ callId: trimmed, fallback: trimmed });
24
+ if (normalized && normalized !== trimmed) {
25
+ ids.add(normalized);
26
+ }
27
+ }
28
+ catch {
29
+ // 归一化失败不应影响主流程
30
+ }
31
+ }
32
+ }
33
+ }
34
+ catch {
35
+ // best-effort: 不因索引构建失败影响主流程
36
+ }
37
+ return ids;
38
+ }
4
39
  function appendReasoningSegments(target, raw) {
5
40
  if (typeof raw !== 'string' || !raw.length) {
6
41
  return;
@@ -91,7 +126,13 @@ export function buildResponsesOutputFromChat(options) {
91
126
  const usage = normalizeUsage(response.usage);
92
127
  const outputTextMeta = response?.__responses_output_text_meta;
93
128
  const outputText = resolveOutputText(convertedContent, outputTextMeta);
94
- const hasNormalizedToolCalls = normalizedToolCalls.length > 0;
129
+ // 如果顶层 tool_outputs 已经为所有 tool_calls 提供了结果,说明这些函数调用
130
+ // 已在服务端(例如 server-side web_search)完成,不应再对客户端暴露
131
+ // required_action/submit_tool_outputs。此时只需返回 completed 状态即可,避免
132
+ // 再触发一轮工具回合。
133
+ const executedIds = buildToolOutputIndex(response);
134
+ const pendingToolCalls = normalizedToolCalls.filter((entry) => !executedIds.has(entry.id));
135
+ const hasNormalizedToolCalls = pendingToolCalls.length > 0;
95
136
  if (hasNormalizedToolCalls) {
96
137
  for (const item of outputItems) {
97
138
  if (item.type === 'message') {
@@ -100,7 +141,7 @@ export function buildResponsesOutputFromChat(options) {
100
141
  }
101
142
  }
102
143
  const requiredAction = hasNormalizedToolCalls
103
- ? buildRequiredActionFromNormalized(normalizedToolCalls)
144
+ ? buildRequiredActionFromNormalized(pendingToolCalls)
104
145
  : undefined;
105
146
  const status = hasNormalizedToolCalls ? 'requires_action' : 'completed';
106
147
  return {
@@ -6,3 +6,7 @@ export declare function registerResponsesReasoning(id: unknown, segments: string
6
6
  export declare function consumeResponsesReasoning(id: unknown): string[] | undefined;
7
7
  export declare function registerResponsesOutputTextMeta(id: unknown, meta: ResponsesOutputTextMeta | undefined): void;
8
8
  export declare function consumeResponsesOutputTextMeta(id: unknown): ResponsesOutputTextMeta | undefined;
9
+ export declare function registerResponsesPayloadSnapshot(id: unknown, snapshot: Record<string, unknown> | undefined): void;
10
+ export declare function consumeResponsesPayloadSnapshot(id: unknown): Record<string, unknown> | undefined;
11
+ export declare function registerResponsesPassthrough(id: unknown, payload: Record<string, unknown> | undefined): void;
12
+ export declare function consumeResponsesPassthrough(id: unknown): Record<string, unknown> | undefined;
@@ -11,10 +11,27 @@ function pruneEntry(id) {
11
11
  const entry = registry.get(id);
12
12
  if (!entry)
13
13
  return;
14
- if (!entry.reasoning && !entry.outputText) {
14
+ if (!entry.reasoning && !entry.outputText && !entry.payloadSnapshot && !entry.passthroughPayload) {
15
15
  registry.delete(id);
16
16
  }
17
17
  }
18
+ function cloneSnapshot(snapshot) {
19
+ try {
20
+ const structuredCloneImpl = globalThis.structuredClone;
21
+ if (typeof structuredCloneImpl === 'function') {
22
+ return structuredCloneImpl(snapshot);
23
+ }
24
+ }
25
+ catch {
26
+ /* ignore structuredClone failures */
27
+ }
28
+ try {
29
+ return JSON.parse(JSON.stringify(snapshot));
30
+ }
31
+ catch {
32
+ return undefined;
33
+ }
34
+ }
18
35
  export function registerResponsesReasoning(id, segments) {
19
36
  if (typeof id !== 'string')
20
37
  return;
@@ -59,3 +76,47 @@ export function consumeResponsesOutputTextMeta(id) {
59
76
  pruneEntry(id);
60
77
  return value;
61
78
  }
79
+ export function registerResponsesPayloadSnapshot(id, snapshot) {
80
+ if (typeof id !== 'string')
81
+ return;
82
+ if (!snapshot || typeof snapshot !== 'object')
83
+ return;
84
+ const clone = cloneSnapshot(snapshot);
85
+ if (!clone)
86
+ return;
87
+ const entry = ensureEntry(id);
88
+ entry.payloadSnapshot = clone;
89
+ }
90
+ export function consumeResponsesPayloadSnapshot(id) {
91
+ if (typeof id !== 'string')
92
+ return undefined;
93
+ const entry = registry.get(id);
94
+ if (!entry?.payloadSnapshot)
95
+ return undefined;
96
+ const clone = cloneSnapshot(entry.payloadSnapshot) ?? entry.payloadSnapshot;
97
+ entry.payloadSnapshot = undefined;
98
+ pruneEntry(id);
99
+ return clone;
100
+ }
101
+ export function registerResponsesPassthrough(id, payload) {
102
+ if (typeof id !== 'string')
103
+ return;
104
+ if (!payload || typeof payload !== 'object')
105
+ return;
106
+ const clone = cloneSnapshot(payload);
107
+ if (!clone)
108
+ return;
109
+ const entry = ensureEntry(id);
110
+ entry.passthroughPayload = clone;
111
+ }
112
+ export function consumeResponsesPassthrough(id) {
113
+ if (typeof id !== 'string')
114
+ return undefined;
115
+ const entry = registry.get(id);
116
+ if (!entry?.passthroughPayload)
117
+ return undefined;
118
+ const clone = cloneSnapshot(entry.passthroughPayload) ?? entry.passthroughPayload;
119
+ entry.passthroughPayload = undefined;
120
+ pruneEntry(id);
121
+ return clone;
122
+ }
@@ -4,6 +4,7 @@ import { extractOutputSegments } from './output-content-normalizer.js';
4
4
  import { sanitizeReasoningTaggedText } from './reasoning-utils.js';
5
5
  import { createBridgeActionState, runBridgeActionPipeline } from './bridge-actions.js';
6
6
  import { resolveBridgePolicy, resolvePolicyActions } from './bridge-policies.js';
7
+ import { registerResponsesPayloadSnapshot, registerResponsesPassthrough } from './responses-reasoning-registry.js';
7
8
  function selectCallId(entry) {
8
9
  const candidates = [
9
10
  entry?.call_id,
@@ -153,13 +154,27 @@ function collectRawReasoningSegments(response) {
153
154
  }
154
155
  return segments;
155
156
  }
157
+ function registerPassthroughSnapshot(payload) {
158
+ const ids = new Set();
159
+ const requestId = typeof payload?.request_id === 'string' ? payload.request_id.trim() : '';
160
+ const id = typeof payload?.id === 'string' ? payload.id.trim() : '';
161
+ if (requestId.length)
162
+ ids.add(requestId);
163
+ if (id.length)
164
+ ids.add(id);
165
+ for (const candidate of ids) {
166
+ registerResponsesPassthrough(candidate, payload);
167
+ }
168
+ }
156
169
  export function buildChatResponseFromResponses(payload) {
157
170
  if (!payload || typeof payload !== 'object')
158
171
  return payload;
159
172
  const response = unwrapResponsesResponse(payload);
160
173
  if (!response) {
161
- if (Array.isArray(payload.choices))
174
+ if (Array.isArray(payload.choices)) {
175
+ registerPassthroughSnapshot(payload);
162
176
  return payload;
177
+ }
163
178
  return payload;
164
179
  }
165
180
  const id = typeof response.id === 'string' ? response.id : `resp_${Date.now()}`;
@@ -235,5 +250,12 @@ export function buildChatResponseFromResponses(payload) {
235
250
  if (usage !== undefined) {
236
251
  chat.usage = usage;
237
252
  }
253
+ const requestId = typeof response.request_id === 'string'
254
+ ? response.request_id
255
+ : (typeof response.id === 'string' ? response.id : undefined);
256
+ if (requestId) {
257
+ chat.request_id = requestId;
258
+ }
259
+ registerResponsesPayloadSnapshot(id, response);
238
260
  return chat;
239
261
  }
@@ -1,35 +1,25 @@
1
- import os from 'node:os';
2
- import path from 'node:path';
3
- import fs from 'node:fs/promises';
4
1
  import { writeSnapshotViaHooks } from './snapshot-hooks.js';
5
- const SNAPSHOT_BASE = path.join(os.homedir(), '.routecodex', 'golden_samples');
6
- function mapEndpointToFolder(endpoint, hint) {
7
- if (hint)
8
- return hint;
9
- const ep = String(endpoint || '').toLowerCase();
10
- if (ep.includes('/responses'))
11
- return 'openai-responses';
12
- if (ep.includes('/messages'))
13
- return 'anthropic-messages';
14
- if (ep.includes('/gemini'))
15
- return 'gemini-chat';
16
- return 'openai-chat';
17
- }
18
- async function ensureDir(dir) {
19
- try {
20
- await fs.mkdir(dir, { recursive: true });
2
+ function resolveBoolFromEnv(value, fallback) {
3
+ if (!value) {
4
+ return fallback;
21
5
  }
22
- catch {
23
- // ignore fs errors
6
+ const normalized = value.trim().toLowerCase();
7
+ if (['1', 'true', 'yes', 'on'].includes(normalized)) {
8
+ return true;
24
9
  }
25
- }
26
- function sanitize(value) {
27
- return value.replace(/[^\w.-]/g, '_');
10
+ if (['0', 'false', 'no', 'off'].includes(normalized)) {
11
+ return false;
12
+ }
13
+ return fallback;
28
14
  }
29
15
  export function shouldRecordSnapshots() {
30
- const flag = process.env.ROUTECODEX_HUB_SNAPSHOTS;
31
- if (flag && flag.trim() === '0') {
32
- return false;
16
+ const hubFlag = process.env.ROUTECODEX_HUB_SNAPSHOTS;
17
+ if (hubFlag && hubFlag.trim().length) {
18
+ return resolveBoolFromEnv(hubFlag, true);
19
+ }
20
+ const sharedFlag = process.env.ROUTECODEX_SNAPSHOT ?? process.env.ROUTECODEX_SNAPSHOTS;
21
+ if (sharedFlag && sharedFlag.trim().length) {
22
+ return resolveBoolFromEnv(sharedFlag, true);
33
23
  }
34
24
  return true;
35
25
  }
@@ -37,26 +27,6 @@ export async function recordSnapshot(options) {
37
27
  if (!shouldRecordSnapshots())
38
28
  return;
39
29
  const endpoint = options.endpoint || '/v1/chat/completions';
40
- const folder = mapEndpointToFolder(endpoint, options.folderHint);
41
- const dir = path.join(SNAPSHOT_BASE, folder);
42
- try {
43
- await ensureDir(dir);
44
- const safeStage = sanitize(options.stage);
45
- const safeRequestId = sanitize(options.requestId);
46
- const file = path.join(dir, `${safeRequestId}_${safeStage}.json`);
47
- const payload = {
48
- meta: {
49
- stage: options.stage,
50
- timestamp: Date.now(),
51
- endpoint
52
- },
53
- body: options.data
54
- };
55
- await fs.writeFile(file, JSON.stringify(payload, null, 2), 'utf-8');
56
- }
57
- catch (error) {
58
- console.warn('[snapshot-utils] failed to write snapshot', error);
59
- }
60
30
  void writeSnapshotViaHooks({
61
31
  endpoint,
62
32
  stage: options.stage,
@@ -0,0 +1,2 @@
1
+ export declare function canonicalizeChatResponseTools(payload: unknown): unknown;
2
+ export default canonicalizeChatResponseTools;
@@ -1,5 +1,6 @@
1
1
  import { FilterEngine } from '../../filters/index.js';
2
2
  import { loadFieldMapConfig } from '../../filters/utils/fieldmap-loader.js';
3
+ import { normalizeChatResponseReasoningTools } from './reasoning-tool-normalizer.js';
3
4
  import { createSnapshotWriter } from './snapshot-utils.js';
4
5
  const REQUEST_FILTER_STAGES = [
5
6
  'request_pre',
@@ -110,6 +111,7 @@ function applyLocalToolGovernance(chatRequest, rawPayload) {
110
111
  }
111
112
  const hasImageHint = detectImageHint(messages, rawPayload);
112
113
  if (hasImageHint) {
114
+ // 有图片线索时不干预工具列表,保持由上游(Codex 等)决定 view_image 的暴露与使用。
113
115
  return chatRequest;
114
116
  }
115
117
  const filteredTools = tools.filter((tool) => {
@@ -191,6 +193,16 @@ export async function runChatResponseToolFilters(chatJson, options = {}) {
191
193
  snapshot(stage, payload);
192
194
  };
193
195
  recordStage('resp_process_tool_filters_input', chatJson);
196
+ try {
197
+ if (chatJson && typeof chatJson === 'object') {
198
+ normalizeChatResponseReasoningTools(chatJson, {
199
+ idPrefixBase: 'reasoning_choice'
200
+ });
201
+ }
202
+ }
203
+ catch {
204
+ // best-effort; do not block response flow on reasoning parsing issues
205
+ }
194
206
  const engine = new FilterEngine();
195
207
  const registeredStages = new Set();
196
208
  const register = (filter) => {