@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
@@ -18,7 +18,7 @@ import { buildProviderProfiles } from '../../../providers/profile/provider-profi
18
18
  import { emitProviderError } from '../../../providers/core/utils/provider-error-reporter.js';
19
19
  import { isStageLoggingEnabled, logPipelineStage } from '../../utils/stage-logger.js';
20
20
  import { registerDefaultMiddleware } from './middleware.js';
21
- import { registerHttpRoutes } from './routes.js';
21
+ import { registerHttpRoutes, registerOAuthPortalRoute } from './routes.js';
22
22
  import { mapProviderProtocol, normalizeProviderType, resolveProviderIdentity, asRecord } from './provider-utils.js';
23
23
  import { resolveRepoRoot, loadLlmswitchModule } from './llmswitch-loader.js';
24
24
  import { importCoreModule } from '../../../modules/llmswitch/core-loader.js';
@@ -27,6 +27,8 @@ import { rebindResponsesConversationRequestId } from '../../../modules/llmswitch
27
27
  import { initializeRouteErrorHub, reportRouteError } from '../../../error-handling/route-error-hub.js';
28
28
  import { writeClientSnapshot } from '../../../providers/core/utils/snapshot-writer.js';
29
29
  import { createServerColoredLogger } from './colored-logger.js';
30
+ import { formatValueForConsole } from '../../../utils/logger.js';
31
+ import { QuietErrorHandlingCenter } from '../../../error-handling/quiet-error-handling-center.js';
30
32
  let convertProviderResponseFn = null;
