@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
@@ -1,4 +1,11 @@
1
1
  import type { JsonObject, JsonValue } from '../../types/json.js';
2
+ import type { FilterConfig as ShapeFilterConfig } from '../../../compat/actions/universal-shape-filter.js';
3
+ import type { ResponseBlacklistConfig } from '../../../compat/actions/response-blacklist.js';
4
+ import type { FieldMapping } from '../../../compat/actions/field-mapping.js';
5
+ import type { RequestRulesConfig } from '../../../compat/actions/request-rules.js';
6
+ import type { AutoThinkingConfig } from '../../../compat/actions/auto-thinking.js';
7
+ import type { ResponseNormalizeConfig } from '../../../compat/actions/response-normalize.js';
8
+ import type { ResponseValidateConfig } from '../../../compat/actions/response-validate.js';
2
9
  export type CompatDirection = 'request' | 'response';
3
10
  export interface CompatProfileConfig {
4
11
  id: string;
@@ -51,6 +58,54 @@ export type MappingInstruction = {
51
58
  fallback?: JsonValue;
52
59
  } | {
53
60
  action: 'convert_responses_output_to_choices';
61
+ } | {
62
+ action: 'extract_glm_tool_markup';
63
+ } | {
64
+ action: 'dto_unwrap';
65
+ } | {
66
+ action: 'dto_rewrap';
67
+ } | {
68
+ action: 'shape_filter';
69
+ config: ShapeFilterConfig;
70
+ target?: CompatDirection;
71
+ } | {
72
+ action: 'field_map';
73
+ direction?: 'incoming' | 'outgoing';
74
+ config: FieldMapping[];
75
+ } | {
76
+ action: 'tool_schema_sanitize';
77
+ mode?: 'glm_shell';
78
+ } | {
79
+ action: 'apply_rules';
80
+ config: RequestRulesConfig;
81
+ } | {
82
+ action: 'auto_thinking';
83
+ config: AutoThinkingConfig;
84
+ } | {
85
+ action: 'snapshot';
86
+ phase: 'compat-pre' | 'compat-post';
87
+ channel?: string;
88
+ } | {
89
+ action: 'resp_blacklist';
90
+ config: ResponseBlacklistConfig;
91
+ } | {
92
+ action: 'response_normalize';
93
+ config?: ResponseNormalizeConfig;
94
+ } | {
95
+ action: 'response_validate';
96
+ config?: ResponseValidateConfig;
97
+ } | {
98
+ action: 'qwen_request_transform';
99
+ } | {
100
+ action: 'qwen_response_transform';
101
+ } | {
102
+ action: 'glm_web_search_request';
103
+ } | {
104
+ action: 'glm_image_content';
105
+ } | {
106
+ action: 'glm_vision_prompt';
107
+ } | {
108
+ action: 'gemini_web_search_request';
54
109
  };
55
110
  export type FilterInstruction = {
56
111
  action: 'rate_limit_text';
@@ -64,5 +64,7 @@ export declare class HubPipeline {
64
64
  private convertSsePayload;
65
65
  private resolveSseProtocol;
66
66
  private extractModelHint;
67
+ private resolveOutboundStreamIntent;
68
+ private applyOutboundStreamPreference;
67
69
  }
68
70
  export {};
@@ -11,6 +11,7 @@ import { GeminiSemanticMapper } from '../semantic-mappers/gemini-mapper.js';
11
11
  import { ChatFormatAdapter } from '../format-adapters/chat-format-adapter.js';
12
12
  import { ChatSemanticMapper } from '../semantic-mappers/chat-mapper.js';
13
13
  import { createSnapshotRecorder } from '../snapshot-recorder.js';
14
+ import { shouldRecordSnapshots } from '../../shared/snapshot-utils.js';
14
15
  import { runReqInboundStage1FormatParse } from './stages/req_inbound/req_inbound_stage1_format_parse/index.js';
15
16
  import { runReqInboundStage2SemanticMap } from './stages/req_inbound/req_inbound_stage2_semantic_map/index.js';
16
17
  import { runChatContextCapture, captureResponsesContextSnapshot } from './stages/req_inbound/req_inbound_stage3_context_capture/index.js';
@@ -93,10 +94,18 @@ export class HubPipeline {
93
94
  });
94
95
  let processedRequest;
95
96
  if (normalized.processMode !== 'passthrough') {
97
+ const processMetadata = {
98
+ ...(normalized.metadata ?? {})
99
+ };
100
+ const webSearchConfig = this.config.virtualRouter?.webSearch;
101
+ if (webSearchConfig) {
102
+ processMetadata.webSearch = webSearchConfig;
103
+ }
104
+ normalized.metadata = processMetadata;
96
105
  const processResult = await runReqProcessStage1ToolGovernance({
97
106
  request: standardizedRequest,
98
107
  rawPayload: rawRequest,
99
- metadata: normalized.metadata,
108
+ metadata: processMetadata,
100
109
  entryEndpoint: normalized.entryEndpoint,
101
110
  requestId: normalized.id,
102
111
  stageRecorder: inboundRecorder
@@ -111,6 +120,9 @@ export class HubPipeline {
111
120
  const responsesResume = normalizedMeta && typeof normalizedMeta.responsesResume === 'object'
112
121
  ? normalizedMeta.responsesResume
113
122
  : undefined;
123
+ const stdMetadata = workingRequest?.metadata;
124
+ const serverToolRequired = stdMetadata?.webSearchEnabled === true ||
125
+ stdMetadata?.serverToolRequired === true;
114
126
  const metadataInput = {
115
127
  requestId: normalized.id,
116
128
  entryEndpoint: normalized.entryEndpoint,
@@ -120,7 +132,8 @@ export class HubPipeline {
120
132
  providerProtocol: normalized.providerProtocol,
121
133
  routeHint: normalized.routeHint,
122
134
  stage: normalized.stage,
123
- responsesResume: responsesResume
135
+ responsesResume: responsesResume,
136
+ ...(serverToolRequired ? { serverToolRequired: true } : {})
124
137
  };
125
138
  const routing = runReqProcessStage2RouteSelect({
126
139
  routerEngine: this.routerEngine,
@@ -142,6 +155,8 @@ export class HubPipeline {
142
155
  catch {
143
156
  // logging must not break routing
144
157
  }
158
+ const outboundStream = this.resolveOutboundStreamIntent(routing.target?.streaming);
159
+ this.applyOutboundStreamPreference(workingRequest, outboundStream);
145
160
  const outboundAdapterContext = this.buildAdapterContext(normalized, routing.target);
146
161
  if (routing.target?.compatibilityProfile) {
147
162
  outboundAdapterContext.compatibilityProfile = routing.target.compatibilityProfile;
@@ -219,14 +234,32 @@ export class HubPipeline {
219
234
  }
220
235
  });
221
236
  }
237
+ // 为响应侧 servertool/web_search 提供一次性 Chat 请求快照,便于在 Hub 内部实现
238
+ // 第三跳(将工具结果注入消息历史后重新调用主模型)。
239
+ let capturedChatRequest;
240
+ if (normalized.processMode !== 'passthrough') {
241
+ try {
242
+ capturedChatRequest = JSON.parse(JSON.stringify({
243
+ model: workingRequest.model,
244
+ messages: workingRequest.messages,
245
+ tools: workingRequest.tools,
246
+ parameters: workingRequest.parameters
247
+ }));
248
+ }
249
+ catch {
250
+ capturedChatRequest = undefined;
251
+ }
252
+ }
222
253
  const metadata = {
223
254
  ...normalized.metadata,
255
+ ...(capturedChatRequest ? { capturedChatRequest } : {}),
224
256
  entryEndpoint: normalized.entryEndpoint,
225
257
  providerProtocol: outboundProtocol,
226
258
  stream: normalized.stream,
227
259
  processMode: normalized.processMode,
228
260
  routeHint: normalized.routeHint,
229
- target: routing.target
261
+ target: routing.target,
262
+ ...(typeof outboundStream === 'boolean' ? { providerStream: outboundStream } : {})
230
263
  };
231
264
  return {
232
265
  requestId: normalized.id,
@@ -339,14 +372,19 @@ export class HubPipeline {
339
372
  if (typeof metadata.assignedModelId === 'string') {
340
373
  adapterContext.modelId = metadata.assignedModelId;
341
374
  }
375
+ // 将 serverToolFollowup 等 ServerTool 相关标记从 normalized.metadata 透传到 AdapterContext,
376
+ // 便于响应侧的 convertProviderResponse 正确识别“二跳/内部跳转”并跳过 servertool 编排。
377
+ if (Object.prototype.hasOwnProperty.call(metadata, 'serverToolFollowup')) {
378
+ adapterContext.serverToolFollowup = metadata
379
+ .serverToolFollowup;
380
+ }
342
381
  if (target?.compatibilityProfile && typeof target.compatibilityProfile === 'string') {
343
382
  adapterContext.compatibilityProfile = target.compatibilityProfile;
344
383
  }
345
384
  return adapterContext;
346
385
  }
347
386
  maybeCreateStageRecorder(context, endpoint) {
348
- const flag = (process.env.ROUTECODEX_HUB_SNAPSHOTS || '').trim();
349
- if (flag === '0') {
387
+ if (!shouldRecordSnapshots()) {
350
388
  return undefined;
351
389
  }
352
390
  const effectiveEndpoint = endpoint || context.entryEndpoint || '/v1/chat/completions';
@@ -508,6 +546,37 @@ export class HubPipeline {
508
546
  }
509
547
  return undefined;
510
548
  }
549
+ resolveOutboundStreamIntent(providerPreference) {
550
+ if (providerPreference === 'always') {
551
+ return true;
552
+ }
553
+ if (providerPreference === 'never') {
554
+ return false;
555
+ }
556
+ return undefined;
557
+ }
558
+ applyOutboundStreamPreference(request, stream) {
559
+ if (!request || typeof request !== 'object') {
560
+ return;
561
+ }
562
+ const parameters = request.parameters || {};
563
+ const nextParameters = { ...parameters };
564
+ if (typeof stream === 'boolean') {
565
+ nextParameters.stream = stream;
566
+ }
567
+ else if ('stream' in nextParameters) {
568
+ delete nextParameters.stream;
569
+ }
570
+ request.parameters = nextParameters;
571
+ if (request.metadata && typeof request.metadata === 'object') {
572
+ if (typeof stream === 'boolean') {
573
+ request.metadata.outboundStream = stream;
574
+ }
575
+ else if ('outboundStream' in request.metadata) {
576
+ delete request.metadata.outboundStream;
577
+ }
578
+ }
579
+ }
511
580
  }
512
581
  function normalizeToolCallIdStyleCandidate(value) {
513
582
  if (typeof value !== 'string') {
@@ -5,7 +5,7 @@ function pickCompatProfile(adapterContext) {
5
5
  }
6
6
  export async function runReqOutboundStage3Compat(options) {
7
7
  const profile = pickCompatProfile(options.adapterContext);
8
- const result = applyRequestCompat(profile, options.payload);
8
+ const result = applyRequestCompat(profile, options.payload, { adapterContext: options.adapterContext });
9
9
  options.stageRecorder?.record('req_outbound_stage3_compat', {
10
10
  applied: Boolean(result.appliedProfile),
11
11
  profile: result.appliedProfile || profile || 'passthrough'
@@ -14,7 +14,7 @@ export async function runReqOutboundStage3Compat(options) {
14
14
  }
15
15
  export function runRespInboundStageCompatResponse(options) {
16
16
  const profile = pickCompatProfile(options.adapterContext);
17
- const result = applyResponseCompat(profile, options.payload);
17
+ const result = applyResponseCompat(profile, options.payload, { adapterContext: options.adapterContext });
18
18
  options.stageRecorder?.record('resp_inbound_stage_compat', {
19
19
  applied: Boolean(result.appliedProfile),
20
20
  profile: result.appliedProfile || profile || 'passthrough'
@@ -9,9 +9,18 @@ export function applyTargetMetadata(metadata, target, routeName, originalModel)
9
9
  metadata.providerType = target.providerType;
10
10
  metadata.modelId = target.modelId;
11
11
  metadata.processMode = target.processMode || 'chat';
12
+ if (target.forceWebSearch === true) {
13
+ metadata.forceWebSearch = true;
14
+ }
15
+ if (target.forceVision === true) {
16
+ metadata.forceVision = true;
17
+ }
12
18
  if (target.responsesConfig?.toolCallIdStyle) {
13
19
  metadata.toolCallIdStyle = target.responsesConfig.toolCallIdStyle;
14
20
  }
21
+ if (target.streaming) {
22
+ metadata.targetStreaming = target.streaming;
23
+ }
15
24
  if (originalModel && typeof originalModel === 'string' && originalModel.trim()) {
16
25
  const trimmed = originalModel.trim();
17
26
  if (typeof metadata.originalModelId !== 'string' || !metadata.originalModelId) {
@@ -1,5 +1,6 @@
1
1
  import { runChatRequestToolFilters } from '../../shared/tool-filter-pipeline.js';
2
2
  import { ToolGovernanceEngine } from '../tool-governance/index.js';
3
+ import { detectLastAssistantToolCategory } from '../../../router/virtual-router/tool-signals.js';
3
4
  const toolGovernanceEngine = new ToolGovernanceEngine();
4
5
  export async function runHubChatProcess(options) {
5
6
  const startTime = Date.now();
@@ -51,7 +52,7 @@ async function applyRequestToolGovernance(request, context) {
51
52
  });
52
53
  const governed = normalizeRecord(governedPayload);
53
54
  const providerStreamIntent = typeof governed.stream === 'boolean' ? governed.stream : undefined;
54
- const merged = {
55
+ let merged = {
55
56
  ...request,
56
57
  messages: Array.isArray(governed.messages)
57
58
  ? governed.messages
@@ -71,6 +72,14 @@ async function applyRequestToolGovernance(request, context) {
71
72
  governanceTimestamp: Date.now()
72
73
  }
73
74
  };
75
+ if (containsImageAttachment(merged.messages)) {
76
+ if (!merged.metadata) {
77
+ merged.metadata = {
78
+ originalEndpoint: request.metadata?.originalEndpoint ?? '/v1/chat/completions'
79
+ };
80
+ }
81
+ merged.metadata.hasImageAttachment = true;
82
+ }
74
83
  if (typeof inboundStreamIntent === 'boolean') {
75
84
  merged.metadata = {
76
85
  ...merged.metadata,
@@ -92,6 +101,8 @@ async function applyRequestToolGovernance(request, context) {
92
101
  if (typeof governed.model === 'string' && governed.model.trim()) {
93
102
  merged.model = governed.model.trim();
94
103
  }
104
+ // Server-side web_search tool injection (config-driven, best-effort).
105
+ merged = maybeInjectWebSearchTool(merged, metadata);
95
106
  const { request: sanitized, summary } = toolGovernanceEngine.governRequest(merged, providerProtocol);
96
107
  if (summary.applied) {
97
108
  sanitized.metadata = {
@@ -194,6 +205,34 @@ function castSingleTool(tool) {
194
205
  }
195
206
  };
196
207
  }
208
+ function containsImageAttachment(messages) {
209
+ if (!Array.isArray(messages)) {
210
+ return false;
211
+ }
212
+ for (const message of messages) {
213
+ if (!message || typeof message !== 'object') {
214
+ continue;
215
+ }
216
+ const content = message.content;
217
+ if (!Array.isArray(content)) {
218
+ continue;
219
+ }
220
+ for (const part of content) {
221
+ if (!part || typeof part !== 'object') {
222
+ continue;
223
+ }
224
+ const typeValue = part.type;
225
+ if (typeof typeValue !== 'string') {
226
+ continue;
227
+ }
228
+ const normalized = typeValue.toLowerCase();
229
+ if (normalized.includes('image')) {
230
+ return true;
231
+ }
232
+ }
233
+ }
234
+ return false;
235
+ }
197
236
  function castCustomTool(tool) {
198
237
  if (!isRecord(tool)) {
199
238
  return null;
@@ -274,3 +313,176 @@ function readToolChoice(value) {
274
313
  function isRecord(value) {
275
314
  return !!value && typeof value === 'object' && !Array.isArray(value);
276
315
  }
316
+ function maybeInjectWebSearchTool(request, metadata) {
317
+ // ServerTool 二/三跳(serverToolFollowup=true)不再注入 web_search 工具,
318
+ // 以避免在 web_search 流程内部形成循环命中。
319
+ if (metadata.serverToolFollowup === true) {
320
+ return request;
321
+ }
322
+ const rawConfig = metadata.webSearch;
323
+ if (!rawConfig || !Array.isArray(rawConfig.engines) || rawConfig.engines.length === 0) {
324
+ return request;
325
+ }
326
+ const injectPolicy = rawConfig.injectPolicy === 'always' || rawConfig.injectPolicy === 'selective'
327
+ ? rawConfig.injectPolicy
328
+ : 'selective';
329
+ if (injectPolicy === 'selective') {
330
+ const hasExplicitIntent = detectWebSearchIntent(request);
331
+ if (!hasExplicitIntent) {
332
+ // 当最近一条用户消息没有明显的“联网搜索”关键词时,
333
+ // 如果上一轮 assistant 的工具调用已经属于搜索类(如 web_search),
334
+ // 则仍然视为 web_search 续写场景,强制注入 web_search 工具,
335
+ // 以便在后续路由中按 servertool 逻辑跳过不适配的 Provider(例如 serverToolsDisabled 的 crs)。
336
+ const assistantMessages = Array.isArray(request.messages)
337
+ ? request.messages.filter((msg) => msg && msg.role === 'assistant')
338
+ : [];
339
+ const lastTool = detectLastAssistantToolCategory(assistantMessages);
340
+ const hasSearchToolContext = lastTool?.category === 'search';
341
+ if (!hasSearchToolContext) {
342
+ return request;
343
+ }
344
+ }
345
+ }
346
+ const existingTools = Array.isArray(request.tools) ? request.tools : [];
347
+ const hasWebSearch = existingTools.some((tool) => {
348
+ if (!tool || typeof tool !== 'object')
349
+ return false;
350
+ const fn = tool.function;
351
+ return typeof fn?.name === 'string' && fn.name.trim() === 'web_search';
352
+ });
353
+ if (hasWebSearch) {
354
+ return request;
355
+ }
356
+ const engines = rawConfig.engines.filter((engine) => typeof engine?.id === 'string' && !!engine.id.trim() && !engine.serverToolsDisabled);
357
+ if (!engines.length) {
358
+ return request;
359
+ }
360
+ const engineIds = engines.map((engine) => engine.id.trim());
361
+ const engineDescriptions = engines
362
+ .map((engine) => {
363
+ const id = engine.id.trim();
364
+ const desc = typeof engine.description === 'string' && engine.description.trim()
365
+ ? engine.description.trim()
366
+ : '';
367
+ return desc ? `${id}: ${desc}` : id;
368
+ })
369
+ .join('; ');
370
+ const parameters = {
371
+ type: 'object',
372
+ properties: {
373
+ engine: {
374
+ type: 'string',
375
+ enum: engineIds,
376
+ description: engineDescriptions
377
+ },
378
+ query: {
379
+ type: 'string',
380
+ description: 'Search query or user question.'
381
+ },
382
+ recency: {
383
+ type: 'string',
384
+ enum: ['oneDay', 'oneWeek', 'oneMonth', 'oneYear', 'noLimit'],
385
+ description: 'Optional recency filter for web search results.'
386
+ },
387
+ count: {
388
+ type: 'integer',
389
+ minimum: 1,
390
+ maximum: 50,
391
+ description: 'Number of results to retrieve.'
392
+ }
393
+ },
394
+ // 对于 Responses 内建 web_search,required 需要覆盖 properties 中的所有字段,
395
+ // 否则上游会报 "required is required to be supplied and to be an array including every key in properties"。
396
+ required: ['engine', 'query', 'recency', 'count'],
397
+ additionalProperties: false
398
+ };
399
+ const webSearchTool = {
400
+ type: 'function',
401
+ function: {
402
+ name: 'web_search',
403
+ description: 'Perform web search using configured search engines. Use this when the user asks for up-to-date information or news.',
404
+ parameters,
405
+ strict: true
406
+ }
407
+ };
408
+ const nextMetadata = {
409
+ ...(request.metadata ?? {}),
410
+ webSearchEnabled: true
411
+ };
412
+ return {
413
+ ...request,
414
+ metadata: nextMetadata,
415
+ tools: [...existingTools, webSearchTool]
416
+ };
417
+ }
418
+ function detectWebSearchIntent(request) {
419
+ const messages = Array.isArray(request.messages) ? request.messages : [];
420
+ if (!messages.length) {
421
+ return false;
422
+ }
423
+ // 从末尾向前找到最近一条 user 消息,忽略 tool / assistant 的工具调用轮次,
424
+ // 以便在 Responses / 多轮工具调用场景下仍然根据“最近一条用户输入”判断意图。
425
+ let lastUser;
426
+ for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
427
+ const candidate = messages[idx];
428
+ if (candidate && candidate.role === 'user') {
429
+ lastUser = candidate;
430
+ break;
431
+ }
432
+ }
433
+ if (!lastUser) {
434
+ return false;
435
+ }
436
+ // 支持多模态 content:既可能是纯文本字符串,也可能是带 image_url 的分段数组。
437
+ let content = '';
438
+ if (typeof lastUser.content === 'string') {
439
+ content = lastUser.content;
440
+ }
441
+ else if (Array.isArray(lastUser.content)) {
442
+ const parts = lastUser.content;
443
+ const texts = [];
444
+ for (const part of parts) {
445
+ if (typeof part === 'string') {
446
+ texts.push(part);
447
+ }
448
+ else if (part && typeof part === 'object') {
449
+ const maybeText = part.text;
450
+ if (typeof maybeText === 'string' && maybeText.trim()) {
451
+ texts.push(maybeText);
452
+ }
453
+ }
454
+ }
455
+ content = texts.join('\n');
456
+ }
457
+ if (!content) {
458
+ return false;
459
+ }
460
+ const text = content.toLowerCase();
461
+ const keywords = [
462
+ // English
463
+ 'web search',
464
+ 'web_search',
465
+ 'websearch',
466
+ 'internet search',
467
+ 'search the web',
468
+ 'online search',
469
+ 'search online',
470
+ 'search on the internet',
471
+ 'search the internet',
472
+ 'web-search',
473
+ 'online-search',
474
+ 'internet-search',
475
+ // Chinese
476
+ '联网搜索',
477
+ '网络搜索',
478
+ '上网搜索',
479
+ '网上搜索',
480
+ '网上查',
481
+ '网上查找',
482
+ '上网查',
483
+ '上网搜',
484
+ // Command-style
485
+ '/search'
486
+ ];
487
+ return keywords.some((keyword) => text.includes(keyword.toLowerCase()));
488
+ }
@@ -0,0 +1,34 @@
1
+ import { Readable } from 'node:stream';
2
+ import type { AdapterContext } from '../types/chat-envelope.js';
3
+ import type { JsonObject } from '../types/json.js';
4
+ import type { StageRecorder } from '../format-adapters/index.js';
5
+ import type { ProviderInvoker } from '../../../servertool/types.js';
6
+ type ProviderProtocol = 'openai-chat' | 'openai-responses' | 'anthropic-messages' | 'gemini-chat';
7
+ export interface ProviderResponseConversionOptions {
8
+ providerProtocol: ProviderProtocol;
9
+ providerResponse: JsonObject;
10
+ context: AdapterContext;
11
+ entryEndpoint: string;
12
+ wantsStream: boolean;
13
+ stageRecorder?: StageRecorder;
14
+ providerInvoker?: ProviderInvoker;
15
+ /**
16
+ * 可选:由 Host 注入的二次请求入口。Server-side 工具在需要发起
17
+ * followup 请求(例如 web_search 二跳)时,可以通过该回调将构造
18
+ * 好的请求体交给 Host,由 Host 走完整 HubPipeline + VirtualRouter
19
+ * 再返回最终客户端响应形状。
20
+ */
21
+ reenterPipeline?: (options: {
22
+ entryEndpoint: string;
23
+ requestId: string;
24
+ body: JsonObject;
25
+ metadata?: JsonObject;
26
+ }) => Promise<ProviderResponseConversionResult>;
27
+ }
28
+ export interface ProviderResponseConversionResult {
29
+ body?: JsonObject;
30
+ __sse_responses?: Readable;
31
+ format?: string;
32
+ }
33
+ export declare function convertProviderResponse(options: ProviderResponseConversionOptions): Promise<ProviderResponseConversionResult>;
34
+ export {};