@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
@@ -0,0 +1,638 @@
1
+ import { buildOpenAIChatFromGeminiResponse } from '../../conversion/codecs/gemini-openai-codec.js';
2
+ import { registerServerToolHandler } from '../registry.js';
3
+ import { cloneJson, extractTextFromChatLike } from '../server-side-tools.js';
4
+ const FLOW_ID = 'web_search_flow';
5
+ const handler = async (ctx) => {
6
+ const toolCall = ctx.toolCall;
7
+ if (!toolCall) {
8
+ return null;
9
+ }
10
+ if (!ctx.options.providerInvoker && !ctx.options.reenterPipeline) {
11
+ return null;
12
+ }
13
+ const webSearchConfig = getWebSearchConfig(ctx.adapterContext);
14
+ const hasConfig = !!webSearchConfig && Array.isArray(webSearchConfig.engines) && webSearchConfig.engines.length > 0;
15
+ const forceMode = webSearchConfig?.force === true;
16
+ const envEnabled = resolveEnvServerSideToolsEnabled();
17
+ if (!hasConfig && !forceMode && !envEnabled) {
18
+ return null;
19
+ }
20
+ const parsedArgs = parseToolArguments(toolCall);
21
+ const query = typeof parsedArgs.query === 'string' && parsedArgs.query.trim() ? parsedArgs.query.trim() : undefined;
22
+ if (!query) {
23
+ return null;
24
+ }
25
+ const engines = webSearchConfig ? buildEnginePriorityList(webSearchConfig, parsedArgs.engine) : [];
26
+ if (!engines.length) {
27
+ return null;
28
+ }
29
+ const resultCount = normalizeResultCount(parsedArgs.count);
30
+ let chosenEngine;
31
+ let chosenResult;
32
+ let lastFailure;
33
+ for (const engine of engines) {
34
+ const backendResult = await executeWebSearchBackend({
35
+ ctx,
36
+ engine,
37
+ query,
38
+ recency: parsedArgs.recency,
39
+ resultCount
40
+ });
41
+ if (backendResult.ok) {
42
+ chosenEngine = engine;
43
+ chosenResult = backendResult;
44
+ break;
45
+ }
46
+ lastFailure = { engine, result: backendResult };
47
+ }
48
+ if (!chosenEngine || !chosenResult) {
49
+ if (!lastFailure) {
50
+ return null;
51
+ }
52
+ chosenEngine = lastFailure.engine;
53
+ chosenResult = lastFailure.result;
54
+ }
55
+ const patched = injectWebSearchToolResult(ctx.base, toolCall, chosenEngine, query, chosenResult);
56
+ const followupPayload = buildWebSearchFollowupPayload(ctx.adapterContext, patched);
57
+ const execution = {
58
+ flowId: FLOW_ID,
59
+ followup: followupPayload
60
+ ? {
61
+ requestIdSuffix: ':web_search_followup',
62
+ payload: followupPayload,
63
+ metadata: buildFollowupMetadata(ctx.adapterContext, 'web_search')
64
+ }
65
+ : undefined
66
+ };
67
+ return {
68
+ chatResponse: patched,
69
+ execution
70
+ };
71
+ };
72
+ registerServerToolHandler('web_search', handler);
73
+ function parseToolArguments(toolCall) {
74
+ if (!toolCall.arguments || typeof toolCall.arguments !== 'string') {
75
+ return {};
76
+ }
77
+ try {
78
+ return JSON.parse(toolCall.arguments);
79
+ }
80
+ catch {
81
+ return {};
82
+ }
83
+ }
84
+ function getWebSearchConfig(ctx) {
85
+ const raw = ctx && typeof ctx === 'object' ? ctx.webSearch : undefined;
86
+ const record = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : null;
87
+ if (!record)
88
+ return undefined;
89
+ const enginesRaw = Array.isArray(record.engines) ? record.engines : [];
90
+ const engines = [];
91
+ for (const entry of enginesRaw) {
92
+ const obj = entry && typeof entry === 'object' && !Array.isArray(entry) ? entry : null;
93
+ if (!obj)
94
+ continue;
95
+ const id = typeof obj.id === 'string' && obj.id.trim() ? obj.id.trim() : undefined;
96
+ const providerKey = typeof obj.providerKey === 'string' && obj.providerKey.trim()
97
+ ? obj.providerKey.trim()
98
+ : undefined;
99
+ if (!id || !providerKey)
100
+ continue;
101
+ const serverToolsDisabled = obj.serverToolsDisabled === true ||
102
+ (typeof obj.serverToolsDisabled === 'string' &&
103
+ obj.serverToolsDisabled.trim().toLowerCase() === 'true') ||
104
+ (obj.serverTools &&
105
+ typeof obj.serverTools === 'object' &&
106
+ obj.serverTools.enabled === false);
107
+ engines.push({
108
+ id,
109
+ providerKey,
110
+ description: typeof obj.description === 'string' && obj.description.trim() ? obj.description.trim() : undefined,
111
+ default: obj.default === true,
112
+ ...(serverToolsDisabled ? { serverToolsDisabled: true } : {})
113
+ });
114
+ }
115
+ if (!engines.length) {
116
+ return undefined;
117
+ }
118
+ const config = { engines };
119
+ if (typeof record.injectPolicy === 'string') {
120
+ const val = String(record.injectPolicy).trim().toLowerCase();
121
+ if (val === 'always' || val === 'selective') {
122
+ config.injectPolicy = val;
123
+ }
124
+ }
125
+ if (record.force === true ||
126
+ (typeof record.force === 'string' && String(record.force).trim().toLowerCase() === 'true')) {
127
+ config.force = true;
128
+ }
129
+ return config;
130
+ }
131
+ function resolveWebSearchEngine(config, engineId) {
132
+ const trimmedId = typeof engineId === 'string' && engineId.trim() ? engineId.trim() : undefined;
133
+ if (trimmedId) {
134
+ const byId = config.engines.find((e) => e.id === trimmedId);
135
+ if (byId && !byId.serverToolsDisabled) {
136
+ return byId;
137
+ }
138
+ }
139
+ const byDefault = config.engines.find((e) => e.default && !e.serverToolsDisabled);
140
+ if (byDefault && !byDefault.serverToolsDisabled) {
141
+ return byDefault;
142
+ }
143
+ if (config.engines.length === 1) {
144
+ const single = config.engines[0];
145
+ return single.serverToolsDisabled ? undefined : single;
146
+ }
147
+ return undefined;
148
+ }
149
+ function buildEnginePriorityList(config, engineId) {
150
+ const engines = (Array.isArray(config.engines) ? config.engines : []).filter((engine) => !engine.serverToolsDisabled);
151
+ if (!engines.length) {
152
+ return [];
153
+ }
154
+ const primary = resolveWebSearchEngine(config, engineId);
155
+ if (!primary) {
156
+ return [...engines];
157
+ }
158
+ const ordered = [primary];
159
+ for (const engine of engines) {
160
+ if (engine !== primary) {
161
+ ordered.push(engine);
162
+ }
163
+ }
164
+ return ordered;
165
+ }
166
+ function resolveEnvServerSideToolsEnabled() {
167
+ const raw = (process.env.ROUTECODEX_SERVER_SIDE_TOOLS || process.env.RCC_SERVER_SIDE_TOOLS || '').trim().toLowerCase();
168
+ if (!raw)
169
+ return false;
170
+ if (raw === '1' || raw === 'true' || raw === 'yes')
171
+ return true;
172
+ if (raw === 'web_search')
173
+ return true;
174
+ return false;
175
+ }
176
+ function isGeminiWebSearchEngine(engine) {
177
+ const key = engine.providerKey.toLowerCase();
178
+ return (key.startsWith('gemini-cli.') ||
179
+ key.startsWith('antigravity.') ||
180
+ key.startsWith('gemini.'));
181
+ }
182
+ function normalizeResultCount(value) {
183
+ if (typeof value === 'number' && Number.isFinite(value)) {
184
+ const normalized = Math.trunc(value);
185
+ if (normalized >= 5 && normalized <= 15) {
186
+ return normalized;
187
+ }
188
+ }
189
+ return 10;
190
+ }
191
+ async function executeWebSearchBackend(args) {
192
+ const { ctx, engine, query } = args;
193
+ const recency = typeof args.recency === 'string' && args.recency.trim() ? args.recency.trim() : undefined;
194
+ let summary = '';
195
+ let hits = [];
196
+ let ok = true;
197
+ try {
198
+ logServerToolWebSearch(engine, ctx.options.requestId, query);
199
+ const requestSuffix = `:web_search:${engine.id}`;
200
+ if (ctx.options.reenterPipeline) {
201
+ const payload = buildWebSearchReenterPayload(engine, query, recency, args.resultCount);
202
+ const followup = await ctx.options.reenterPipeline({
203
+ entryEndpoint: '/v1/chat/completions',
204
+ requestId: `${ctx.options.requestId}${requestSuffix}`,
205
+ body: payload,
206
+ metadata: {
207
+ routeHint: 'web_search',
208
+ serverToolFollowup: true,
209
+ stream: false
210
+ }
211
+ });
212
+ const body = followup.body && typeof followup.body === 'object' ? followup.body : null;
213
+ if (body) {
214
+ summary = extractTextFromChatLike(body);
215
+ hits = collectWebSearchHits(body);
216
+ if (!summary && process.env.ROUTECODEX_DEBUG_GLM_WEB_SEARCH === '1') {
217
+ try {
218
+ // eslint-disable-next-line no-console
219
+ console.log('\x1b[38;5;27m[server-tool][web_search][backend_debug]' +
220
+ ` requestId=${ctx.options.requestId}${requestSuffix} payload=${JSON.stringify(body).slice(0, 2000)}\x1b[0m`);
221
+ }
222
+ catch {
223
+ /* logging best-effort */
224
+ }
225
+ }
226
+ }
227
+ }
228
+ else if (ctx.options.providerInvoker) {
229
+ summary = await executeWebSearchViaProvider({
230
+ ctx,
231
+ engine,
232
+ query,
233
+ recency,
234
+ count: args.resultCount,
235
+ requestSuffix
236
+ });
237
+ hits = [];
238
+ }
239
+ }
240
+ catch (error) {
241
+ ok = false;
242
+ const message = error instanceof Error && typeof error.message === 'string' && error.message.trim()
243
+ ? sanitizeBackendError(error.message.trim())
244
+ : 'web_search backend failed';
245
+ summary =
246
+ `web_search failed: ${message}. ` +
247
+ '请调整搜索关键词(例如减少敏感描述或换一种说法)后重试,这只是当前查询被阻止。';
248
+ }
249
+ if (!summary) {
250
+ if (hits.length) {
251
+ summary = formatHitsSummary(hits);
252
+ }
253
+ else {
254
+ summary =
255
+ 'web_search completed but returned no textual summary. ' +
256
+ '可以尝试修改搜索词、增加时间范围或换一个更具体的描述后再次搜索。';
257
+ }
258
+ }
259
+ try {
260
+ const preview = summary.length > 120 ? `${summary.slice(0, 117)}...` : summary;
261
+ // eslint-disable-next-line no-console
262
+ console.log(`\x1b[38;5;27m[server-tool][web_search][result] requestId=${ctx.options.requestId} ` +
263
+ `engine=${engine.id} chars=${summary.length} preview=${JSON.stringify(preview)}\x1b[0m`);
264
+ }
265
+ catch {
266
+ /* logging best-effort */
267
+ }
268
+ const finalHits = limitHits(hits);
269
+ if (!summary) {
270
+ summary = formatHitsSummary(finalHits);
271
+ }
272
+ if (finalHits.length > 0 && finalHits.length < 5) {
273
+ summary = `${summary}\n(当前仅返回${finalHits.length}条可用结果,可尝试调整关键词或时间范围以获取更多。)`;
274
+ }
275
+ return { summary, hits: finalHits, ok };
276
+ }
277
+ function buildWebSearchReenterPayload(engine, query, recency, resultCount) {
278
+ const systemPrompt = buildWebSearchSystemPrompt(resultCount);
279
+ const basePayload = {
280
+ model: engine.id,
281
+ messages: [
282
+ {
283
+ role: 'system',
284
+ content: systemPrompt
285
+ },
286
+ {
287
+ role: 'user',
288
+ content: query
289
+ }
290
+ ],
291
+ stream: false
292
+ };
293
+ if (isGeminiWebSearchEngine(engine)) {
294
+ return basePayload;
295
+ }
296
+ return {
297
+ ...basePayload,
298
+ web_search: {
299
+ query,
300
+ ...(recency ? { recency } : {}),
301
+ count: resultCount,
302
+ engine: engine.id
303
+ }
304
+ };
305
+ }
306
+ async function executeWebSearchViaProvider(args) {
307
+ const { ctx, engine, query, recency, count, requestSuffix } = args;
308
+ if (!ctx.options.providerInvoker) {
309
+ return '';
310
+ }
311
+ if (isGeminiWebSearchEngine(engine)) {
312
+ const geminiPayload = {
313
+ model: engine.id,
314
+ contents: [
315
+ {
316
+ role: 'user',
317
+ parts: [
318
+ {
319
+ text: query
320
+ }
321
+ ]
322
+ }
323
+ ],
324
+ tools: [
325
+ {
326
+ googleSearch: {}
327
+ }
328
+ ]
329
+ };
330
+ const backend = await ctx.options.providerInvoker({
331
+ providerKey: engine.providerKey,
332
+ providerType: undefined,
333
+ modelId: engine.id,
334
+ providerProtocol: 'gemini-chat',
335
+ payload: geminiPayload,
336
+ entryEndpoint: '/v1/models/gemini:generateContent',
337
+ requestId: `${ctx.options.requestId}${requestSuffix}`,
338
+ routeHint: 'web_search'
339
+ });
340
+ const providerResponse = backend.providerResponse && typeof backend.providerResponse === 'object'
341
+ ? backend.providerResponse
342
+ : null;
343
+ if (!providerResponse) {
344
+ return '';
345
+ }
346
+ const chatLike = buildOpenAIChatFromGeminiResponse(providerResponse);
347
+ return chatLike ? extractTextFromChatLike(chatLike) : '';
348
+ }
349
+ const backendPayload = {
350
+ model: engine.id,
351
+ messages: [
352
+ {
353
+ role: 'system',
354
+ content: 'You are a web search engine. Answer with up-to-date information based on the open internet.'
355
+ },
356
+ {
357
+ role: 'user',
358
+ content: query
359
+ }
360
+ ],
361
+ stream: false,
362
+ web_search: {
363
+ query,
364
+ ...(recency ? { recency } : {}),
365
+ count: args.count,
366
+ engine: engine.id
367
+ }
368
+ };
369
+ const backend = await ctx.options.providerInvoker({
370
+ providerKey: engine.providerKey,
371
+ providerType: undefined,
372
+ modelId: undefined,
373
+ providerProtocol: ctx.options.providerProtocol,
374
+ payload: backendPayload,
375
+ entryEndpoint: '/v1/chat/completions',
376
+ requestId: `${ctx.options.requestId}${requestSuffix}`,
377
+ routeHint: 'web_search'
378
+ });
379
+ const providerResponse = backend.providerResponse && typeof backend.providerResponse === 'object'
380
+ ? backend.providerResponse
381
+ : null;
382
+ if (!providerResponse) {
383
+ return '';
384
+ }
385
+ return extractTextFromChatLike(providerResponse);
386
+ }
387
+ function injectWebSearchToolResult(base, toolCall, engine, query, backendResult) {
388
+ const cloned = cloneJson(base);
389
+ const existingOutputs = Array.isArray(cloned.tool_outputs)
390
+ ? cloned.tool_outputs
391
+ : [];
392
+ const resultsPayload = backendResult.hits.map((hit, index) => ({
393
+ index: index + 1,
394
+ title: hit.title ?? '',
395
+ link: hit.link,
396
+ snippet: hit.content ?? '',
397
+ source: hit.media ?? '',
398
+ publish_date: hit.publish_date ?? ''
399
+ }));
400
+ cloned.tool_outputs = [
401
+ ...existingOutputs,
402
+ {
403
+ tool_call_id: toolCall.id,
404
+ name: 'web_search',
405
+ content: JSON.stringify({
406
+ engine: engine.id,
407
+ query,
408
+ summary: backendResult.summary,
409
+ results: resultsPayload
410
+ })
411
+ }
412
+ ];
413
+ return cloned;
414
+ }
415
+ function buildWebSearchFollowupPayload(adapterContext, chatResponse) {
416
+ const captured = adapterContext && typeof adapterContext === 'object'
417
+ ? adapterContext.capturedChatRequest
418
+ : undefined;
419
+ if (!captured || typeof captured !== 'object') {
420
+ return null;
421
+ }
422
+ const originalMessages = Array.isArray(captured.messages)
423
+ ? cloneJson(captured.messages)
424
+ : [];
425
+ const originalTools = Array.isArray(captured.tools)
426
+ ? cloneJson(captured.tools)
427
+ : [];
428
+ const assistantMessage = extractAssistantMessage(chatResponse);
429
+ if (!assistantMessage) {
430
+ return null;
431
+ }
432
+ const toolMessages = buildToolMessages(chatResponse);
433
+ if (!toolMessages.length) {
434
+ return null;
435
+ }
436
+ const reconstructed = [...originalMessages, assistantMessage, ...toolMessages];
437
+ const filteredTools = originalTools.filter((tool) => {
438
+ if (!tool || typeof tool !== 'object')
439
+ return false;
440
+ const fn = tool.function;
441
+ const name = fn && typeof fn.name === 'string'
442
+ ? fn.name
443
+ : '';
444
+ if (!name)
445
+ return true;
446
+ return name !== 'web_search';
447
+ });
448
+ const payload = {
449
+ messages: reconstructed
450
+ };
451
+ if (typeof captured.model === 'string' && captured.model.trim()) {
452
+ payload.model = captured.model.trim();
453
+ }
454
+ if (filteredTools.length) {
455
+ payload.tools = filteredTools;
456
+ }
457
+ const parameters = captured.parameters;
458
+ if (parameters && typeof parameters === 'object' && !Array.isArray(parameters)) {
459
+ Object.assign(payload, cloneJson(parameters));
460
+ }
461
+ return payload;
462
+ }
463
+ function extractAssistantMessage(chatResponse) {
464
+ const choices = Array.isArray(chatResponse.choices)
465
+ ? chatResponse.choices
466
+ : [];
467
+ if (!choices.length)
468
+ return null;
469
+ const firstChoice = choices[0] && typeof choices[0] === 'object' && !Array.isArray(choices[0])
470
+ ? choices[0]
471
+ : null;
472
+ if (!firstChoice)
473
+ return null;
474
+ const assistantMessage = firstChoice.message && typeof firstChoice.message === 'object'
475
+ ? firstChoice.message
476
+ : null;
477
+ return assistantMessage;
478
+ }
479
+ function buildToolMessages(chatResponse) {
480
+ const toolOutputs = Array.isArray(chatResponse.tool_outputs)
481
+ ? chatResponse.tool_outputs
482
+ : [];
483
+ const messages = [];
484
+ for (const entry of toolOutputs) {
485
+ if (!entry || typeof entry !== 'object')
486
+ continue;
487
+ const toolCallId = typeof entry.tool_call_id === 'string'
488
+ ? entry.tool_call_id
489
+ : undefined;
490
+ if (!toolCallId)
491
+ continue;
492
+ const name = typeof entry.name === 'string'
493
+ ? entry.name
494
+ : 'web_search';
495
+ const rawContent = entry.content;
496
+ let contentText;
497
+ if (typeof rawContent === 'string') {
498
+ contentText = rawContent;
499
+ }
500
+ else {
501
+ try {
502
+ contentText = JSON.stringify(rawContent ?? {});
503
+ }
504
+ catch {
505
+ contentText = String(rawContent ?? '');
506
+ }
507
+ }
508
+ messages.push({
509
+ role: 'tool',
510
+ tool_call_id: toolCallId,
511
+ name,
512
+ content: contentText
513
+ });
514
+ }
515
+ return messages;
516
+ }
517
+ function logServerToolWebSearch(engine, requestId, query) {
518
+ const providerAlias = engine.providerKey.split('.')[0] || engine.providerKey;
519
+ const backendLabel = `${providerAlias}:${engine.id}`;
520
+ const prefix = `[server-tool][web_search][${backendLabel}]`;
521
+ const line = `${prefix} requestId=${requestId} query=${JSON.stringify(query)}`;
522
+ // eslint-disable-next-line no-console
523
+ console.log(`\x1b[38;5;27m${line}\x1b[0m`);
524
+ const vrPrefix = `[virtual-router][servertool][web_search]`;
525
+ const vrBackend = `${engine.providerKey}:${engine.id}`;
526
+ const vrLine = `${vrPrefix} requestId=${requestId} backend=${vrBackend}`;
527
+ // eslint-disable-next-line no-console
528
+ console.log(`\x1b[31m${vrLine}\x1b[0m`);
529
+ }
530
+ function buildFollowupMetadata(adapterContext, toolName) {
531
+ const ctx = adapterContext && typeof adapterContext === 'object' ? adapterContext : null;
532
+ const routeId = ctx && typeof ctx.routeId === 'string' && ctx.routeId.trim() ? ctx.routeId.trim() : '';
533
+ if (!routeId || routeId.toLowerCase() === toolName.toLowerCase()) {
534
+ return undefined;
535
+ }
536
+ return { routeHint: routeId };
537
+ }
538
+ function findWebSearchArray(payload) {
539
+ let current = payload;
540
+ const visited = new Set();
541
+ while (current && !visited.has(current)) {
542
+ visited.add(current);
543
+ const hits = getArray(current.web_search);
544
+ if (hits.length) {
545
+ return hits;
546
+ }
547
+ const nextData = current.data;
548
+ if (nextData && typeof nextData === 'object' && !Array.isArray(nextData)) {
549
+ current = nextData;
550
+ continue;
551
+ }
552
+ const nextResponse = current.response;
553
+ if (nextResponse && typeof nextResponse === 'object' && !Array.isArray(nextResponse)) {
554
+ current = nextResponse;
555
+ continue;
556
+ }
557
+ break;
558
+ }
559
+ return undefined;
560
+ }
561
+ function collectWebSearchHits(payload) {
562
+ const array = findWebSearchArray(payload);
563
+ if (!array) {
564
+ return [];
565
+ }
566
+ const hits = [];
567
+ for (const entry of array) {
568
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry))
569
+ continue;
570
+ const record = entry;
571
+ const link = typeof record.link === 'string' && record.link.trim() ? record.link.trim() : '';
572
+ if (!link)
573
+ continue;
574
+ hits.push({
575
+ title: typeof record.title === 'string' ? record.title : undefined,
576
+ link,
577
+ media: typeof record.media === 'string' ? record.media : undefined,
578
+ publish_date: typeof record.publish_date === 'string' ? record.publish_date : undefined,
579
+ content: typeof record.content === 'string' ? record.content : undefined,
580
+ refer: typeof record.refer === 'string' ? record.refer : undefined
581
+ });
582
+ }
583
+ return hits;
584
+ }
585
+ function limitHits(hits) {
586
+ if (!hits.length)
587
+ return [];
588
+ const filtered = hits.slice(0, 15);
589
+ if (filtered.length >= 5) {
590
+ return filtered;
591
+ }
592
+ return filtered;
593
+ }
594
+ function formatHitsSummary(hits) {
595
+ if (!hits.length) {
596
+ return '';
597
+ }
598
+ const segments = [];
599
+ hits.forEach((hit, index) => {
600
+ const idx = hit.refer && hit.refer.trim() ? hit.refer.trim() : String(index + 1);
601
+ const headerParts = [];
602
+ if (hit.title)
603
+ headerParts.push(hit.title);
604
+ if (hit.media)
605
+ headerParts.push(hit.media);
606
+ if (hit.publish_date)
607
+ headerParts.push(hit.publish_date);
608
+ const header = headerParts.length ? headerParts.join(' · ') : '搜索结果';
609
+ const details = [hit.content, hit.link].filter(Boolean).join('\n');
610
+ segments.push(`【${idx}】${header}\n${details}`);
611
+ });
612
+ return segments.join('\n\n');
613
+ }
614
+ function getArray(value) {
615
+ return Array.isArray(value) ? value : [];
616
+ }
617
+ function sanitizeBackendError(message) {
618
+ const lowered = message.toLowerCase();
619
+ if (lowered.includes('contentfilter')) {
620
+ return '搜索请求被后端暂时拒绝';
621
+ }
622
+ if (lowered.includes('instructions are not valid')) {
623
+ return '搜索指令格式未被后端接受';
624
+ }
625
+ return message;
626
+ }
627
+ function buildWebSearchSystemPrompt(targetCount) {
628
+ const normalizedTarget = Math.max(5, Math.min(15, targetCount));
629
+ const instructions = [
630
+ 'You are an up-to-date web search engine that aggregates public internet results.',
631
+ `Return between 5 and 15 high-quality search results (aim for about ${normalizedTarget} when available).`,
632
+ 'Each result must include: title, source/media, publish date if available, a concise summary (<=200 characters), and a direct URL that users can click for verification.',
633
+ 'Prefer de-duplicated sources and include diverse outlets. If fewer than 5 results exist, return what you can find and explain the limitation.',
634
+ 'Only mention that the query was blocked when the backend explicitly rejects it, and encourage the user to adjust their keywords before retrying.',
635
+ 'Structure the answer so downstream systems can extract each result cleanly.'
636
+ ];
637
+ return instructions.join('\n');
638
+ }
@@ -0,0 +1,33 @@
1
+ import type { AdapterContext } from '../conversion/hub/types/chat-envelope.js';
2
+ import type { JsonObject } from '../conversion/hub/types/json.js';
3
+ import type { ProviderInvoker } from './types.js';
4
+ export interface ServerToolOrchestrationOptions {
5
+ chat: JsonObject;
6
+ adapterContext: AdapterContext;
7
+ requestId: string;
8
+ entryEndpoint: string;
9
+ providerProtocol: string;
10
+ /**
11
+ * 将带有工具结果的新 ChatEnvelope 作为普通请求再送入 HubPipeline。
12
+ * 支持 routeHint 来强制路由(例如 web_search)
13
+ */
14
+ reenterPipeline?: (options: {
15
+ entryEndpoint: string;
16
+ requestId: string;
17
+ body: JsonObject;
18
+ metadata?: JsonObject;
19
+ }) => Promise<{
20
+ body?: JsonObject;
21
+ __sse_responses?: unknown;
22
+ format?: string;
23
+ }>;
24
+ providerInvoker?: ProviderInvoker;
25
+ }
26
+ export interface ServerToolOrchestrationResult {
27
+ chat: JsonObject;
28
+ executed: boolean;
29
+ /**
30
+ * 记录本次执行使用的骨架流程,便于日志输出和后续扩展。
31
+ */
32
+ flowId?: string;
33
+ }
@@ -0,0 +1,18 @@
1
+ import type { ServerToolHandler } from './types.js';
2
+ /**
3
+ * ServerToolRegistry:全局注册表,按 tool name 管理 ServerTool handler。
4
+ * - key 统一使用小写名称(如 "web_search");
5
+ * - 不关注具体协议(Chat / Responses),只负责分发到 handler。
6
+ */
7
+ type TriggerMode = 'tool_call' | 'auto';
8
+ interface ServerToolHandlerEntry {
9
+ name: string;
10
+ trigger: TriggerMode;
11
+ handler: ServerToolHandler;
12
+ }
13
+ export declare function registerServerToolHandler(name: string, handler: ServerToolHandler, options?: {
14
+ trigger?: TriggerMode;
15
+ }): void;
16
+ export declare function getServerToolHandler(name: string): ServerToolHandlerEntry | undefined;
17
+ export declare function listAutoServerToolHandlers(): ServerToolHandlerEntry[];
18
+ export {};