31
33
  async function loadConvertProviderResponse() {
32
34
  if (convertProviderResponseFn) {
@@ -82,7 +84,7 @@ export class RouteCodexHttpServer {
82
84
  constructor(config) {
83
85
  this.config = config;
84
86
  this.app = express();
85
- this.errorHandling = new ErrorHandlingCenter();
87
+ this.errorHandling = new QuietErrorHandlingCenter();
86
88
  this.stageLoggingEnabled = isStageLoggingEnabled();
87
89
  this.repoRoot = resolveRepoRoot(import.meta.url);
88
90
  const envFlag = (process.env.ROUTECODEX_USE_HUB_PIPELINE || '').trim().toLowerCase();
@@ -96,6 +98,11 @@ export class RouteCodexHttpServer {
96
98
  console.warn('[RouteCodexHttpServer] Failed to initialize PipelineDebugLogger; falling back to noop logger.', error);
97
99
  this.pipelineLogger = createNoopPipelineLogger();
98
100
  }
101
+ // Register critical routes early (before provider initialization)
102
+ // This ensures OAuth Portal is available when providers check token validity
103
+ registerDefaultMiddleware(this.app);
104
+ registerOAuthPortalRoute(this.app);
105
+ console.log('[RouteCodexHttpServer] OAuth Portal route registered (early initialization)');
99
106
  console.log('[RouteCodexHttpServer] Initialized (pipeline=hub)');
100
107
  }
101
108
  resolveVirtualRouterInput(userConfig) {
@@ -122,6 +129,9 @@ export class RouteCodexHttpServer {
122
129
  const sanitizedContext = formatErrorForErrorCenter(contextPayload);
123
130
  await this.errorHandling.handleError({
124
131
  error: sanitizedError,
132
+ source: 'pipeline',
133
+ severity: 'medium',
134
+ timestamp: Date.now(),
125
135
  context: sanitizedContext
126
136
  });
127
137
  },
@@ -329,7 +339,8 @@ export class RouteCodexHttpServer {
329
339
  // 初始化错误处理
330
340
  await this.errorHandling.initialize();
331
341
  await this.initializeRouteErrorHub();
332
- registerDefaultMiddleware(this.app);
342
+ // registerDefaultMiddleware and registerOAuthPortalRoute already called in constructor
343
+ // Register remaining HTTP routes
333
344
  registerHttpRoutes({
334
345
  app: this.app,
335
346
  config: this.config,
@@ -434,8 +445,8 @@ export class RouteCodexHttpServer {
434
445
  await reportRouteError(payload);
435
446
  }
436
447
  catch (handlerError) {
437
- console.error('[RouteCodexHttpServer] Failed to report error via RouteErrorHub:', handlerError);
438
- console.error('[RouteCodexHttpServer] Original error:', error);
448
+ console.error('[RouteCodexHttpServer] Failed to report error via RouteErrorHub:', formatValueForConsole(handlerError));
449
+ console.error('[RouteCodexHttpServer] Original error:', formatValueForConsole(error));
439
450
  }
440
451
  }
441
452
  // --- V1 parity helpers and attach methods ---
@@ -619,14 +630,14 @@ export class RouteCodexHttpServer {
619
630
  if (!this.isPipelineReady()) {
620
631
  throw new Error('Hub pipeline runtime is not initialized');
621
632
  }
622
- const metadata = this.buildRequestMetadata(input);
633
+ const initialMetadata = this.buildRequestMetadata(input);
623
634
  const providerRequestId = input.requestId;
624
- const clientRequestId = typeof metadata.clientRequestId === 'string' && metadata.clientRequestId.trim()
625
- ? metadata.clientRequestId.trim()
635
+ const clientRequestId = typeof initialMetadata.clientRequestId === 'string' && initialMetadata.clientRequestId.trim()
636
+ ? initialMetadata.clientRequestId.trim()
626
637
  : providerRequestId;
627
638
  this.logStage('request.received', providerRequestId, {
628
639
  endpoint: input.entryEndpoint,
629
- stream: input.metadata?.stream === true
640
+ stream: initialMetadata.stream === true
630
641
  });
631
642
  try {
632
643
  const headerUa = (typeof input.headers?.['user-agent'] === 'string' && input.headers['user-agent']) ||
@@ -639,7 +650,7 @@ export class RouteCodexHttpServer {
639
650
  headers: asRecord(input.headers),
640
651
  body: input.body,
641
652
  metadata: {
642
- ...metadata,
653
+ ...initialMetadata,
643
654
  userAgent: headerUa,
644
655
  clientOriginator: headerOriginator
645
656
  }
@@ -649,155 +660,161 @@ export class RouteCodexHttpServer {
649
660
  // snapshot failure should not block request path
650
661
  }
651
662
  const pipelineLabel = 'hub';
652
- this.logStage(`${pipelineLabel}.start`, providerRequestId, {
653
- endpoint: input.entryEndpoint,
654
- stream: metadata.stream
655
- });
656
- const originalRequestSnapshot = this.cloneRequestPayload(input.body);
657
- const pipelineResult = await this.runHubPipeline(input, metadata);
658
- const pipelineMetadata = pipelineResult.metadata ?? {};
659
- const mergedMetadata = { ...metadata, ...pipelineMetadata };
660
- this.logStage(`${pipelineLabel}.completed`, providerRequestId, {
661
- route: pipelineResult.routingDecision?.routeName,
662
- target: pipelineResult.target?.providerKey
663
- });
664
- const providerPayload = pipelineResult.providerPayload;
665
- const target = pipelineResult.target;
666
- if (!providerPayload || !target?.providerKey) {
667
- throw Object.assign(new Error('Virtual router did not produce a provider target'), {
668
- code: 'ERR_NO_PROVIDER_TARGET',
669
- requestId: input.requestId
670
- });
671
- }
672
- const runtimeKey = target.runtimeKey || this.providerKeyToRuntimeKey.get(target.providerKey);
673
- if (!runtimeKey) {
674
- throw Object.assign(new Error(`Runtime for provider ${target.providerKey} not initialized`), {
675
- code: 'ERR_RUNTIME_NOT_FOUND',
676
- requestId: input.requestId
677
- });
678
- }
679
- const handle = this.providerHandles.get(runtimeKey);
680
- if (!handle) {
681
- throw Object.assign(new Error(`Provider runtime ${runtimeKey} not found`), {
682
- code: 'ERR_PROVIDER_NOT_FOUND',
683
- requestId: input.requestId
663
+ let iterationMetadata = initialMetadata;
664
+ let followupTriggered = false;
665
+ while (true) {
666
+ this.logStage(`${pipelineLabel}.start`, providerRequestId, {
667
+ endpoint: input.entryEndpoint,
668
+ stream: iterationMetadata.stream
684
669
  });
685
- }
686
- const providerProtocol = target.outboundProfile ||
687
- handle.providerProtocol;
688
- const metadataModel = mergedMetadata?.target && typeof mergedMetadata.target === 'object'
689
- ? mergedMetadata.target.clientModelId
690
- : undefined;
691
- const rawModel = this.extractProviderModel(providerPayload) ||
692
- (typeof metadataModel === 'string' ? metadataModel : undefined);
693
- const providerIdToken = target.providerKey || handle.providerId || runtimeKey;
694
- if (!providerIdToken) {
695
- throw Object.assign(new Error('Provider identifier missing for request'), {
696
- code: 'ERR_PROVIDER_ID_MISSING',
697
- requestId: providerRequestId
670
+ const originalRequestSnapshot = this.cloneRequestPayload(input.body);
671
+ const pipelineResult = await this.runHubPipeline(input, iterationMetadata);
672
+ const pipelineMetadata = pipelineResult.metadata ?? {};
673
+ const mergedMetadata = { ...iterationMetadata, ...pipelineMetadata };
674
+ this.logStage(`${pipelineLabel}.completed`, providerRequestId, {
675
+ route: pipelineResult.routingDecision?.routeName,
676
+ target: pipelineResult.target?.providerKey
698
677
  });
699
- }
700
- const enhancedRequestId = enhanceProviderRequestId(providerRequestId, {
701
- entryEndpoint: input.entryEndpoint,
702
- providerId: providerIdToken,
703
- model: rawModel
704
- });
705
- if (providerProtocol === 'openai-responses') {
706
- try {
707
- await rebindResponsesConversationRequestId(pipelineResult.requestId, enhancedRequestId);
678
+ const providerPayload = pipelineResult.providerPayload;
679
+ const target = pipelineResult.target;
680
+ if (!providerPayload || !target?.providerKey) {
681
+ throw Object.assign(new Error('Virtual router did not produce a provider target'), {
682
+ code: 'ERR_NO_PROVIDER_TARGET',
683
+ requestId: input.requestId
684
+ });
708
685
  }
709
- catch {
710
- /* ignore rebind failures */
686
+ const runtimeKey = target.runtimeKey || this.providerKeyToRuntimeKey.get(target.providerKey);
687
+ if (!runtimeKey) {
688
+ throw Object.assign(new Error(`Runtime for provider ${target.providerKey} not initialized`), {
689
+ code: 'ERR_RUNTIME_NOT_FOUND',
690
+ requestId: input.requestId
691
+ });
711
692
  }
712
- }
713
- if (enhancedRequestId !== input.requestId) {
714
- input.requestId = enhancedRequestId;
715
- }
716
- mergedMetadata.clientRequestId = clientRequestId;
717
- const providerModel = rawModel;
718
- const providerLabel = this.buildProviderLabel(target.providerKey, providerModel);
719
- this.logStage('provider.prepare', input.requestId, {
720
- providerKey: target.providerKey,
721
- runtimeKey,
722
- protocol: providerProtocol,
723
- providerType: handle.providerType,
724
- providerFamily: handle.providerFamily,
725
- model: providerModel,
726
- providerLabel
727
- });
728
- attachProviderRuntimeMetadata(providerPayload, {
729
- requestId: input.requestId,
730
- providerId: handle.providerId,
731
- providerKey: target.providerKey,
732
- providerType: handle.providerType,
733
- providerFamily: handle.providerFamily,
734
- providerProtocol,
735
- pipelineId: target.providerKey,
736
- routeName: pipelineResult.routingDecision?.routeName,
737
- runtimeKey,
738
- target,
739
- metadata: mergedMetadata
740
- });
741
- this.logStage('provider.send.start', input.requestId, {
742
- providerKey: target.providerKey,
743
- runtimeKey,
744
- protocol: providerProtocol,
745
- providerType: handle.providerType,
746
- providerFamily: handle.providerFamily,
747
- model: providerModel,
748
- providerLabel
749
- });
750
- try {
751
- const providerResponse = await handle.instance.processIncoming(providerPayload);
752
- const responseStatus = this.extractResponseStatus(providerResponse);
753
- this.logStage('provider.send.completed', input.requestId, {
754
- providerKey: target.providerKey,
755
- status: responseStatus,
756
- providerType: handle.providerType,
757
- providerFamily: handle.providerFamily,
758
- model: providerModel,
759
- providerLabel
760
- });
761
- const normalized = this.normalizeProviderResponse(providerResponse);
762
- return await this.convertProviderResponseIfNeeded({
693
+ const handle = this.providerHandles.get(runtimeKey);
694
+ if (!handle) {
695
+ throw Object.assign(new Error(`Provider runtime ${runtimeKey} not found`), {
696
+ code: 'ERR_PROVIDER_NOT_FOUND',
697
+ requestId: input.requestId
698
+ });
699
+ }
700
+ const providerProtocol = target.outboundProfile ||
701
+ handle.providerProtocol;
702
+ const metadataModel = mergedMetadata?.target && typeof mergedMetadata.target === 'object'
703
+ ? mergedMetadata.target.clientModelId
704
+ : undefined;
705
+ const rawModel = this.extractProviderModel(providerPayload) ||
706
+ (typeof metadataModel === 'string' ? metadataModel : undefined);
707
+ const providerIdToken = target.providerKey || handle.providerId || runtimeKey;
708
+ if (!providerIdToken) {
709
+ throw Object.assign(new Error('Provider identifier missing for request'), {
710
+ code: 'ERR_PROVIDER_ID_MISSING',
711
+ requestId: providerRequestId
712
+ });
713
+ }
714
+ const enhancedRequestId = enhanceProviderRequestId(providerRequestId, {
763
715
  entryEndpoint: input.entryEndpoint,
764
- providerType: handle.providerType,
765
- requestId: input.requestId,
766
- wantsStream: Boolean(input.metadata?.inboundStream ?? input.metadata?.stream),
767
- originalRequest: originalRequestSnapshot,
768
- processMode: pipelineResult.processMode,
769
- response: normalized,
770
- pipelineMetadata: mergedMetadata
716
+ providerId: providerIdToken,
717
+ model: rawModel
771
718
  });
772
- }
773
- catch (error) {
774
- this.logStage('provider.send.error', input.requestId, {
719
+ if (providerProtocol === 'openai-responses') {
720
+ try {
721
+ await rebindResponsesConversationRequestId(pipelineResult.requestId, enhancedRequestId);
722
+ }
723
+ catch {
724
+ /* ignore rebind failures */
725
+ }
726
+ }
727
+ if (enhancedRequestId !== input.requestId) {
728
+ input.requestId = enhancedRequestId;
729
+ }
730
+ mergedMetadata.clientRequestId = clientRequestId;
731
+ const providerModel = rawModel;
732
+ const providerLabel = this.buildProviderLabel(target.providerKey, providerModel);
733
+ this.logStage('provider.prepare', input.requestId, {
775
734
  providerKey: target.providerKey,
776
- message: error instanceof Error ? error.message : String(error ?? 'Unknown error'),
735
+ runtimeKey,
736
+ protocol: providerProtocol,
777
737
  providerType: handle.providerType,
778
738
  providerFamily: handle.providerFamily,
779
739
  model: providerModel,
780
740
  providerLabel
781
741
  });
782
- const runtimeMetadata = {
742
+ attachProviderRuntimeMetadata(providerPayload, {
783
743
  requestId: input.requestId,
784
- providerKey: target.providerKey,
785
744
  providerId: handle.providerId,
745
+ providerKey: target.providerKey,
786
746
  providerType: handle.providerType,
747
+ providerFamily: handle.providerFamily,
787
748
  providerProtocol,
788
- routeName: pipelineResult.routingDecision?.routeName,
789
749
  pipelineId: target.providerKey,
750
+ routeName: pipelineResult.routingDecision?.routeName,
790
751
  runtimeKey,
791
- target
792
- };
793
- runtimeMetadata.providerFamily = handle.providerFamily;
794
- emitProviderError({
795
- error,
796
- stage: 'provider.send',
797
- runtime: runtimeMetadata,
798
- dependencies: this.getModuleDependencies()
752
+ target,
753
+ metadata: mergedMetadata
799
754
  });
800
- throw error;
755
+ this.logStage('provider.send.start', input.requestId, {
756
+ providerKey: target.providerKey,
757
+ runtimeKey,
758
+ protocol: providerProtocol,
759
+ providerType: handle.providerType,
760
+ providerFamily: handle.providerFamily,
761
+ model: providerModel,
762
+ providerLabel
763
+ });
764
+ try {
765
+ const providerResponse = await handle.instance.processIncoming(providerPayload);
766
+ const responseStatus = this.extractResponseStatus(providerResponse);
767
+ this.logStage('provider.send.completed', input.requestId, {
768
+ providerKey: target.providerKey,
769
+ status: responseStatus,
770
+ providerType: handle.providerType,
771
+ providerFamily: handle.providerFamily,
772
+ model: providerModel,
773
+ providerLabel
774
+ });
775
+ const wantsStreamBase = Boolean(input.metadata?.inboundStream ?? input.metadata?.stream);
776
+ const normalized = this.normalizeProviderResponse(providerResponse);
777
+ const converted = await this.convertProviderResponseIfNeeded({
778
+ entryEndpoint: input.entryEndpoint,
779
+ providerType: handle.providerType,
780
+ requestId: input.requestId,
781
+ wantsStream: wantsStreamBase,
782
+ originalRequest: originalRequestSnapshot,
783
+ processMode: pipelineResult.processMode,
784
+ response: normalized,
785
+ pipelineMetadata: mergedMetadata
786
+ });
787
+ return converted;
788
+ }
789
+ catch (error) {
790
+ this.logStage('provider.send.error', input.requestId, {
791
+ providerKey: target.providerKey,
792
+ message: error instanceof Error ? error.message : String(error ?? 'Unknown error'),
793
+ providerType: handle.providerType,
794
+ providerFamily: handle.providerFamily,
795
+ model: providerModel,
796
+ providerLabel
797
+ });
798
+ const runtimeMetadata = {
799
+ requestId: input.requestId,
800
+ providerKey: target.providerKey,
801
+ providerId: handle.providerId,
802
+ providerType: handle.providerType,
803
+ providerProtocol,
804
+ routeName: pipelineResult.routingDecision?.routeName,
805
+ pipelineId: target.providerKey,
806
+ runtimeKey,
807
+ target
808
+ };
809
+ runtimeMetadata.providerFamily = handle.providerFamily;
810
+ emitProviderError({
811
+ error,
812
+ stage: 'provider.send',
813
+ runtime: runtimeMetadata,
814
+ dependencies: this.getModuleDependencies()
815
+ });
816
+ throw error;
817
+ }
801
818
  }
802
819
  }
803
820
  async runHubPipeline(input, metadata) {
@@ -836,6 +853,15 @@ export class RouteCodexHttpServer {
836
853
  }
837
854
  buildRequestMetadata(input) {
838
855
  const userMeta = asRecord(input.metadata);
856
+ const headers = asRecord(input.headers);
857
+ const inboundUserAgent = this.extractHeaderValue(headers, 'user-agent');
858
+ const inboundOriginator = this.extractHeaderValue(headers, 'originator');
859
+ const resolvedUserAgent = typeof userMeta.userAgent === 'string' && userMeta.userAgent.trim()
860
+ ? userMeta.userAgent.trim()
861
+ : inboundUserAgent;
862
+ const resolvedOriginator = typeof userMeta.clientOriginator === 'string' && userMeta.clientOriginator.trim()
863
+ ? userMeta.clientOriginator.trim()
864
+ : inboundOriginator;
839
865
  const routeHint = this.extractRouteHint(input) ?? userMeta.routeHint;
840
866
  const processMode = userMeta.processMode || 'chat';
841
867
  return {
@@ -845,9 +871,30 @@ export class RouteCodexHttpServer {
845
871
  direction: 'request',
846
872
  stage: 'inbound',
847
873
  routeHint,
848
- stream: userMeta.stream === true
874
+ stream: userMeta.stream === true,
875
+ ...(resolvedUserAgent ? { userAgent: resolvedUserAgent } : {}),
876
+ ...(resolvedOriginator ? { clientOriginator: resolvedOriginator } : {})
849
877
  };
850
878
  }
879
+ extractHeaderValue(headers, name) {
880
+ if (!headers) {
881
+ return undefined;
882
+ }
883
+ const target = name.toLowerCase();
884
+ for (const [key, value] of Object.entries(headers)) {
885
+ if (key.toLowerCase() !== target) {
886
+ continue;
887
+ }
888
+ if (typeof value === 'string') {
889
+ return value.trim() || undefined;
890
+ }
891
+ if (Array.isArray(value) && value.length) {
892
+ return String(value[0]).trim() || undefined;
893
+ }
894
+ return undefined;
895
+ }
896
+ return undefined;
897
+ }
851
898
  extractRouteHint(input) {
852
899
  const header = input.headers['x-route-hint'];
853
900
  if (typeof header === 'string' && header.trim()) {
@@ -905,12 +952,28 @@ export class RouteCodexHttpServer {
905
952
  const metadataBag = asRecord(options.pipelineMetadata);
906
953
  const aliasMap = extractAnthropicToolAliasMap(metadataBag);
907
954
  const originalModelId = this.extractClientModelId(metadataBag, options.originalRequest);
908
- const adapterContext = {
909
- requestId: options.requestId,
910
- entryEndpoint: options.entryEndpoint || entry,
911
- providerProtocol,
912
- originalModelId
955
+ // HubPipeline metadata 为基础构建 AdapterContext,确保诸如
956
+ // capturedChatRequest / webSearch / routeHint 等字段在响应侧可见,
957
+ // 便于 llmswitch-core 内部实现 servertool/web_search 的第三跳。
958
+ const baseContext = {
959
+ ...(metadataBag ?? {})
913
960
  };
961
+ // 将 HubPipeline metadata.routeName 映射为 AdapterContext.routeId,
962
+ // 便于 llmswitch-core 在第三跳中使用 routeHint 复用首次路由决策。
963
+ if (typeof metadataBag?.routeName === 'string') {
964
+ baseContext.routeId = metadataBag.routeName;
965
+ }
966
+ baseContext.requestId = options.requestId;
967
+ baseContext.entryEndpoint = options.entryEndpoint || entry;
968
+ baseContext.providerProtocol = providerProtocol;
969
+ baseContext.originalModelId = originalModelId;
970
+ const adapterContext = baseContext;
971
+ // 将 serverToolFollowup 等标记从 pipelineMetadata 透传到 AdapterContext,
972
+ // 便于 convertProviderResponse 正确识别内部二跳请求并跳过 servertool。
973
+ if (metadataBag && Object.prototype.hasOwnProperty.call(metadataBag, 'serverToolFollowup')) {
974
+ adapterContext.serverToolFollowup = metadataBag
975
+ .serverToolFollowup;
976
+ }
914
977
  const compatProfile = metadataBag &&
915
978
  typeof metadataBag === 'object' &&
916
979
  metadataBag.target &&
@@ -924,18 +987,85 @@ export class RouteCodexHttpServer {
924
987
  if (aliasMap) {
925
988
  adapterContext.anthropicToolNameMap = aliasMap;
926
989
  }
990
+ if (metadataBag && typeof metadataBag === 'object') {
991
+ const webSearchConfig = metadataBag.webSearch;
992
+ if (webSearchConfig && typeof webSearchConfig === 'object') {
993
+ adapterContext.webSearch = webSearchConfig;
994
+ }
995
+ if (metadataBag.forceWebSearch === true) {
996
+ adapterContext.forceWebSearch = true;
997
+ }
998
+ if (metadataBag.forceVision === true) {
999
+ adapterContext.forceVision = true;
1000
+ }
1001
+ }
927
1002
  const [convertProviderResponse, createSnapshotRecorder] = await Promise.all([
928
1003
  loadConvertProviderResponse(),
929
1004
  loadSnapshotRecorderFactory()
930
1005
  ]);
931
- const stageRecorder = createSnapshotRecorder(adapterContext, adapterContext.entryEndpoint);
1006
+ const stageRecorder = createSnapshotRecorder(adapterContext, typeof adapterContext.entryEndpoint === 'string'
1007
+ ? adapterContext.entryEndpoint
1008
+ : options.entryEndpoint || entry);
1009
+ const providerInvoker = async (invokeOptions) => {
1010
+ const runtimeKey = this.providerKeyToRuntimeKey.get(invokeOptions.providerKey) || invokeOptions.providerKey;
1011
+ const handle = this.providerHandles.get(runtimeKey);
1012
+ if (!handle) {
1013
+ throw new Error(`Provider runtime ${runtimeKey} not found`);
1014
+ }
1015
+ const providerResponse = await handle.instance.processIncoming(invokeOptions.payload);
1016
+ const normalized = this.normalizeProviderResponse(providerResponse);
1017
+ const bodyPayload = normalized.body && typeof normalized.body === 'object'
1018
+ ? normalized.body
1019
+ : normalized;
1020
+ return { providerResponse: bodyPayload };
1021
+ };
1022
+ const reenterPipeline = async (reenterOpts) => {
1023
+ const nestedEntry = reenterOpts.entryEndpoint || options.entryEndpoint || entry;
1024
+ const nestedExtra = asRecord(reenterOpts.metadata) ?? {};
1025
+ const nestedEntryLower = nestedEntry.toLowerCase();
1026
+ // 基于首次 HubPipeline metadata + 调用方注入的 metadata 构建新的请求 metadata。
1027
+ // 不在 Host 层编码 servertool/web_search 等语义,由 llmswitch-core 负责。
1028
+ const nestedMetadata = {
1029
+ ...(metadataBag ?? {}),
1030
+ ...nestedExtra,
1031
+ entryEndpoint: nestedEntry,
1032
+ direction: 'request',
1033
+ stage: 'inbound'
1034
+ };
1035
+ // 针对 reenterPipeline 的入口端点,纠正 providerProtocol,避免沿用外层协议。
1036
+ if (nestedEntryLower.includes('/v1/chat/completions')) {
1037
+ nestedMetadata.providerProtocol = 'openai-chat';
1038
+ }
1039
+ else if (nestedEntryLower.includes('/v1/responses')) {
1040
+ nestedMetadata.providerProtocol = 'openai-responses';
1041
+ }
1042
+ else if (nestedEntryLower.includes('/v1/messages')) {
1043
+ nestedMetadata.providerProtocol = 'anthropic-messages';
1044
+ }
1045
+ const nestedInput = {
1046
+ entryEndpoint: nestedEntry,
1047
+ method: 'POST',
1048
+ requestId: reenterOpts.requestId,
1049
+ headers: {},
1050
+ query: {},
1051
+ body: reenterOpts.body,
1052
+ metadata: nestedMetadata
1053
+ };
1054
+ const nestedResult = await this.executePipeline(nestedInput);
1055
+ const nestedBody = nestedResult.body && typeof nestedResult.body === 'object'
1056
+ ? nestedResult.body
1057
+ : undefined;
1058
+ return { body: nestedBody };
1059
+ };
932
1060
  const converted = await convertProviderResponse({
933
1061
  providerProtocol,
934
1062
  providerResponse: body,
935
1063
  context: adapterContext,
936
1064
  entryEndpoint: options.entryEndpoint || entry,
937
1065
  wantsStream: options.wantsStream,
938
- stageRecorder
1066
+ providerInvoker,
1067
+ stageRecorder,
1068
+ reenterPipeline
939
1069
  });
940
1070
  if (converted.__sse_responses) {
941
1071
  return {
@@ -985,6 +1115,279 @@ export class RouteCodexHttpServer {
985
1115
  return undefined;
986
1116
  }
987
1117
  }
1118
+ buildVisionFollowupPayload(options) {
1119
+ const { originalPayload, visionResponse } = options;
1120
+ if (!originalPayload || typeof originalPayload !== 'object') {
1121
+ return null;
1122
+ }
1123
+ const clone = this.cloneRequestPayload(originalPayload) ?? { ...originalPayload };
1124
+ if (!clone) {
1125
+ return null;
1126
+ }
1127
+ const visionText = this.extractVisionDescription(visionResponse?.body);
1128
+ if (!visionText) {
1129
+ return null;
1130
+ }
1131
+ if (this.rewriteResponsesInput(clone, visionText)) {
1132
+ return clone;
1133
+ }
1134
+ if (this.rewriteChatMessages(clone, visionText)) {
1135
+ return clone;
1136
+ }
1137
+ return null;
1138
+ }
1139
+ rewriteResponsesInput(payload, visionText) {
1140
+ const inputList = payload.input;
1141
+ if (!Array.isArray(inputList)) {
1142
+ return false;
1143
+ }
1144
+ for (let i = inputList.length - 1; i >= 0; i -= 1) {
1145
+ const item = inputList[i];
1146
+ if (!item || typeof item !== 'object') {
1147
+ continue;
1148
+ }
1149
+ const role = typeof item.role === 'string'
1150
+ ? item.role
1151
+ : '';
1152
+ if (role !== 'user') {
1153
+ continue;
1154
+ }
1155
+ const contentBlocks = Array.isArray(item.content)
1156
+ ? [...item.content]
1157
+ : [];
1158
+ const originalText = this.extractTextFromContentBlocks(contentBlocks, ['input_text', 'text']);
1159
+ const textType = this.detectContentTextType(contentBlocks, 'input_text');
1160
+ const composed = this.composeVisionUserText(visionText, originalText);
1161
+ item.content = [
1162
+ {
1163
+ type: textType,
1164
+ text: composed
1165
+ }
1166
+ ];
1167
+ inputList[i] = item;
1168
+ return true;
1169
+ }
1170
+ return false;
1171
+ }
1172
+ rewriteChatMessages(payload, visionText) {
1173
+ const messages = payload.messages;
1174
+ if (!Array.isArray(messages)) {
1175
+ return false;
1176
+ }
1177
+ for (let i = messages.length - 1; i >= 0; i -= 1) {
1178
+ const message = messages[i];
1179
+ if (!message || typeof message !== 'object') {
1180
+ continue;
1181
+ }
1182
+ const role = typeof message.role === 'string'
1183
+ ? message.role
1184
+ : '';
1185
+ if (role !== 'user') {
1186
+ continue;
1187
+ }
1188
+ const contentBlocks = Array.isArray(message.content)
1189
+ ? [...message.content]
1190
+ : [];
1191
+ const originalText = this.extractTextFromContentBlocks(contentBlocks, ['text']);
1192
+ const textType = this.detectContentTextType(contentBlocks, 'text');
1193
+ const composed = this.composeVisionUserText(visionText, originalText);
1194
+ message.content = [
1195
+ {
1196
+ type: textType,
1197
+ text: composed
1198
+ }
1199
+ ];
1200
+ messages[i] = message;
1201
+ return true;
1202
+ }
1203
+ return false;
1204
+ }
1205
+ extractTextFromContentBlocks(content, allowedTypes) {
1206
+ if (typeof content === 'string') {
1207
+ return content;
1208
+ }
1209
+ if (!Array.isArray(content)) {
1210
+ return '';
1211
+ }
1212
+ const collected = [];
1213
+ for (const block of content) {
1214
+ if (!block || typeof block !== 'object') {
1215
+ continue;
1216
+ }
1217
+ const typeValue = typeof block.type === 'string'
1218
+ ? block.type
1219
+ : '';
1220
+ if (allowedTypes.length && !allowedTypes.includes(typeValue)) {
1221
+ continue;
1222
+ }
1223
+ const textValue = block.text;
1224
+ if (typeof textValue === 'string' && textValue.trim()) {
1225
+ collected.push(textValue.trim());
1226
+ }
1227
+ }
1228
+ return collected.join('\n');
1229
+ }
1230
+ detectContentTextType(content, fallback) {
1231
+ if (Array.isArray(content)) {
1232
+ for (const block of content) {
1233
+ if (!block || typeof block !== 'object') {
1234
+ continue;
1235
+ }
1236
+ const typeValue = block.type;
1237
+ if (typeof typeValue === 'string' && (typeValue === 'text' || typeValue === 'input_text')) {
1238
+ return typeValue;
1239
+ }
1240
+ }
1241
+ }
1242
+ return fallback;
1243
+ }
1244
+ composeVisionUserText(visionText, originalText) {
1245
+ const sections = [];
1246
+ const cleanedVision = (visionText || '').trim();
1247
+ if (cleanedVision) {
1248
+ sections.push(`【图片分析】\n${cleanedVision}`);
1249
+ }
1250
+ const cleanedOriginal = (originalText || '').trim();
1251
+ if (cleanedOriginal) {
1252
+ sections.push(`【用户原始请求】\n${cleanedOriginal}`);
1253
+ }
1254
+ return sections.join('\n\n');
1255
+ }
1256
+ extractVisionDescription(body) {
1257
+ if (!body) {
1258
+ return null;
1259
+ }
1260
+ if (typeof body === 'string') {
1261
+ const trimmed = body.trim();
1262
+ return trimmed.length ? trimmed : null;
1263
+ }
1264
+ if (typeof body !== 'object') {
1265
+ return null;
1266
+ }
1267
+ const record = body;
1268
+ const direct = this.extractTextCandidate(record);
1269
+ if (direct) {
1270
+ return direct;
1271
+ }
1272
+ if (record.response && typeof record.response === 'object') {
1273
+ const responseNode = record.response;
1274
+ const nested = this.extractTextCandidate(responseNode);
1275
+ if (nested) {
1276
+ return nested;
1277
+ }
1278
+ const output = responseNode.output;
1279
+ if (Array.isArray(output)) {
1280
+ for (const entry of output) {
1281
+ if (entry && typeof entry === 'object') {
1282
+ const nestedText = this.extractTextCandidate(entry);
1283
+ if (nestedText) {
1284
+ return nestedText;
1285
+ }
1286
+ }
1287
+ }
1288
+ }
1289
+ }
1290
+ if (Array.isArray(record.output)) {
1291
+ for (const entry of record.output) {
1292
+ if (entry && typeof entry === 'object') {
1293
+ const nested = this.extractTextCandidate(entry);
1294
+ if (nested) {
1295
+ return nested;
1296
+ }
1297
+ }
1298
+ }
1299
+ }
1300
+ const choices = record.choices;
1301
+ if (Array.isArray(choices)) {
1302
+ for (const choice of choices) {
1303
+ if (!choice || typeof choice !== 'object') {
1304
+ continue;
1305
+ }
1306
+ const message = choice.message;
1307
+ if (message && typeof message === 'object') {
1308
+ const msg = message;
1309
+ const content = msg.content;
1310
+ if (typeof content === 'string' && content.trim()) {
1311
+ return content.trim();
1312
+ }
1313
+ if (Array.isArray(content)) {
1314
+ for (const part of content) {
1315
+ if (part && typeof part === 'object' && typeof part.text === 'string') {
1316
+ const textValue = part.text.trim();
1317
+ if (textValue) {
1318
+ return textValue;
1319
+ }
1320
+ }
1321
+ }
1322
+ }
1323
+ }
1324
+ }
1325
+ }
1326
+ return null;
1327
+ }
1328
+ extractTextCandidate(record) {
1329
+ const candidates = [
1330
+ { key: 'output_text', allowJson: true },
1331
+ { key: 'text' },
1332
+ { key: 'content' }
1333
+ ];
1334
+ for (const candidate of candidates) {
1335
+ if (!(candidate.key in record)) {
1336
+ continue;
1337
+ }
1338
+ const text = this.normalizeTextCandidateValue(record[candidate.key], candidate.allowJson === true);
1339
+ if (text) {
1340
+ return text;
1341
+ }
1342
+ }
1343
+ return null;
1344
+ }
1345
+ normalizeTextCandidateValue(value, allowJsonStringify = false) {
1346
+ if (!value) {
1347
+ return null;
1348
+ }
1349
+ if (typeof value === 'string') {
1350
+ const trimmed = value.trim();
1351
+ return trimmed.length ? trimmed : null;
1352
+ }
1353
+ if (Array.isArray(value)) {
1354
+ const collected = [];
1355
+ for (const entry of value) {
1356
+ const nested = this.normalizeTextCandidateValue(entry, allowJsonStringify);
1357
+ if (nested) {
1358
+ collected.push(nested);
1359
+ }
1360
+ }
1361
+ return collected.length ? collected.join('\n') : null;
1362
+ }
1363
+ if (typeof value === 'object') {
1364
+ const bag = value;
1365
+ const textField = bag.text;
1366
+ if (typeof textField === 'string' && textField.trim()) {
1367
+ return textField.trim();
1368
+ }
1369
+ const summaryField = bag.summary;
1370
+ if (typeof summaryField === 'string' && summaryField.trim()) {
1371
+ return summaryField.trim();
1372
+ }
1373
+ if ('content' in bag) {
1374
+ const nested = this.normalizeTextCandidateValue(bag.content, allowJsonStringify);
1375
+ if (nested) {
1376
+ return nested;
1377
+ }
1378
+ }
1379
+ if (allowJsonStringify) {
1380
+ try {
1381
+ const serialized = JSON.stringify(value, null, 2);
1382
+ return serialized.trim() || null;
1383
+ }
1384
+ catch {
1385
+ return null;
1386
+ }
1387
+ }
1388
+ }
1389
+ return null;
1390
+ }
988
1391
  async initializeRouteErrorHub() {
989
1392
  try {
990
1393
  this.routeErrorHub = initializeRouteErrorHub({ errorHandlingCenter: this.errorHandling });