@jsonstudio/llms 0.4.3 → 0.4.5

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 (542) hide show
  1. package/README.md +3 -1
  2. package/dist/bridge/routecodex-adapter.js +6 -3
  3. package/dist/config-unified/enhanced-path-resolver.js +14 -6
  4. package/dist/config-unified/unified-config.js +103 -59
  5. package/dist/conversion/codec-registry.js +15 -3
  6. package/dist/conversion/codecs/anthropic-openai-codec.d.ts +3 -13
  7. package/dist/conversion/codecs/anthropic-openai-codec.js +18 -473
  8. package/dist/conversion/codecs/gemini-openai-codec.js +91 -48
  9. package/dist/conversion/codecs/responses-openai-codec.js +9 -2
  10. package/dist/conversion/hub/format-adapters/anthropic-format-adapter.js +3 -0
  11. package/dist/conversion/hub/format-adapters/chat-format-adapter.js +3 -0
  12. package/dist/conversion/hub/format-adapters/gemini-format-adapter.js +3 -0
  13. package/dist/conversion/hub/format-adapters/responses-format-adapter.d.ts +2 -0
  14. package/dist/conversion/hub/format-adapters/responses-format-adapter.js +9 -0
  15. package/dist/conversion/hub/node-support.js +3 -1
  16. package/dist/conversion/hub/pipeline/hub-pipeline.js +41 -37
  17. package/dist/conversion/hub/process/chat-process.js +258 -41
  18. package/dist/conversion/hub/response/provider-response.js +9 -3
  19. package/dist/conversion/hub/response/response-mappers.js +1 -1
  20. package/dist/conversion/hub/response/response-runtime.js +109 -10
  21. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +70 -156
  22. package/dist/conversion/hub/semantic-mappers/chat-mapper.js +63 -52
  23. package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +76 -143
  24. package/dist/conversion/hub/semantic-mappers/responses-mapper.js +40 -160
  25. package/dist/conversion/hub/standardized-bridge.js +3 -0
  26. package/dist/conversion/hub/tool-governance/engine.d.ts +16 -0
  27. package/dist/conversion/hub/tool-governance/engine.js +266 -0
  28. package/dist/conversion/hub/tool-governance/index.d.ts +3 -0
  29. package/dist/conversion/hub/tool-governance/index.js +2 -0
  30. package/dist/conversion/hub/tool-governance/rules.d.ts +2 -0
  31. package/dist/conversion/hub/tool-governance/rules.js +76 -0
  32. package/dist/conversion/hub/tool-governance/types.d.ts +38 -0
  33. package/dist/conversion/index.d.ts +6 -0
  34. package/dist/conversion/index.js +6 -0
  35. package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.d.ts +12 -0
  36. package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.js +100 -0
  37. package/dist/conversion/pipeline/codecs/v2/openai-openai-pipeline.d.ts +15 -0
  38. package/dist/conversion/pipeline/codecs/v2/openai-openai-pipeline.js +174 -0
  39. package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.d.ts +14 -0
  40. package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.js +166 -0
  41. package/dist/conversion/pipeline/codecs/v2/shared/openai-chat-helpers.d.ts +13 -0
  42. package/dist/conversion/pipeline/codecs/v2/shared/openai-chat-helpers.js +66 -0
  43. package/dist/conversion/pipeline/hooks/adapter-context.d.ts +7 -0
  44. package/dist/conversion/pipeline/hooks/adapter-context.js +18 -0
  45. package/dist/conversion/pipeline/hooks/protocol-hooks.d.ts +67 -0
  46. package/dist/conversion/pipeline/hooks/protocol-hooks.js +1 -0
  47. package/dist/conversion/pipeline/index.d.ts +35 -0
  48. package/dist/conversion/pipeline/index.js +103 -0
  49. package/dist/conversion/pipeline/meta/meta-bag.d.ts +20 -0
  50. package/dist/conversion/pipeline/meta/meta-bag.js +81 -0
  51. package/dist/conversion/pipeline/schema/canonical-chat.d.ts +18 -0
  52. package/dist/conversion/pipeline/schema/canonical-chat.js +1 -0
  53. package/dist/conversion/pipeline/schema/index.d.ts +1 -0
  54. package/dist/conversion/pipeline/schema/index.js +1 -0
  55. package/dist/conversion/responses/responses-openai-bridge.d.ts +11 -58
  56. package/dist/conversion/responses/responses-openai-bridge.js +157 -1144
  57. package/dist/conversion/shared/anthropic-message-utils.d.ts +12 -0
  58. package/dist/conversion/shared/anthropic-message-utils.js +587 -0
  59. package/dist/conversion/shared/bridge-actions.d.ts +39 -0
  60. package/dist/conversion/shared/bridge-actions.js +709 -0
  61. package/dist/conversion/shared/{responses-conversation-store.d.ts → bridge-conversation-store.d.ts} +7 -7
  62. package/dist/conversion/shared/bridge-conversation-store.js +279 -0
  63. package/dist/conversion/shared/bridge-id-utils.js +42 -0
  64. package/dist/conversion/shared/bridge-instructions.d.ts +1 -0
  65. package/dist/conversion/shared/bridge-instructions.js +113 -0
  66. package/dist/conversion/shared/bridge-message-types.d.ts +39 -0
  67. package/dist/conversion/shared/bridge-message-types.js +1 -0
  68. package/dist/conversion/shared/bridge-message-utils.d.ts +22 -0
  69. package/dist/conversion/shared/bridge-message-utils.js +473 -0
  70. package/dist/conversion/shared/bridge-metadata.d.ts +1 -0
  71. package/dist/conversion/shared/bridge-metadata.js +1 -0
  72. package/dist/conversion/shared/bridge-policies.d.ts +18 -0
  73. package/dist/conversion/shared/bridge-policies.js +276 -0
  74. package/dist/conversion/shared/bridge-request-adapter.d.ts +28 -0
  75. package/dist/conversion/shared/bridge-request-adapter.js +430 -0
  76. package/dist/conversion/shared/chat-output-normalizer.d.ts +4 -0
  77. package/dist/conversion/shared/chat-output-normalizer.js +56 -0
  78. package/dist/conversion/shared/chat-request-filters.js +24 -1
  79. package/dist/conversion/shared/gemini-tool-utils.d.ts +5 -0
  80. package/dist/conversion/shared/gemini-tool-utils.js +130 -0
  81. package/dist/conversion/shared/metadata-passthrough.d.ts +11 -0
  82. package/dist/conversion/shared/metadata-passthrough.js +57 -0
  83. package/dist/conversion/shared/output-content-normalizer.d.ts +12 -0
  84. package/dist/conversion/shared/output-content-normalizer.js +119 -0
  85. package/dist/conversion/shared/reasoning-normalizer.d.ts +21 -0
  86. package/dist/conversion/shared/reasoning-normalizer.js +368 -0
  87. package/dist/conversion/shared/reasoning-tool-normalizer.d.ts +12 -0
  88. package/dist/conversion/shared/reasoning-tool-normalizer.js +132 -0
  89. package/dist/conversion/shared/reasoning-tool-parser.d.ts +10 -0
  90. package/dist/conversion/shared/reasoning-tool-parser.js +95 -0
  91. package/dist/conversion/shared/reasoning-utils.d.ts +2 -0
  92. package/dist/conversion/shared/reasoning-utils.js +42 -0
  93. package/dist/conversion/shared/responses-conversation-store.js +5 -11
  94. package/dist/conversion/shared/responses-message-utils.d.ts +15 -0
  95. package/dist/conversion/shared/responses-message-utils.js +206 -0
  96. package/dist/conversion/shared/responses-output-builder.d.ts +15 -0
  97. package/dist/conversion/shared/responses-output-builder.js +179 -0
  98. package/dist/conversion/shared/responses-output-utils.d.ts +7 -0
  99. package/dist/conversion/shared/responses-output-utils.js +108 -0
  100. package/dist/conversion/shared/responses-request-adapter.d.ts +3 -41
  101. package/dist/conversion/shared/responses-request-adapter.js +9 -40
  102. package/dist/conversion/shared/responses-response-utils.d.ts +3 -0
  103. package/dist/conversion/shared/responses-response-utils.js +209 -0
  104. package/dist/conversion/shared/responses-tool-utils.d.ts +12 -0
  105. package/dist/conversion/shared/responses-tool-utils.js +90 -0
  106. package/dist/conversion/shared/responses-types.d.ts +33 -0
  107. package/dist/conversion/shared/responses-types.js +1 -0
  108. package/dist/conversion/shared/tool-call-utils.d.ts +11 -0
  109. package/dist/conversion/shared/tool-call-utils.js +56 -0
  110. package/dist/conversion/shared/tool-mapping.d.ts +9 -0
  111. package/dist/conversion/shared/tool-mapping.js +124 -0
  112. package/dist/conversion/shared/tool-normalizers.d.ts +4 -0
  113. package/dist/conversion/shared/tool-normalizers.js +84 -0
  114. package/dist/router/virtual-router/bootstrap.js +18 -3
  115. package/dist/router/virtual-router/provider-registry.js +4 -2
  116. package/dist/router/virtual-router/types.d.ts +6 -0
  117. package/dist/sse/index.d.ts +38 -2
  118. package/dist/sse/index.js +27 -0
  119. package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.d.ts +12 -9
  120. package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.js +106 -73
  121. package/dist/sse/json-to-sse/chat-json-to-sse-converter.js +6 -2
  122. package/dist/sse/json-to-sse/gemini-json-to-sse-converter.d.ts +14 -0
  123. package/dist/sse/json-to-sse/gemini-json-to-sse-converter.js +99 -0
  124. package/dist/sse/json-to-sse/index.d.ts +2 -1
  125. package/dist/sse/json-to-sse/index.js +2 -0
  126. package/dist/sse/json-to-sse/sequencers/anthropic-sequencer.d.ts +13 -0
  127. package/dist/sse/json-to-sse/sequencers/anthropic-sequencer.js +150 -0
  128. package/dist/sse/json-to-sse/sequencers/chat-sequencer.d.ts +3 -1
  129. package/dist/sse/json-to-sse/sequencers/chat-sequencer.js +49 -3
  130. package/dist/sse/json-to-sse/sequencers/gemini-sequencer.d.ts +10 -0
  131. package/dist/sse/json-to-sse/sequencers/gemini-sequencer.js +95 -0
  132. package/dist/sse/json-to-sse/sequencers/responses-sequencer.js +31 -5
  133. package/dist/sse/registry/sse-codec-registry.d.ts +1 -1
  134. package/dist/sse/registry/sse-codec-registry.js +30 -1
  135. package/dist/sse/shared/reasoning-dispatcher.d.ts +10 -0
  136. package/dist/sse/shared/reasoning-dispatcher.js +25 -0
  137. package/dist/sse/shared/responses-output-normalizer.d.ts +12 -0
  138. package/dist/sse/shared/responses-output-normalizer.js +45 -0
  139. package/dist/sse/shared/serializers/anthropic-event-serializer.d.ts +2 -0
  140. package/dist/sse/shared/serializers/anthropic-event-serializer.js +9 -0
  141. package/dist/sse/shared/serializers/gemini-event-serializer.d.ts +2 -0
  142. package/dist/sse/shared/serializers/gemini-event-serializer.js +5 -0
  143. package/dist/sse/shared/serializers/index.d.ts +2 -0
  144. package/dist/sse/shared/serializers/index.js +2 -0
  145. package/dist/sse/shared/writer.d.ts +17 -1
  146. package/dist/sse/shared/writer.js +37 -1
  147. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +9 -11
  148. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +92 -127
  149. package/dist/sse/sse-to-json/builders/anthropic-response-builder.d.ts +16 -0
  150. package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +151 -0
  151. package/dist/sse/sse-to-json/builders/response-builder.d.ts +1 -1
  152. package/dist/sse/sse-to-json/builders/response-builder.js +29 -7
  153. package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +8 -0
  154. package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +116 -26
  155. package/dist/sse/sse-to-json/gemini-sse-to-json-converter.d.ts +13 -0
  156. package/dist/sse/sse-to-json/gemini-sse-to-json-converter.js +160 -0
  157. package/dist/sse/sse-to-json/index.d.ts +2 -1
  158. package/dist/sse/sse-to-json/index.js +2 -0
  159. package/dist/sse/sse-to-json/parsers/sse-parser.js +73 -13
  160. package/dist/sse/sse-to-json/responses-sse-to-json-converter.d.ts +1 -0
  161. package/dist/sse/sse-to-json/responses-sse-to-json-converter.js +10 -8
  162. package/dist/sse/types/anthropic-types.d.ts +119 -36
  163. package/dist/sse/types/anthropic-types.js +8 -5
  164. package/dist/sse/types/chat-types.d.ts +19 -6
  165. package/dist/sse/types/chat-types.js +2 -1
  166. package/dist/sse/types/conversion-context.d.ts +14 -11
  167. package/dist/sse/types/core-interfaces.d.ts +7 -3
  168. package/dist/sse/types/gemini-types.d.ts +116 -0
  169. package/dist/sse/types/gemini-types.js +5 -0
  170. package/dist/sse/types/index.d.ts +5 -2
  171. package/dist/sse/types/index.js +2 -0
  172. package/dist/sse/types/responses-types.d.ts +20 -20
  173. package/dist/sse/types/sse-events.d.ts +4 -3
  174. package/dist/sse/types/stream-state.d.ts +34 -39
  175. package/dist/sse/types/utility-types.d.ts +47 -43
  176. package/dist/sse/types/utility-types.js +10 -13
  177. package/dist/tools/tool-registry.js +156 -98
  178. package/package.json +7 -7
  179. package/dist/api/index.d.ts +0 -10
  180. package/dist/api/index.js +0 -11
  181. package/dist/api/llmswitch-config.d.ts +0 -15
  182. package/dist/api/llmswitch-config.js +0 -415
  183. package/dist/api/llmswitch-types.d.ts +0 -412
  184. package/dist/api/llmswitch-types.js +0 -60
  185. package/dist/bridge/routecodex-adapter.d.ts +0 -74
  186. package/dist/config/index.d.ts +0 -3
  187. package/dist/config/index.js +0 -5
  188. package/dist/config-unified/enhanced-path-resolver.d.ts +0 -5
  189. package/dist/config-unified/unified-config.d.ts +0 -26
  190. package/dist/conversion/codec-registry.d.ts +0 -10
  191. package/dist/conversion/codecs/gemini-openai-codec.d.ts +0 -16
  192. package/dist/conversion/codecs/openai-openai-codec.d.ts +0 -12
  193. package/dist/conversion/codecs/responses-openai-codec.d.ts +0 -12
  194. package/dist/conversion/config/config-manager.d.ts +0 -212
  195. package/dist/conversion/conversion-v3/adapters/index.d.ts +0 -2
  196. package/dist/conversion/conversion-v3/adapters/index.js +0 -1
  197. package/dist/conversion/conversion-v3/adapters/v3-to-standard-adapter.d.ts +0 -38
  198. package/dist/conversion/conversion-v3/adapters/v3-to-standard-adapter.js +0 -55
  199. package/dist/conversion/conversion-v3/compatibility/compatibility-profiles.d.ts +0 -22
  200. package/dist/conversion/conversion-v3/compatibility/compatibility-profiles.js +0 -84
  201. package/dist/conversion/conversion-v3/compatibility/compatibility-stages.d.ts +0 -4
  202. package/dist/conversion/conversion-v3/compatibility/compatibility-stages.js +0 -285
  203. package/dist/conversion/conversion-v3/compatibility/index.d.ts +0 -3
  204. package/dist/conversion/conversion-v3/compatibility/index.js +0 -2
  205. package/dist/conversion/conversion-v3/config/default-configs.d.ts +0 -48
  206. package/dist/conversion/conversion-v3/config/default-configs.js +0 -1007
  207. package/dist/conversion/conversion-v3/config/index.d.ts +0 -5
  208. package/dist/conversion/conversion-v3/config/index.js +0 -5
  209. package/dist/conversion/conversion-v3/config/pipeline-config-manager.d.ts +0 -49
  210. package/dist/conversion/conversion-v3/config/pipeline-config-manager.js +0 -65
  211. package/dist/conversion/conversion-v3/index.d.ts +0 -11
  212. package/dist/conversion/conversion-v3/index.js +0 -17
  213. package/dist/conversion/conversion-v3/nodes/index.d.ts +0 -56
  214. package/dist/conversion/conversion-v3/nodes/index.js +0 -149
  215. package/dist/conversion/conversion-v3/nodes/input/anthropic-input-node.d.ts +0 -25
  216. package/dist/conversion/conversion-v3/nodes/input/anthropic-input-node.js +0 -56
  217. package/dist/conversion/conversion-v3/nodes/input/base-input-node.d.ts +0 -75
  218. package/dist/conversion/conversion-v3/nodes/input/base-input-node.js +0 -237
  219. package/dist/conversion/conversion-v3/nodes/input/chat-input-node.d.ts +0 -25
  220. package/dist/conversion/conversion-v3/nodes/input/chat-input-node.js +0 -56
  221. package/dist/conversion/conversion-v3/nodes/input/chat-shape-helpers.d.ts +0 -4
  222. package/dist/conversion/conversion-v3/nodes/input/chat-shape-helpers.js +0 -197
  223. package/dist/conversion/conversion-v3/nodes/input/gemini-input-node.d.ts +0 -16
  224. package/dist/conversion/conversion-v3/nodes/input/gemini-input-node.js +0 -125
  225. package/dist/conversion/conversion-v3/nodes/input/index.d.ts +0 -8
  226. package/dist/conversion/conversion-v3/nodes/input/index.js +0 -8
  227. package/dist/conversion/conversion-v3/nodes/input/input-decision.d.ts +0 -46
  228. package/dist/conversion/conversion-v3/nodes/input/input-decision.js +0 -125
  229. package/dist/conversion/conversion-v3/nodes/input/responses-input-node.d.ts +0 -20
  230. package/dist/conversion/conversion-v3/nodes/input/responses-input-node.js +0 -51
  231. package/dist/conversion/conversion-v3/nodes/output/anthropic-output-node.d.ts +0 -71
  232. package/dist/conversion/conversion-v3/nodes/output/anthropic-output-node.js +0 -320
  233. package/dist/conversion/conversion-v3/nodes/output/base-output-node.d.ts +0 -116
  234. package/dist/conversion/conversion-v3/nodes/output/base-output-node.js +0 -512
  235. package/dist/conversion/conversion-v3/nodes/output/index.d.ts +0 -7
  236. package/dist/conversion/conversion-v3/nodes/output/index.js +0 -7
  237. package/dist/conversion/conversion-v3/nodes/output/openai-output-node.d.ts +0 -71
  238. package/dist/conversion/conversion-v3/nodes/output/openai-output-node.js +0 -293
  239. package/dist/conversion/conversion-v3/nodes/output/output-decision.d.ts +0 -68
  240. package/dist/conversion/conversion-v3/nodes/output/output-decision.js +0 -161
  241. package/dist/conversion/conversion-v3/nodes/output/responses-output-node.d.ts +0 -64
  242. package/dist/conversion/conversion-v3/nodes/output/responses-output-node.js +0 -323
  243. package/dist/conversion/conversion-v3/nodes/process/base-process-node.d.ts +0 -72
  244. package/dist/conversion/conversion-v3/nodes/process/base-process-node.js +0 -246
  245. package/dist/conversion/conversion-v3/nodes/process/chat-process-node.d.ts +0 -135
  246. package/dist/conversion/conversion-v3/nodes/process/chat-process-node.js +0 -854
  247. package/dist/conversion/conversion-v3/nodes/process/compatibility-process-node.d.ts +0 -29
  248. package/dist/conversion/conversion-v3/nodes/process/compatibility-process-node.js +0 -181
  249. package/dist/conversion/conversion-v3/nodes/process/index.d.ts +0 -10
  250. package/dist/conversion/conversion-v3/nodes/process/index.js +0 -10
  251. package/dist/conversion/conversion-v3/nodes/process/passthrough-process-node.d.ts +0 -59
  252. package/dist/conversion/conversion-v3/nodes/process/passthrough-process-node.js +0 -243
  253. package/dist/conversion/conversion-v3/nodes/process/response-process-node.d.ts +0 -17
  254. package/dist/conversion/conversion-v3/nodes/process/response-process-node.js +0 -213
  255. package/dist/conversion/conversion-v3/nodes/process/tool-process-node.d.ts +0 -30
  256. package/dist/conversion/conversion-v3/nodes/process/tool-process-node.js +0 -360
  257. package/dist/conversion/conversion-v3/nodes/process/virtual-router-process-node.d.ts +0 -40
  258. package/dist/conversion/conversion-v3/nodes/process/virtual-router-process-node.js +0 -430
  259. package/dist/conversion/conversion-v3/nodes/response/anthropic-response-input-node.d.ts +0 -12
  260. package/dist/conversion/conversion-v3/nodes/response/anthropic-response-input-node.js +0 -129
  261. package/dist/conversion/conversion-v3/nodes/response/chat-to-responses-response-node.d.ts +0 -15
  262. package/dist/conversion/conversion-v3/nodes/response/chat-to-responses-response-node.js +0 -57
  263. package/dist/conversion/conversion-v3/nodes/response/index.d.ts +0 -4
  264. package/dist/conversion/conversion-v3/nodes/response/index.js +0 -4
  265. package/dist/conversion/conversion-v3/nodes/response/openai-response-input-node.d.ts +0 -15
  266. package/dist/conversion/conversion-v3/nodes/response/openai-response-input-node.js +0 -87
  267. package/dist/conversion/conversion-v3/nodes/response/response-utils.d.ts +0 -1
  268. package/dist/conversion/conversion-v3/nodes/response/response-utils.js +0 -1
  269. package/dist/conversion/conversion-v3/nodes/response/responses-response-input-node.d.ts +0 -12
  270. package/dist/conversion/conversion-v3/nodes/response/responses-response-input-node.js +0 -67
  271. package/dist/conversion/conversion-v3/nodes/sse/index.d.ts +0 -3
  272. package/dist/conversion/conversion-v3/nodes/sse/index.js +0 -3
  273. package/dist/conversion/conversion-v3/nodes/sse/sse-input-node.d.ts +0 -27
  274. package/dist/conversion/conversion-v3/nodes/sse/sse-input-node.js +0 -165
  275. package/dist/conversion/conversion-v3/nodes/sse/sse-output-node.d.ts +0 -19
  276. package/dist/conversion/conversion-v3/nodes/sse/sse-output-node.js +0 -267
  277. package/dist/conversion/conversion-v3/nodes/sse/sse-passthrough-node.d.ts +0 -18
  278. package/dist/conversion/conversion-v3/nodes/sse/sse-passthrough-node.js +0 -48
  279. package/dist/conversion/conversion-v3/pipelines/index.d.ts +0 -6
  280. package/dist/conversion/conversion-v3/pipelines/index.js +0 -6
  281. package/dist/conversion/conversion-v3/pipelines/super-pipeline.d.ts +0 -112
  282. package/dist/conversion/conversion-v3/pipelines/super-pipeline.js +0 -566
  283. package/dist/conversion/conversion-v3/response/provider-response-converter.d.ts +0 -28
  284. package/dist/conversion/conversion-v3/response/provider-response-converter.js +0 -249
  285. package/dist/conversion/conversion-v3/sse/index.d.ts +0 -140
  286. package/dist/conversion/conversion-v3/sse/index.js +0 -115
  287. package/dist/conversion/conversion-v3/sse/json-to-sse/anthropic-json-to-sse-converter.d.ts +0 -11
  288. package/dist/conversion/conversion-v3/sse/json-to-sse/anthropic-json-to-sse-converter.js +0 -79
  289. package/dist/conversion/conversion-v3/sse/json-to-sse/chat-json-to-sse-converter.d.ts +0 -79
  290. package/dist/conversion/conversion-v3/sse/json-to-sse/chat-json-to-sse-converter.js +0 -296
  291. package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/chat.d.ts +0 -55
  292. package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/chat.js +0 -233
  293. package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/responses.d.ts +0 -99
  294. package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/responses.js +0 -599
  295. package/dist/conversion/conversion-v3/sse/json-to-sse/index.d.ts +0 -6
  296. package/dist/conversion/conversion-v3/sse/json-to-sse/index.js +0 -7
  297. package/dist/conversion/conversion-v3/sse/json-to-sse/responses-json-to-sse-converter.d.ts +0 -79
  298. package/dist/conversion/conversion-v3/sse/json-to-sse/responses-json-to-sse-converter.js +0 -322
  299. package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/chat-sequencer.d.ts +0 -37
  300. package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/chat-sequencer.js +0 -218
  301. package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/responses-sequencer.d.ts +0 -40
  302. package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/responses-sequencer.js +0 -263
  303. package/dist/conversion/conversion-v3/sse/registry/sse-codec-registry.d.ts +0 -32
  304. package/dist/conversion/conversion-v3/sse/registry/sse-codec-registry.js +0 -106
  305. package/dist/conversion/conversion-v3/sse/shared/chat-serializer.d.ts +0 -4
  306. package/dist/conversion/conversion-v3/sse/shared/chat-serializer.js +0 -40
  307. package/dist/conversion/conversion-v3/sse/shared/constants.d.ts +0 -272
  308. package/dist/conversion/conversion-v3/sse/shared/constants.js +0 -321
  309. package/dist/conversion/conversion-v3/sse/shared/serializers/base-serializer.d.ts +0 -158
  310. package/dist/conversion/conversion-v3/sse/shared/serializers/base-serializer.js +0 -210
  311. package/dist/conversion/conversion-v3/sse/shared/serializers/chat-event-serializer.d.ts +0 -82
  312. package/dist/conversion/conversion-v3/sse/shared/serializers/chat-event-serializer.js +0 -275
  313. package/dist/conversion/conversion-v3/sse/shared/serializers/index.d.ts +0 -39
  314. package/dist/conversion/conversion-v3/sse/shared/serializers/index.js +0 -54
  315. package/dist/conversion/conversion-v3/sse/shared/serializers/responses-event-serializer.d.ts +0 -123
  316. package/dist/conversion/conversion-v3/sse/shared/serializers/responses-event-serializer.js +0 -356
  317. package/dist/conversion/conversion-v3/sse/shared/serializers/types.d.ts +0 -51
  318. package/dist/conversion/conversion-v3/sse/shared/serializers/types.js +0 -4
  319. package/dist/conversion/conversion-v3/sse/shared/utils.d.ts +0 -254
  320. package/dist/conversion/conversion-v3/sse/shared/utils.js +0 -543
  321. package/dist/conversion/conversion-v3/sse/shared/writer.d.ts +0 -111
  322. package/dist/conversion/conversion-v3/sse/shared/writer.js +0 -268
  323. package/dist/conversion/conversion-v3/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +0 -13
  324. package/dist/conversion/conversion-v3/sse/sse-to-json/anthropic-sse-to-json-converter.js +0 -139
  325. package/dist/conversion/conversion-v3/sse/sse-to-json/builders/response-builder.d.ts +0 -165
  326. package/dist/conversion/conversion-v3/sse/sse-to-json/builders/response-builder.js +0 -776
  327. package/dist/conversion/conversion-v3/sse/sse-to-json/chat-sse-to-json-converter.d.ts +0 -106
  328. package/dist/conversion/conversion-v3/sse/sse-to-json/chat-sse-to-json-converter.js +0 -540
  329. package/dist/conversion/conversion-v3/sse/sse-to-json/index.d.ts +0 -6
  330. package/dist/conversion/conversion-v3/sse/sse-to-json/index.js +0 -7
  331. package/dist/conversion/conversion-v3/sse/sse-to-json/parsers/sse-parser.d.ts +0 -73
  332. package/dist/conversion/conversion-v3/sse/sse-to-json/parsers/sse-parser.js +0 -332
  333. package/dist/conversion/conversion-v3/sse/sse-to-json/responses-sse-to-json-converter.d.ts +0 -59
  334. package/dist/conversion/conversion-v3/sse/sse-to-json/responses-sse-to-json-converter.js +0 -270
  335. package/dist/conversion/conversion-v3/sse/types/anthropic-types.d.ts +0 -87
  336. package/dist/conversion/conversion-v3/sse/types/anthropic-types.js +0 -5
  337. package/dist/conversion/conversion-v3/sse/types/chat-types.d.ts +0 -308
  338. package/dist/conversion/conversion-v3/sse/types/chat-types.js +0 -32
  339. package/dist/conversion/conversion-v3/sse/types/conversion-context.d.ts +0 -211
  340. package/dist/conversion/conversion-v3/sse/types/conversion-context.js +0 -20
  341. package/dist/conversion/conversion-v3/sse/types/core-interfaces.d.ts +0 -90
  342. package/dist/conversion/conversion-v3/sse/types/core-interfaces.js +0 -5
  343. package/dist/conversion/conversion-v3/sse/types/index.d.ts +0 -14
  344. package/dist/conversion/conversion-v3/sse/types/index.js +0 -7
  345. package/dist/conversion/conversion-v3/sse/types/responses-types.d.ts +0 -328
  346. package/dist/conversion/conversion-v3/sse/types/responses-types.js +0 -38
  347. package/dist/conversion/conversion-v3/sse/types/sse-events.d.ts +0 -180
  348. package/dist/conversion/conversion-v3/sse/types/sse-events.js +0 -150
  349. package/dist/conversion/conversion-v3/sse/types/stream-state.d.ts +0 -204
  350. package/dist/conversion/conversion-v3/sse/types/stream-state.js +0 -44
  351. package/dist/conversion/conversion-v3/sse/types/utility-types.d.ts +0 -230
  352. package/dist/conversion/conversion-v3/sse/types/utility-types.js +0 -49
  353. package/dist/conversion/conversion-v3/standards/context-adapter.d.ts +0 -146
  354. package/dist/conversion/conversion-v3/standards/context-adapter.js +0 -438
  355. package/dist/conversion/conversion-v3/standards/errors.d.ts +0 -38
  356. package/dist/conversion/conversion-v3/standards/errors.js +0 -27
  357. package/dist/conversion/conversion-v3/standards/index.d.ts +0 -15
  358. package/dist/conversion/conversion-v3/standards/index.js +0 -11
  359. package/dist/conversion/conversion-v3/standards/node-capabilities.d.ts +0 -123
  360. package/dist/conversion/conversion-v3/standards/node-capabilities.js +0 -330
  361. package/dist/conversion/conversion-v3/standards/pipeline-context.d.ts +0 -237
  362. package/dist/conversion/conversion-v3/standards/pipeline-context.js +0 -84
  363. package/dist/conversion/conversion-v3/standards/pipeline-node.d.ts +0 -196
  364. package/dist/conversion/conversion-v3/standards/pipeline-node.js +0 -316
  365. package/dist/conversion/conversion-v3/standards/snapshot-handles.d.ts +0 -24
  366. package/dist/conversion/conversion-v3/standards/snapshot-handles.js +0 -49
  367. package/dist/conversion/conversion-v3/types/config-types.d.ts +0 -242
  368. package/dist/conversion/conversion-v3/types/config-types.js +0 -13
  369. package/dist/conversion/conversion-v3/types/index.d.ts +0 -8
  370. package/dist/conversion/conversion-v3/types/index.js +0 -11
  371. package/dist/conversion/conversion-v3/types/node-types.d.ts +0 -211
  372. package/dist/conversion/conversion-v3/types/node-types.js +0 -20
  373. package/dist/conversion/conversion-v3/types/pipeline-types.d.ts +0 -246
  374. package/dist/conversion/conversion-v3/types/pipeline-types.js +0 -26
  375. package/dist/conversion/conversion-v3/types/request-types.d.ts +0 -293
  376. package/dist/conversion/conversion-v3/types/request-types.js +0 -26
  377. package/dist/conversion/conversion-v3/utils/provider-payload-sanitizer.d.ts +0 -10
  378. package/dist/conversion/conversion-v3/utils/provider-payload-sanitizer.js +0 -103
  379. package/dist/conversion/conversion-v3/validations/index.d.ts +0 -8
  380. package/dist/conversion/conversion-v3/validations/index.js +0 -7
  381. package/dist/conversion/conversion-v3/validations/node-graph-validator.d.ts +0 -116
  382. package/dist/conversion/conversion-v3/validations/node-graph-validator.js +0 -505
  383. package/dist/conversion/conversion-v3/validations/tool-governance-enforcer.d.ts +0 -139
  384. package/dist/conversion/conversion-v3/validations/tool-governance-enforcer.js +0 -338
  385. package/dist/conversion/hub/config/types.d.ts +0 -26
  386. package/dist/conversion/hub/core/detour-registry.d.ts +0 -9
  387. package/dist/conversion/hub/core/hub-context.d.ts +0 -21
  388. package/dist/conversion/hub/core/index.d.ts +0 -3
  389. package/dist/conversion/hub/core/stage-driver.d.ts +0 -30
  390. package/dist/conversion/hub/format-adapters/anthropic-format-adapter.d.ts +0 -16
  391. package/dist/conversion/hub/format-adapters/chat-format-adapter.d.ts +0 -17
  392. package/dist/conversion/hub/format-adapters/gemini-format-adapter.d.ts +0 -16
  393. package/dist/conversion/hub/format-adapters/index.d.ts +0 -21
  394. package/dist/conversion/hub/hub-feature.d.ts +0 -1
  395. package/dist/conversion/hub/node-support.d.ts +0 -19
  396. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +0 -68
  397. package/dist/conversion/hub/pipelines/inbound.d.ts +0 -22
  398. package/dist/conversion/hub/pipelines/outbound.d.ts +0 -22
  399. package/dist/conversion/hub/process/chat-process.d.ts +0 -13
  400. package/dist/conversion/hub/registry.d.ts +0 -28
  401. package/dist/conversion/hub/response/chat-response-utils.d.ts +0 -6
  402. package/dist/conversion/hub/response/provider-response.d.ts +0 -20
  403. package/dist/conversion/hub/response/response-mappers.d.ts +0 -19
  404. package/dist/conversion/hub/response/response-runtime.d.ts +0 -3
  405. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.d.ts +0 -7
  406. package/dist/conversion/hub/semantic-mappers/chat-mapper.d.ts +0 -7
  407. package/dist/conversion/hub/semantic-mappers/gemini-mapper.d.ts +0 -7
  408. package/dist/conversion/hub/semantic-mappers/index.d.ts +0 -4
  409. package/dist/conversion/hub/semantic-mappers/responses-mapper.d.ts +0 -21
  410. package/dist/conversion/hub/snapshot-recorder.d.ts +0 -12
  411. package/dist/conversion/hub/standardized-bridge.d.ts +0 -12
  412. package/dist/conversion/hub/types/chat-envelope.d.ts +0 -67
  413. package/dist/conversion/hub/types/chat-schema.d.ts +0 -112
  414. package/dist/conversion/hub/types/errors.d.ts +0 -5
  415. package/dist/conversion/hub/types/format-envelope.d.ts +0 -7
  416. package/dist/conversion/hub/types/index.d.ts +0 -6
  417. package/dist/conversion/hub/types/json.d.ts +0 -9
  418. package/dist/conversion/hub/types/node.d.ts +0 -31
  419. package/dist/conversion/hub/types/standardized.d.ts +0 -94
  420. package/dist/conversion/schema-validator.d.ts +0 -7
  421. package/dist/conversion/shared/args-mapping.d.ts +0 -18
  422. package/dist/conversion/shared/chat-request-filters.d.ts +0 -9
  423. package/dist/conversion/shared/jsonish.d.ts +0 -3
  424. package/dist/conversion/shared/mcp-injection.d.ts +0 -2
  425. package/dist/conversion/shared/media.d.ts +0 -1
  426. package/dist/conversion/shared/openai-finalizer.d.ts +0 -9
  427. package/dist/conversion/shared/openai-message-normalize.d.ts +0 -1
  428. package/dist/conversion/shared/payload-budget.d.ts +0 -13
  429. package/dist/conversion/shared/reasoning-mapping.d.ts +0 -5
  430. package/dist/conversion/shared/responses-instructions.d.ts +0 -1
  431. package/dist/conversion/shared/responses-metadata.d.ts +0 -1
  432. package/dist/conversion/shared/snapshot-hooks.d.ts +0 -12
  433. package/dist/conversion/shared/streaming-text-extractor.d.ts +0 -26
  434. package/dist/conversion/shared/text-markup-normalizer.d.ts +0 -9
  435. package/dist/conversion/shared/tool-canonicalizer.d.ts +0 -2
  436. package/dist/conversion/shared/tool-filter-pipeline.d.ts +0 -17
  437. package/dist/conversion/shared/tool-governor.d.ts +0 -27
  438. package/dist/conversion/shared/tool-harvester.d.ts +0 -31
  439. package/dist/conversion/shared/tooling.d.ts +0 -26
  440. package/dist/conversion/types.d.ts +0 -33
  441. package/dist/core/index.d.ts +0 -6
  442. package/dist/core/index.js +0 -9
  443. package/dist/core/llmswitch-engine-v2.d.ts +0 -132
  444. package/dist/core/llmswitch-engine-v2.js +0 -649
  445. package/dist/core/llmswitch-factory-v2.d.ts +0 -123
  446. package/dist/core/llmswitch-factory-v2.js +0 -521
  447. package/dist/endpoints/base-endpoint-handler.d.ts +0 -128
  448. package/dist/endpoints/base-endpoint-handler.js +0 -545
  449. package/dist/endpoints/chat-endpoint-handler.d.ts +0 -115
  450. package/dist/endpoints/chat-endpoint-handler.js +0 -218
  451. package/dist/endpoints/endpoint-router.d.ts +0 -127
  452. package/dist/endpoints/endpoint-router.js +0 -438
  453. package/dist/endpoints/index.d.ts +0 -13
  454. package/dist/endpoints/index.js +0 -11
  455. package/dist/endpoints/messages-endpoint-handler.d.ts +0 -171
  456. package/dist/endpoints/messages-endpoint-handler.js +0 -238
  457. package/dist/endpoints/responses-endpoint-handler.d.ts +0 -147
  458. package/dist/endpoints/responses-endpoint-handler.js +0 -233
  459. package/dist/filters/builtin/add-fields-filter.d.ts +0 -8
  460. package/dist/filters/builtin/blacklist-filter.d.ts +0 -8
  461. package/dist/filters/builtin/whitelist-filter.d.ts +0 -8
  462. package/dist/filters/engine.d.ts +0 -16
  463. package/dist/filters/index.d.ts +0 -19
  464. package/dist/filters/special/request-streaming-to-nonstreaming.d.ts +0 -12
  465. package/dist/filters/special/request-tool-choice-policy.d.ts +0 -11
  466. package/dist/filters/special/request-tool-list-filter.d.ts +0 -11
  467. package/dist/filters/special/request-toolcalls-stringify.d.ts +0 -10
  468. package/dist/filters/special/request-tools-normalize.d.ts +0 -12
  469. package/dist/filters/special/response-finish-invariants.d.ts +0 -11
  470. package/dist/filters/special/response-openai-to-responses-bridge.d.ts +0 -13
  471. package/dist/filters/special/response-tool-arguments-blacklist.d.ts +0 -12
  472. package/dist/filters/special/response-tool-arguments-schema-converge.d.ts +0 -13
  473. package/dist/filters/special/response-tool-arguments-stringify.d.ts +0 -9
  474. package/dist/filters/special/response-tool-arguments-toon-decode.d.ts +0 -10
  475. package/dist/filters/special/response-tool-arguments-whitelist.d.ts +0 -11
  476. package/dist/filters/special/response-tool-text-canonicalize.d.ts +0 -10
  477. package/dist/filters/special/tool-filter-hooks.d.ts +0 -19
  478. package/dist/filters/special/tool-post-constraints.d.ts +0 -31
  479. package/dist/filters/types.d.ts +0 -68
  480. package/dist/filters/utils/fieldmap-loader.d.ts +0 -2
  481. package/dist/filters/utils/snapshot-writer.d.ts +0 -10
  482. package/dist/guidance/index.d.ts +0 -3
  483. package/dist/hooks/hooks-integration.d.ts +0 -161
  484. package/dist/hooks/hooks-integration.js +0 -519
  485. package/dist/hooks/index.d.ts +0 -10
  486. package/dist/hooks/index.js +0 -13
  487. package/dist/html-to-markdown.d.ts +0 -5
  488. package/dist/html-to-markdown.js +0 -66
  489. package/dist/http/sse-response.d.ts +0 -22
  490. package/dist/router/virtual-router/bootstrap.d.ts +0 -6
  491. package/dist/router/virtual-router/classifier.d.ts +0 -10
  492. package/dist/router/virtual-router/engine.d.ts +0 -35
  493. package/dist/router/virtual-router/error-center.d.ts +0 -10
  494. package/dist/router/virtual-router/features.d.ts +0 -3
  495. package/dist/router/virtual-router/health-manager.d.ts +0 -18
  496. package/dist/router/virtual-router/load-balancer.d.ts +0 -18
  497. package/dist/router/virtual-router/provider-registry.d.ts +0 -11
  498. package/dist/sse/json-to-sse/chat-json-to-sse-converter.d.ts +0 -79
  499. package/dist/sse/json-to-sse/event-generators/chat.d.ts +0 -55
  500. package/dist/sse/json-to-sse/event-generators/responses.d.ts +0 -99
  501. package/dist/sse/json-to-sse/responses-json-to-sse-converter.d.ts +0 -79
  502. package/dist/sse/json-to-sse/sequencers/responses-sequencer.d.ts +0 -40
  503. package/dist/sse/shared/chat-serializer.d.ts +0 -4
  504. package/dist/sse/shared/constants.d.ts +0 -272
  505. package/dist/sse/shared/serializers/base-serializer.d.ts +0 -158
  506. package/dist/sse/shared/serializers/chat-event-serializer.d.ts +0 -82
  507. package/dist/sse/shared/serializers/responses-event-serializer.d.ts +0 -123
  508. package/dist/sse/shared/serializers/types.d.ts +0 -51
  509. package/dist/sse/shared/utils.d.ts +0 -254
  510. package/dist/sse/sse-to-json/parsers/sse-parser.d.ts +0 -73
  511. package/dist/tools/proxy/anthropic-tool-proxy.d.ts +0 -19
  512. package/dist/tools/proxy/anthropic-tool-proxy.js +0 -57
  513. package/dist/tools/proxy/executors/web-fetch.d.ts +0 -6
  514. package/dist/tools/proxy/executors/web-fetch.js +0 -39
  515. package/dist/tools/proxy/registry.d.ts +0 -8
  516. package/dist/tools/proxy/registry.js +0 -14
  517. package/dist/tools/proxy/types.d.ts +0 -29
  518. package/dist/tools/tool-registry.d.ts +0 -8
  519. package/dist/tools/web-fetch-html.d.ts +0 -15
  520. package/dist/tools/web-fetch-html.js +0 -83
  521. package/dist/utils/conversion-adapter.d.ts +0 -65
  522. package/dist/utils/conversion-adapter.js +0 -183
  523. package/dist/utils/error-factory.d.ts +0 -88
  524. package/dist/utils/error-factory.js +0 -138
  525. package/dist/utils/error-utils.d.ts +0 -334
  526. package/dist/utils/error-utils.js +0 -782
  527. package/dist/utils/index.d.ts +0 -8
  528. package/dist/utils/index.js +0 -13
  529. package/dist/utils/performance-utils.d.ts +0 -205
  530. package/dist/utils/performance-utils.js +0 -440
  531. package/dist/utils/profile-mapper.d.ts +0 -32
  532. package/dist/utils/profile-mapper.js +0 -269
  533. package/dist/utils/request-processor.d.ts +0 -52
  534. package/dist/utils/request-processor.js +0 -210
  535. package/dist/utils/request-utils.d.ts +0 -117
  536. package/dist/utils/request-utils.js +0 -333
  537. package/dist/utils/response-utils.d.ts +0 -127
  538. package/dist/utils/response-utils.js +0 -516
  539. package/dist/utils/token-counter.d.ts +0 -89
  540. package/dist/utils/token-counter.js +0 -541
  541. /package/dist/{tools/proxy → conversion/hub/tool-governance}/types.js +0 -0
  542. /package/dist/conversion/shared/{responses-id-utils.d.ts → bridge-id-utils.d.ts} +0 -0
@@ -1,85 +1,25 @@
1
- import { normalizeFunctionCallId, normalizeFunctionCallOutputId } from '../shared/responses-id-utils.js';
2
- import { ensureResponsesInstructions } from '../shared/responses-instructions.js';
1
+ import { ensureBridgeInstructions } from '../shared/bridge-instructions.js';
2
+ import { convertMessagesToBridgeInput, convertBridgeInputToChatMessages } from '../shared/bridge-message-utils.js';
3
+ import { createToolCallIdTransformer, enforceToolCallIdStyle, resolveToolCallIdStyle, stripInternalToolingMetadata, sanitizeResponsesFunctionName } from '../shared/responses-tool-utils.js';
4
+ import { mapBridgeToolsToChat, mapChatToolsToBridge } from '../shared/tool-mapping.js';
3
5
  // --- Utilities (ported strictly) ---
4
6
  import { canonicalizeChatResponseTools } from '../shared/tool-canonicalizer.js';
7
+ import { normalizeMessageReasoningTools } from '../shared/reasoning-tool-normalizer.js';
8
+ import { createBridgeActionState, runBridgeActionPipeline } from '../shared/bridge-actions.js';
9
+ import { resolveBridgePolicy, resolvePolicyActions } from '../shared/bridge-policies.js';
10
+ import { buildResponsesOutputFromChat } from '../shared/responses-output-builder.js';
5
11
  function isObject(v) {
6
12
  return !!v && typeof v === 'object' && !Array.isArray(v);
7
13
  }
8
- // tryParseJson now shared in ../shared/jsonish.ts
9
- // splitCommandString now unified in ../shared/tooling.ts
10
- // parseLenient now shared in ../shared/jsonish.ts
11
- function defaultObjectSchema() { return { type: 'object', properties: {}, additionalProperties: true }; }
12
14
  // normalizeTools unified in ../shared/args-mapping.ts
13
15
  // --- Structured self-repair helpers for tool failures (Responses path) ---
14
16
  // use shared isImagePath
15
17
  // NOTE: 自修复提示已移除(统一标准:不做模糊兜底)。
16
- function getExpectedType(schema, key) {
17
- if (!schema || !isObject(schema))
18
- return { kind: 'any' };
19
- const props = isObject(schema.properties) ? schema.properties : undefined;
20
- const s = props && isObject(props[key]) ? props[key] : undefined;
21
- if (!s)
22
- return { kind: 'any' };
23
- const t = s.type;
24
- if (t === 'string')
25
- return { kind: 'string' };
26
- if (t === 'object')
27
- return { kind: 'object' };
28
- if (t === 'array') {
29
- const items = s.items;
30
- const it = items && isObject(items) ? items.type : undefined;
31
- if (it === 'string')
32
- return { kind: 'arrayString' };
33
- return { kind: 'any' };
34
- }
35
- return { kind: 'any' };
36
- }
37
- function normalizeArgumentsBySchema(argsStringOrObj, _functionName, _tools) {
38
- // 只做最小字符串化:字符串原样透传;对象仅 stringify 一次;不做 parse/修复
39
- if (typeof argsStringOrObj === 'string')
40
- return argsStringOrObj;
41
- try {
42
- return JSON.stringify(argsStringOrObj ?? {});
43
- }
44
- catch {
45
- return String(argsStringOrObj);
46
- }
47
- }
48
- function parseFunctionArguments(args) {
49
- if (typeof args === 'string') {
50
- try {
51
- const obj = JSON.parse(args);
52
- return isObject(obj) ? obj : {};
53
- }
54
- catch {
55
- return {};
56
- }
57
- }
58
- if (isObject(args))
59
- return args;
60
- return {};
61
- }
62
- // Responses-only: 保持“只映射,不解析/不修复”。
63
- function normalizeToolOutput(entry) {
64
- const out = entry?.output;
65
- if (typeof out === 'string')
66
- return out;
67
- if (out && typeof out === 'object') {
68
- try {
69
- return JSON.stringify(out);
70
- }
71
- catch {
72
- return String(out);
73
- }
74
- }
75
- return null;
76
- }
77
18
  // --- Public bridge functions ---
78
19
  export function captureResponsesContext(payload, dto) {
79
- ensureResponsesInstructions(payload);
20
+ ensureBridgeInstructions(payload);
80
21
  const context = {
81
22
  requestId: dto?.route?.requestId,
82
- instructions: typeof payload.instructions === 'string' ? payload.instructions : undefined,
83
23
  input: Array.isArray(payload.input) ? payload.input : undefined,
84
24
  include: payload.include,
85
25
  store: payload.store,
@@ -100,46 +40,39 @@ export function buildChatRequestFromResponses(payload, context) {
100
40
  // V3: 对 Responses 路径仅做“形状转换”,不做参数解析/修复。
101
41
  // 将顶层 { type,name,description,parameters,strict } 归一为 OpenAI Chat tools 形状:
102
42
  // { type:'function', function:{ name,description,parameters,strict? } }
103
- const mapToolToChatShape = (t) => {
104
- if (!t || typeof t !== 'object')
105
- return null;
106
- const anyT = t;
107
- const originalType = typeof anyT.type === 'string' ? anyT.type : 'function';
108
- const mappedType = ['function', 'custom'].includes(originalType.toLowerCase()) ? 'function' : originalType;
109
- const fn = (anyT.function && typeof anyT.function === 'object') ? anyT.function : {};
110
- const topName = typeof anyT.name === 'string' ? anyT.name : undefined;
111
- const fnName = typeof fn.name === 'string' ? fn.name : undefined;
112
- const name = (fnName || topName || '').trim();
113
- if (!name)
114
- return null;
115
- const topDesc = typeof anyT.description === 'string' ? anyT.description : undefined;
116
- const fnDesc = typeof fn.description === 'string' ? fn.description : undefined;
117
- const description = fnDesc || topDesc;
118
- const fnParams = Object.prototype.hasOwnProperty.call(fn, 'parameters') ? fn.parameters : undefined;
119
- const topParams = Object.prototype.hasOwnProperty.call(anyT, 'parameters') ? anyT.parameters : undefined;
120
- // 不解析/修复参数;保留原始 schema
121
- const parameters = fnParams !== undefined ? fnParams : topParams;
122
- const strict = typeof fn.strict === 'boolean' ? fn.strict :
123
- typeof anyT.strict === 'boolean' ? anyT.strict :
124
- undefined;
125
- const fnOut = { name };
126
- if (description)
127
- fnOut.description = description;
128
- if (parameters !== undefined)
129
- fnOut.parameters = parameters;
130
- if (strict !== undefined)
131
- fnOut.strict = strict;
132
- return { type: mappedType, function: fnOut };
133
- };
134
- const toolsNormalized = Array.isArray(payload.tools)
135
- ? payload.tools.map(mapToolToChatShape).filter(Boolean)
136
- : undefined;
43
+ const toolsNormalized = mapBridgeToolsToChat(payload.tools, {
44
+ sanitizeName: sanitizeResponsesFunctionName
45
+ });
137
46
  // 不在 Responses 路径进行 MCP 工具注入;统一由 Chat 后半段治理注入
138
- let messages = mapResponsesInputToChat({
139
- instructions: context.instructions,
47
+ let messages = convertBridgeInputToChatMessages({
140
48
  input: context.input,
141
- toolsNormalized
49
+ tools: toolsNormalized,
50
+ normalizeFunctionName: sanitizeResponsesFunctionName,
51
+ toolResultFallbackText: 'Command succeeded (no output).'
142
52
  });
53
+ try {
54
+ const bridgePolicy = resolveBridgePolicy({ protocol: 'openai-responses', moduleType: 'openai-responses' });
55
+ const policyActions = resolvePolicyActions(bridgePolicy, 'request_inbound');
56
+ if (policyActions?.length) {
57
+ const actionState = createBridgeActionState({
58
+ messages,
59
+ requiredAction: typeof payload?.required_action === 'object' ? payload.required_action : undefined,
60
+ rawRequest: payload
61
+ });
62
+ runBridgeActionPipeline({
63
+ stage: 'request_inbound',
64
+ actions: policyActions,
65
+ protocol: bridgePolicy?.protocol ?? 'openai-responses',
66
+ moduleType: bridgePolicy?.moduleType ?? 'openai-responses',
67
+ requestId: context.requestId,
68
+ state: actionState
69
+ });
70
+ messages = actionState.messages;
71
+ }
72
+ }
73
+ catch {
74
+ // Policy application is best-effort; fall back to raw mapping on failure.
75
+ }
143
76
  if (Array.isArray(context.originalSystemMessages) && context.originalSystemMessages.length) {
144
77
  const preservedSystems = context.originalSystemMessages
145
78
  .map(text => ({ role: 'system', content: text }))
@@ -152,52 +85,9 @@ export function buildChatRequestFromResponses(payload, context) {
152
85
  // 不在 Responses 路径做工具治理;统一在 Chat 后半段处理
153
86
  // No system tips for MCP on OpenAI Responses path (avoid leaking tool names)
154
87
  if (!messages.length) {
155
- // Fallback: if there is genuine user text in input blocks, inject a user message (align with Anthropic)
156
- try {
157
- const input = Array.isArray(context.input) ? context.input : [];
158
- for (const entry of input) {
159
- if (!entry || typeof entry !== 'object')
160
- continue;
161
- const role = normalizeResponseRole(entry.role || 'user');
162
- if (role !== 'user')
163
- continue;
164
- const blocks = Array.isArray(entry.content) ? entry.content : [];
165
- const parts = [];
166
- for (const b of blocks) {
167
- if (!b || typeof b !== 'object')
168
- continue;
169
- const t = String(b.type || '').toLowerCase();
170
- if ((t === 'input_text' || t === 'text' || t === 'commentary') && typeof b.text === 'string') {
171
- parts.push(b.text);
172
- }
173
- }
174
- const txt = parts.join('\n').trim();
175
- if (txt) {
176
- messages.push({ role: 'user', content: txt });
177
- break;
178
- }
179
- }
180
- }
181
- catch { /* ignore */ }
182
- if (!messages.length) {
183
- // 最小兜底:若存在 instructions,则用作一条 user 消息(部分上游要求至少一条 user)
184
- if (typeof context.instructions === 'string' && context.instructions.trim().length > 0) {
185
- const s = context.instructions.trim();
186
- messages.push({ role: 'user', content: s });
187
- }
188
- else {
189
- throw new Error('Responses payload produced no chat messages');
190
- }
191
- }
88
+ throw new Error('Responses payload produced no chat messages');
192
89
  }
193
- // 如果只有 system 消息且无 user/assistant/tool,则将 instructions 重用为一条 user 消息,保证最小可用
194
- try {
195
- const hasNonSystem = messages.some((m) => (m && typeof m === 'object' && (m.role === 'user' || m.role === 'assistant' || m.role === 'tool')));
196
- if (!hasNonSystem && typeof context.instructions === 'string' && context.instructions.trim().length > 0) {
197
- messages.push({ role: 'user', content: context.instructions.trim() });
198
- }
199
- }
200
- catch { /* ignore */ }
90
+ // 如果只有 system 消息且无 user/assistant/tool,后续桥接 action 会从 instructions 注入兜底 user 消息
201
91
  const result = { model: payload.model, messages };
202
92
  if (typeof payload.stream === 'boolean') {
203
93
  result.stream = payload.stream;
@@ -224,31 +114,39 @@ export function buildChatRequestFromResponses(payload, context) {
224
114
  * - 将 system 消息折叠到 instructions;
225
115
  * - 将 user/assistant/tool 消息编码为 input[] 中的 message 块,使得 mapResponsesInputToChat 能够还原为等价 Chat 请求。
226
116
  */
227
- export function buildResponsesRequestFromChat(payload, ctx) {
117
+ function normalizeBridgeHistory(seed) {
118
+ if (!seed || typeof seed !== 'object') {
119
+ return undefined;
120
+ }
121
+ const record = seed;
122
+ if (!Array.isArray(record.input)) {
123
+ return undefined;
124
+ }
125
+ const systemMessages = Array.isArray(record.originalSystemMessages)
126
+ ? record.originalSystemMessages.filter((entry) => typeof entry === 'string' && entry.trim().length > 0)
127
+ : [];
128
+ return {
129
+ input: record.input,
130
+ combinedSystemInstruction: typeof record.combinedSystemInstruction === 'string' && record.combinedSystemInstruction.trim().length
131
+ ? record.combinedSystemInstruction
132
+ : undefined,
133
+ latestUserInstruction: typeof record.latestUserInstruction === 'string' && record.latestUserInstruction.trim().length
134
+ ? record.latestUserInstruction
135
+ : undefined,
136
+ originalSystemMessages: systemMessages
137
+ };
138
+ }
139
+ export function buildResponsesRequestFromChat(payload, ctx, extras) {
228
140
  const chat = unwrapData(payload);
229
141
  const out = {};
230
142
  // 基本字段
231
143
  out.model = chat.model;
232
144
  // tools: 反向映射为 ResponsesToolDefinition 形状
233
- const toolsArr = Array.isArray(chat.tools) ? chat.tools : [];
234
- if (toolsArr.length) {
235
- out.tools = toolsArr.map(t => {
236
- const anyT = t || {};
237
- if (anyT.type === 'function' && anyT.function && typeof anyT.function === 'object') {
238
- const fn = anyT.function;
239
- const base = { type: 'function' };
240
- if (typeof fn.name === 'string')
241
- base.name = fn.name;
242
- if (typeof fn.description === 'string')
243
- base.description = fn.description;
244
- if (Object.prototype.hasOwnProperty.call(fn, 'parameters'))
245
- base.parameters = fn.parameters;
246
- if (typeof fn.strict === 'boolean')
247
- base.strict = fn.strict;
248
- return base;
249
- }
250
- return anyT;
251
- });
145
+ const responsesTools = mapChatToolsToBridge(chat.tools, {
146
+ sanitizeName: sanitizeResponsesFunctionName
147
+ });
148
+ if (responsesTools?.length) {
149
+ out.tools = responsesTools;
252
150
  }
253
151
  const passthroughKeys = [
254
152
  'tool_choice',
@@ -267,190 +165,57 @@ export function buildResponsesRequestFromChat(payload, ctx) {
267
165
  if (typeof chat.max_tokens === 'number' && chat.max_output_tokens === undefined) {
268
166
  out.max_output_tokens = chat.max_tokens;
269
167
  }
270
- const messages = Array.isArray(chat.messages) ? chat.messages : [];
271
- const input = [];
272
- const collectText = (val) => {
273
- if (!val)
274
- return '';
275
- if (typeof val === 'string')
276
- return val;
277
- if (Array.isArray(val))
278
- return val.map(collectText).join('');
279
- if (typeof val === 'object') {
280
- if (typeof val.text === 'string')
281
- return String(val.text);
282
- if (Array.isArray(val.content))
283
- return collectText(val.content);
284
- if (typeof val.content === 'string')
285
- return String(val.content);
286
- }
287
- return '';
288
- };
289
- const extractUserTextFromEntry = (entry) => {
290
- if (!entry || typeof entry !== 'object')
291
- return '';
292
- const directContent = entry.content ?? entry.message?.content;
293
- if (typeof directContent === 'string')
294
- return directContent.trim();
295
- if (Array.isArray(directContent)) {
296
- return directContent.map(block => collectText(block)).join('').trim();
297
- }
298
- const text = entry.text ?? entry.message?.text;
299
- if (typeof text === 'string')
300
- return text.trim();
301
- return '';
302
- };
303
- const systemParts = [];
304
- const originalSystemMessages = [];
305
- let latestUserInstruction = null;
306
- const pendingToolCallIds = [];
307
- const knownToolCallIds = new Set();
308
- const toolCallIdAliases = new Map();
309
- // 将 system 消息折叠到 instructions,其余 role 映射到 input[].message.content 中
310
- for (const m of messages) {
311
- if (!m || typeof m !== 'object')
312
- continue;
313
- const role = String(m.role || '').toLowerCase();
314
- const content = m.content;
315
- const collectedText = collectText(content);
316
- const text = role === 'system' ? collectedText : collectedText.trim();
317
- if (role === 'system') {
318
- if (collectedText && collectedText.length) {
319
- originalSystemMessages.push(collectedText);
320
- systemParts.push(collectedText);
321
- }
322
- continue;
323
- }
324
- // tool 结果消息:Chat 中 role='tool' 的消息,应回写为 Responses 的 function_call_output 输入块,
325
- // 以便 FC 等上游识别为工具结果,而不是普通 message(其 role 不接受 'tool')。
326
- if (role === 'tool') {
327
- const rawToolId = m.tool_call_id ||
328
- m.call_id ||
329
- m.tool_use_id ||
330
- m.id ||
331
- undefined;
332
- let callId = typeof rawToolId === 'string' ? rawToolId : undefined;
333
- if (callId && toolCallIdAliases.has(callId)) {
334
- callId = toolCallIdAliases.get(callId);
335
- }
336
- if (!callId || !knownToolCallIds.has(callId)) {
337
- const fallbackId = pendingToolCallIds.length ? pendingToolCallIds.shift() : undefined;
338
- if (fallbackId) {
339
- if (callId && callId !== fallbackId) {
340
- toolCallIdAliases.set(callId, fallbackId);
341
- }
342
- callId = fallbackId;
343
- }
344
- }
345
- else if (callId) {
346
- const idx = pendingToolCallIds.indexOf(callId);
347
- if (idx >= 0)
348
- pendingToolCallIds.splice(idx, 1);
349
- }
350
- const normalizedCallId = normalizeFunctionCallId({
351
- callId,
352
- fallback: `fc_call_${input.length + 1}`
168
+ let messages = Array.isArray(chat.messages) ? chat.messages : [];
169
+ let bridgeMetadata;
170
+ try {
171
+ const bridgePolicy = resolveBridgePolicy({ protocol: 'openai-responses', moduleType: 'openai-responses' });
172
+ const policyActions = resolvePolicyActions(bridgePolicy, 'request_outbound');
173
+ if (policyActions?.length) {
174
+ const actionState = createBridgeActionState({
175
+ messages,
176
+ rawRequest: chat
353
177
  });
354
- if (callId && callId !== normalizedCallId) {
355
- toolCallIdAliases.set(callId, normalizedCallId);
356
- }
357
- const normalizedId = normalizeFunctionCallOutputId({
358
- callId: normalizedCallId,
359
- fallback: `fc_tool_${input.length + 1}`
178
+ runBridgeActionPipeline({
179
+ stage: 'request_outbound',
180
+ actions: policyActions,
181
+ protocol: bridgePolicy?.protocol ?? 'openai-responses',
182
+ moduleType: bridgePolicy?.moduleType ?? 'openai-responses',
183
+ requestId: ctx?.requestId,
184
+ state: actionState
360
185
  });
361
- const entry = {
362
- type: 'function_call_output',
363
- id: normalizedId,
364
- call_id: normalizedCallId,
365
- output: text || undefined
366
- };
367
- input.push(entry);
368
- continue;
369
- }
370
- // tool_calls: 将 Chat 中的 tool_calls 归一为 function_call/tool_call 输入块。
371
- // Responses V3 要求 call_id 稳定并与 Chat payload 完全一致,以便多轮工具结果匹配。
372
- // 因此这里不再改写 id,仅在缺失时生成随机 call_id。
373
- const toolCalls = Array.isArray(m.tool_calls) ? m.tool_calls : [];
374
- if (toolCalls.length) {
375
- for (const tc of toolCalls) {
376
- try {
377
- const rawId = typeof tc?.id === 'string' && tc.id
378
- ? String(tc.id)
379
- : `call_${Math.random().toString(36).slice(2, 8)}`;
380
- const normalizedCallId = normalizeFunctionCallId({
381
- callId: rawId,
382
- fallback: `fc_call_${input.length + 1}`
383
- });
384
- if (rawId !== normalizedCallId) {
385
- toolCallIdAliases.set(rawId, normalizedCallId);
386
- }
387
- const fn = tc?.function || {};
388
- const name = typeof fn?.name === 'string' ? String(fn.name) : 'tool';
389
- const argsRaw = fn?.arguments;
390
- const args = typeof argsRaw === 'string' ? argsRaw : normalizeArgumentsBySchema(argsRaw, name, out.tools);
391
- const entry = {
392
- type: 'function_call',
393
- id: normalizedCallId,
394
- call_id: normalizedCallId,
395
- name,
396
- arguments: args
397
- };
398
- input.push(entry);
399
- knownToolCallIds.add(normalizedCallId);
400
- pendingToolCallIds.push(normalizedCallId);
401
- }
402
- catch {
403
- // ignore single tool_call
404
- }
405
- }
406
- continue;
407
- }
408
- // 普通 user/assistant/tool 消息 → message 块
409
- // FC 在 user 输入块上要求 content[*].type 是 input_text/input_image/input_file,
410
- // 在 assistant 历史消息上要求 output_text/refusal。
411
- if (text) {
412
- const tRole = role === 'assistant' ? 'output_text' : 'input_text';
413
- const entry = {
414
- type: 'message',
415
- role,
416
- content: [{ type: tRole, text }]
417
- };
418
- input.push(entry);
419
- if (role === 'user' && text) {
420
- latestUserInstruction = text;
186
+ messages = actionState.messages;
187
+ if (actionState.metadata && Object.keys(actionState.metadata).length) {
188
+ bridgeMetadata = actionState.metadata;
421
189
  }
422
190
  }
423
191
  }
424
- if (!latestUserInstruction) {
425
- for (let i = input.length - 1; i >= 0; i -= 1) {
426
- const entry = input[i];
427
- const roleSource = entry?.role ?? entry?.message?.role;
428
- const role = typeof roleSource === 'string' ? roleSource.toLowerCase() : '';
429
- if (role !== 'user')
430
- continue;
431
- const text = extractUserTextFromEntry(entry);
432
- if (text) {
433
- latestUserInstruction = text;
434
- break;
435
- }
192
+ catch {
193
+ // ignore policy errors
194
+ }
195
+ const envelopeMetadata = ctx?.metadata && typeof ctx.metadata === 'object' ? ctx.metadata : undefined;
196
+ const toolCallIdStyle = resolveToolCallIdStyle(envelopeMetadata);
197
+ const historySeed = normalizeBridgeHistory(bridgeMetadata?.bridgeHistory ?? envelopeMetadata?.bridgeHistory ?? extras?.bridgeHistory);
198
+ const history = historySeed ??
199
+ convertMessagesToBridgeInput({
200
+ messages,
201
+ tools: Array.isArray(out.tools) ? out.tools : undefined
202
+ });
203
+ const callIdTransformer = createToolCallIdTransformer(toolCallIdStyle);
204
+ if (callIdTransformer) {
205
+ enforceToolCallIdStyle(history.input, callIdTransformer);
206
+ }
207
+ const { input, combinedSystemInstruction, originalSystemMessages } = history;
208
+ const instructionCandidates = [
209
+ typeof extras?.systemInstruction === 'string' && extras.systemInstruction.trim().length ? extras.systemInstruction.trim() : undefined,
210
+ typeof envelopeMetadata?.systemInstruction === 'string' && envelopeMetadata.systemInstruction.trim().length ? envelopeMetadata.systemInstruction.trim() : undefined,
211
+ combinedSystemInstruction && combinedSystemInstruction.length > 0 ? combinedSystemInstruction : undefined
212
+ ];
213
+ for (const candidate of instructionCandidates) {
214
+ if (candidate && candidate.length) {
215
+ out.instructions = candidate;
216
+ break;
436
217
  }
437
218
  }
438
- const combinedSystemInstruction = systemParts.join('\n\n').trim();
439
- if (combinedSystemInstruction.length > 0) {
440
- out.instructions = combinedSystemInstruction;
441
- }
442
- else if (typeof ctx?.instructions === 'string' && ctx.instructions.trim().length) {
443
- out.instructions = ctx.instructions.trim();
444
- }
445
- if (!out.instructions && typeof latestUserInstruction === 'string' && latestUserInstruction.trim().length) {
446
- out.instructions = latestUserInstruction.trim();
447
- }
448
- if (ctx?.instructionsIsRaw === true) {
449
- out.instructions_is_raw = true;
450
- }
451
- else if ('instructions_is_raw' in out) {
452
- delete out.instructions_is_raw;
453
- }
454
219
  // 不追加 metadata,以便 roundtrip 与原始 payload 对齐;系统提示直接写入 instructions。
455
220
  if (input.length) {
456
221
  out.input = input;
@@ -468,7 +233,7 @@ export function buildResponsesRequestFromChat(payload, ctx) {
468
233
  else if (resolvedStream === false) {
469
234
  out.stream = false;
470
235
  }
471
- ensureResponsesInstructions(out);
236
+ ensureBridgeInstructions(out);
472
237
  return { request: out, originalSystemMessages };
473
238
  }
474
239
  export function buildResponsesPayloadFromChat(payload, context) {
@@ -477,571 +242,79 @@ export function buildResponsesPayloadFromChat(payload, context) {
477
242
  const response = unwrapData(payload);
478
243
  if (!response || typeof response !== 'object')
479
244
  return payload;
480
- // If provider already returned Responses shape, sanitize textual output to remove tool result envelopes
481
245
  if (response.object === 'response' && Array.isArray(response.output)) {
482
- try {
483
- const outArr = response.output;
484
- for (const item of outArr) {
485
- if (!item || typeof item !== 'object')
486
- continue;
487
- const t = String(item.type || '').toLowerCase();
488
- if (t === 'message' && item.message && typeof item.message === 'object') {
489
- const msg = item.message;
490
- const content = msg.content;
491
- if (Array.isArray(content)) {
492
- for (const part of content) {
493
- if (part && typeof part === 'object' && String(part.type || '').toLowerCase() === 'output_text' && typeof part.text === 'string') {
494
- // rcc.tool.v1 剥离已移除
495
- }
496
- }
497
- }
498
- else if (typeof content === 'string') {
499
- // rcc.tool.v1 剥离已移除
500
- }
501
- }
502
- if (t === 'reasoning' && Array.isArray(item.content)) {
503
- for (const part of item.content) {
504
- if (part && typeof part === 'object' && String(part.type || '').toLowerCase() === 'output_text' && typeof part.text === 'string') {
505
- // rcc.tool.v1 剥离已移除
506
- }
507
- }
508
- }
509
- }
510
- if (typeof response.output_text === 'string') {
511
- // rcc.tool.v1 剥离已移除
512
- }
513
- }
514
- catch { /* ignore sanitize errors */ }
515
246
  return response;
516
247
  }
517
- // 如果响应本身是 Anthropic-style message(type:'message'+content[]),先归一为 Chat completion,
518
- // 再走统一的 Chat→Responses 映射路径,避免“带 tool_use message”直接被当作 Chat completion
519
- let responseForBridge = response;
520
- try {
521
- const maybeType = String(response.type || '').toLowerCase();
522
- if (maybeType === 'message' && Array.isArray(response.content) && !Array.isArray(response.choices)) {
523
- const msg = response;
524
- const contentArr = Array.isArray(msg.content) ? msg.content : [];
525
- const textParts = [];
526
- const toolCalls = [];
527
- for (const b of contentArr) {
528
- if (!b || typeof b !== 'object')
529
- continue;
530
- const t = String(b.type || '').toLowerCase();
531
- if (t === 'text' && typeof b.text === 'string') {
532
- const s = b.text;
533
- if (s && s.trim().length)
534
- textParts.push(s);
535
- }
536
- else if (t === 'tool_use') {
537
- const name = typeof b.name === 'string' ? String(b.name) : '';
538
- const id = typeof b.id === 'string' ? String(b.id) : `call_${Math.random().toString(36).slice(2, 10)}`;
539
- let args = '';
540
- const input = b.input;
541
- if (typeof input === 'string')
542
- args = input;
543
- else {
544
- try {
545
- args = JSON.stringify(input ?? {});
546
- }
547
- catch {
548
- args = '{}';
549
- }
550
- }
551
- if (name)
552
- toolCalls.push({ id, name, args });
553
- }
554
- }
555
- const mapStopToFinish = (sr) => {
556
- const v = String(sr || '');
557
- if (v === 'tool_use')
558
- return 'tool_calls';
559
- if (v === 'max_tokens')
560
- return 'length';
561
- if (v === 'stop_sequence')
562
- return 'content_filter';
563
- return 'stop';
564
- };
565
- const finish_reason = mapStopToFinish(msg.stop_reason);
566
- const chatMsg = {
567
- role: msg.role || 'assistant',
568
- content: textParts.join('\n')
569
- };
570
- if (toolCalls.length) {
571
- chatMsg.tool_calls = toolCalls.map(tc => ({
572
- id: tc.id,
573
- type: 'function',
574
- function: { name: tc.name, arguments: tc.args }
575
- }));
576
- }
577
- const usageIn = msg.usage || {};
578
- responseForBridge = {
579
- id: msg.id || `chatcmpl_${Date.now()}`,
580
- object: 'chat.completion',
581
- model: msg.model || 'unknown',
582
- choices: [
583
- {
584
- index: 0,
585
- finish_reason,
586
- message: chatMsg
587
- }
588
- ],
589
- usage: usageIn
590
- };
591
- }
592
- }
593
- catch {
594
- responseForBridge = response;
248
+ if (!Array.isArray(response.choices) || !response.choices.length) {
249
+ throw new Error('Responses bridge expects OpenAI Chat completion payload');
595
250
  }
596
- // Canonicalize response tools (Responses-style) before mapping to Responses blocks
597
- const canonical = canonicalizeChatResponseTools(responseForBridge);
251
+ const canonical = canonicalizeChatResponseTools(response);
598
252
  const choices = Array.isArray(canonical?.choices) ? canonical.choices : [];
599
253
  const primaryChoice = choices[0] && typeof choices[0] === 'object' ? choices[0] : undefined;
600
254
  const message = primaryChoice && typeof primaryChoice.message === 'object' ? primaryChoice.message : undefined;
601
- const role = message?.role || 'assistant';
602
- const content = message?.content;
603
- const reasoningText = typeof message?.reasoning_content === 'string' && message.reasoning_content.trim().length
604
- ? String(message.reasoning_content).trim() : undefined;
605
- const outputItems = [];
606
- const allocateOutputId = (prefix) => `${prefix}_${context?.requestId ?? Date.now()}_${outputItems.length + 1}`;
607
- if (reasoningText) {
608
- outputItems.push({
609
- id: allocateOutputId('reasoning'),
610
- type: 'reasoning',
611
- status: 'completed',
612
- summary: [],
613
- content: [{ type: 'reasoning_text', text: reasoningText }]
614
- });
615
- }
616
- const convertedContent = convertChatContentToResponses(content);
617
- if (convertedContent.length > 0) {
618
- outputItems.push({
619
- id: allocateOutputId('message'),
620
- type: 'message',
621
- status: 'completed',
622
- role,
623
- content: convertedContent
624
- });
255
+ if (!message) {
256
+ throw new Error('Responses bridge could not locate assistant message in Chat completion');
625
257
  }
626
- let toolCalls = Array.isArray(message?.tool_calls) ? message.tool_calls : [];
627
- const toolCallIdMap = new Map();
628
- // 过滤无效函数调用(name 缺失或为空)
629
- try {
630
- toolCalls = toolCalls.filter((it) => {
631
- const nm = (it && typeof it === 'object') ? (it?.function?.name || it.name) : undefined;
632
- return typeof nm === 'string' && nm.trim().length > 0 && nm.toLowerCase() !== 'tool';
633
- });
634
- }
635
- catch { /* ignore */ }
636
- for (const call of toolCalls) {
258
+ if (message) {
637
259
  try {
638
- const fn = call?.function || {};
639
- const callName = typeof fn?.name === 'string' && fn.name.trim().length
640
- ? fn.name
641
- : (typeof call.name === 'string' ? call.name : 'tool');
642
- if (!callName || callName.toLowerCase() === 'tool')
643
- continue;
644
- const rawArgs = fn?.arguments ?? call.arguments ?? {};
645
- const argsStr = typeof rawArgs === 'string'
646
- ? rawArgs
647
- : (() => {
648
- try {
649
- return JSON.stringify(rawArgs ?? {});
650
- }
651
- catch {
652
- return '{}';
653
- }
654
- })();
655
- const originalCallId = typeof call.id === 'string' && call.id.trim().length
656
- ? String(call.id)
657
- : (typeof call.call_id === 'string' && call.call_id.trim().length
658
- ? String(call.call_id)
659
- : allocateOutputId('tool_call'));
660
- const callId = normalizeFunctionCallId({
661
- callId: originalCallId,
662
- fallback: `fc_call_${outputItems.length + 1}`
663
- });
664
- if (originalCallId && originalCallId !== callId) {
665
- toolCallIdMap.set(originalCallId, callId);
260
+ const bridgePolicy = resolveBridgePolicy({ protocol: 'openai-responses', moduleType: 'openai-responses' });
261
+ const policyActions = resolvePolicyActions(bridgePolicy, 'response_outbound');
262
+ if (policyActions?.length) {
263
+ const actionState = createBridgeActionState({ messages: [message] });
264
+ runBridgeActionPipeline({
265
+ stage: 'response_outbound',
266
+ actions: policyActions,
267
+ protocol: bridgePolicy?.protocol ?? 'openai-responses',
268
+ moduleType: bridgePolicy?.moduleType ?? 'openai-responses',
269
+ requestId: context?.requestId,
270
+ state: actionState
271
+ });
666
272
  }
667
- toolCallIdMap.set(callId, callId);
668
- outputItems.push({
669
- id: allocateOutputId('function_call'),
670
- type: 'function_call',
671
- status: 'in_progress',
672
- name: callName,
673
- call_id: callId,
674
- arguments: argsStr
675
- });
676
273
  }
677
274
  catch {
678
- // ignore malformed tool call
275
+ // best-effort bridge policy application
679
276
  }
680
277
  }
681
- const usageRaw = response.usage;
682
- let usage = undefined;
683
- if (usageRaw && typeof usageRaw === 'object') {
684
- usage = { ...usageRaw };
685
- if (usage.input_tokens != null && usage.prompt_tokens == null) {
686
- usage.prompt_tokens = usage.input_tokens;
687
- }
688
- if (usage.output_tokens != null && usage.completion_tokens == null) {
689
- usage.completion_tokens = usage.output_tokens;
690
- }
691
- if (usage.prompt_tokens != null && usage.completion_tokens != null && usage.total_tokens == null) {
692
- const total = Number(usage.prompt_tokens) + Number(usage.completion_tokens);
693
- if (!Number.isNaN(total))
694
- usage.total_tokens = total;
695
- }
278
+ if (message) {
696
279
  try {
697
- delete usage.input_tokens;
698
- delete usage.output_tokens;
280
+ normalizeMessageReasoningTools(message, {
281
+ idPrefix: `responses_reasoning_${context?.requestId ?? 'canonical'}`
282
+ });
699
283
  }
700
- catch { /* ignore */ }
701
- }
702
- else if (usageRaw !== undefined) {
703
- usage = usageRaw;
704
- }
705
- const outputText = extractOutputText(convertedContent, toolCalls);
706
- const hasToolCalls = toolCalls.length > 0;
707
- const status = hasToolCalls ? 'requires_action' : 'completed';
708
- if (hasToolCalls) {
709
- for (const item of outputItems) {
710
- if (item.type === 'message') {
711
- item.status = 'in_progress';
712
- }
284
+ catch {
285
+ // best-effort reasoning normalization
713
286
  }
714
287
  }
288
+ const outputBuild = buildResponsesOutputFromChat({
289
+ response: response,
290
+ message,
291
+ requestId: context?.requestId,
292
+ sanitizeFunctionName: sanitizeResponsesFunctionName
293
+ });
715
294
  const out = {
716
295
  id: response.id || `resp-${Date.now()}`,
717
296
  object: 'response',
718
297
  created_at: response.created_at || response.created || Math.floor(Date.now() / 1000),
719
298
  model: response.model,
720
- status,
721
- output: outputItems,
722
- output_text: outputText || ''
299
+ status: outputBuild.status,
300
+ output: outputBuild.outputItems,
301
+ output_text: outputBuild.outputText || ''
723
302
  };
724
- if (usage !== undefined)
725
- out.usage = usage;
726
- // Synthesize required_action for non-stream JSON when tool_calls exist
727
- try {
728
- if (toolCalls.length > 0) {
729
- const toStringJson = (v) => { if (typeof v === 'string')
730
- return v; try {
731
- return JSON.stringify(v ?? {});
732
- }
733
- catch {
734
- return '{}';
735
- } };
736
- const callsAll = toolCalls.filter((it) => {
737
- const nm = (it && typeof it === 'object') ? (it?.function?.name || it.name) : undefined;
738
- return typeof nm === 'string' && nm.trim().length > 0 && nm.toLowerCase() !== 'tool';
739
- }).map((it) => {
740
- const rawId = typeof it.id === 'string' ? it.id : (typeof it.call_id === 'string' ? it.call_id : `call_${Math.random().toString(36).slice(2, 8)}`);
741
- const id = toolCallIdMap.get(rawId) ?? normalizeFunctionCallId({ callId: rawId, fallback: `fc_call_${outputItems.length + 1}` });
742
- const nm = typeof it?.function?.name === 'string' ? it.function.name : (typeof it.name === 'string' ? it.name : 'tool');
743
- const rawArgs = it?.function?.arguments ?? it.arguments ?? {};
744
- const argsStr = toStringJson(rawArgs);
745
- return { id, type: 'function', function: { name: String(nm), arguments: String(argsStr) } };
746
- });
747
- // 仅做最小形状映射:不进行校验与归一,仅透传(字符串化)。
748
- const calls = callsAll;
749
- const required_action = { type: 'submit_tool_outputs', submit_tool_outputs: { tool_calls: calls } };
750
- out.required_action = required_action;
751
- }
752
- }
753
- catch { /* ignore */ }
303
+ if (outputBuild.usage !== undefined)
304
+ out.usage = outputBuild.usage;
305
+ if (outputBuild.requiredAction)
306
+ out.required_action = outputBuild.requiredAction;
754
307
  // Do not inject captured tool results here; keep Chat back-half behavior standard.
755
308
  if (context) {
756
- for (const k of ['metadata', 'instructions', 'parallel_tool_calls', 'tool_choice', 'include', 'store']) {
309
+ for (const k of ['metadata', 'parallel_tool_calls', 'tool_choice', 'include', 'store']) {
757
310
  if (context[k] !== undefined)
758
311
  out[k] = context[k];
759
312
  }
760
313
  }
761
- return out;
762
- }
763
- function mapResponsesInputToChat(options) {
764
- const { instructions, input, toolsNormalized } = options;
765
- const messages = [];
766
- if (typeof instructions === 'string') {
767
- const trimmed = instructions.trim();
768
- if (trimmed.length) {
769
- messages.push({ role: 'system', content: trimmed });
770
- }
771
- }
772
- if (!Array.isArray(input))
773
- return messages;
774
- const toolNameById = new Map();
775
- const toolArgsById = new Map();
776
- const toolCallIdAliases = new Map();
777
- let lastToolCallId = null;
778
- for (const entry of input) {
779
- if (!entry || typeof entry !== 'object')
780
- continue;
781
- const entryType = typeof entry.type === 'string' ? entry.type.toLowerCase() : 'message';
782
- if (typeof entry.content === 'string') {
783
- const directText = (entry.content || '').toString().trim();
784
- if (directText.length) {
785
- const normalizedRole = normalizeResponseRole(entry.role || 'user');
786
- messages.push({ role: normalizedRole, content: directText });
787
- continue;
788
- }
789
- }
790
- if (entryType === 'function_call' || entryType === 'tool_call') {
791
- const rawName = typeof entry.name === 'string' ? entry.name : (typeof entry?.function?.name === 'string' ? entry.function.name : undefined);
792
- const name = (typeof rawName === 'string' && rawName.includes('.')) ? rawName.slice(rawName.indexOf('.') + 1).trim() : rawName;
793
- if (typeof name !== 'string' || !name.trim() || name.toLowerCase() === 'tool') {
794
- // 无效函数名:不生成 tool_calls,避免污染会话
795
- continue;
796
- }
797
- const args = entry.arguments ?? entry?.function?.arguments ?? {};
798
- const parsedArgs = args; // 不解析,原样透传(对象在后续 stringify)
799
- const callIdRaw = typeof entry.id === 'string' ? entry.id : (typeof entry.call_id === 'string' ? entry.call_id : `call_${Math.random().toString(36).slice(2, 8)}`);
800
- const callId = normalizeFunctionCallId({
801
- callId: callIdRaw,
802
- fallback: `fc_call_${messages.length + 1}`
803
- });
804
- if (callIdRaw && callIdRaw !== callId) {
805
- toolCallIdAliases.set(callIdRaw, callId);
806
- }
807
- const serialized = normalizeArgumentsBySchema(parsedArgs, name, toolsNormalized).trim();
808
- toolNameById.set(callId, name);
809
- toolArgsById.set(callId, serialized);
810
- messages.push({ role: 'assistant', tool_calls: [{ id: callId, type: 'function', function: { name, arguments: serialized } }] });
811
- lastToolCallId = callId;
812
- continue;
813
- }
814
- if (entryType === 'function_call_output' || entryType === 'tool_result' || entryType === 'tool_message') {
815
- let toolCallId = entry.tool_call_id || entry.call_id || entry.tool_use_id || entry.id || lastToolCallId;
816
- if (toolCallId && toolCallIdAliases.has(String(toolCallId))) {
817
- toolCallId = toolCallIdAliases.get(String(toolCallId)) || toolCallId;
818
- }
819
- else if (typeof toolCallId === 'string' && toolCallId.trim().length) {
820
- const normalized = normalizeFunctionCallId({ callId: toolCallId, fallback: toolCallId });
821
- if (normalized !== toolCallId) {
822
- toolCallIdAliases.set(toolCallId, normalized);
823
- }
824
- toolCallId = normalized;
825
- }
826
- const output = normalizeToolOutput(entry);
827
- if (toolCallId) {
828
- try {
829
- // Emit a standard tool role message so downstream Chat back-half can govern correctly
830
- let contentStr = output != null ? String(output) : '';
831
- if (!contentStr || contentStr.trim().length === 0) {
832
- contentStr = 'Command succeeded (no output).';
833
- }
834
- const nm = toolNameById.get(String(toolCallId));
835
- const toolMsg = { role: 'tool', tool_call_id: String(toolCallId), content: contentStr };
836
- if (typeof nm === 'string' && nm.trim().length)
837
- toolMsg.name = nm;
838
- messages.push(toolMsg);
839
- }
840
- catch {
841
- const fallback = (output ?? '');
842
- const nm = toolNameById.get(String(toolCallId));
843
- const toolMsg = { role: 'tool', tool_call_id: String(toolCallId), content: String(fallback) };
844
- if (typeof nm === 'string' && nm.trim().length)
845
- toolMsg.name = nm;
846
- messages.push(toolMsg);
847
- }
848
- lastToolCallId = null;
849
- }
850
- continue;
851
- }
852
- // Prefer explicit message shape when present: entry.message.{role,content[]}
853
- let handledViaExplicitMessage = false;
854
- if (entry && typeof entry.message === 'object' && Array.isArray(entry.message?.content)) {
855
- const explicit = entry.message;
856
- const { text, toolCalls, toolMessages, lastCallId } = processMessageBlocks(Array.isArray(explicit.content) ? explicit.content : [], toolsNormalized, toolNameById, toolCallIdAliases, lastToolCallId);
857
- if (toolCalls.length)
858
- messages.push({ role: 'assistant', tool_calls: toolCalls });
859
- for (const msg of toolMessages)
860
- messages.push(msg);
861
- const normalizedRole = normalizeResponseRole((explicit.role ?? entry.role) || 'user');
862
- if (typeof text === 'string' && text.trim().length) {
863
- messages.push({ role: normalizedRole, content: text.trim() });
864
- }
865
- lastToolCallId = lastCallId;
866
- handledViaExplicitMessage = true;
867
- }
868
- // Otherwise, consume entry.content[] if present
869
- if (!handledViaExplicitMessage) {
870
- const { text, toolCalls, toolMessages, lastCallId } = processMessageBlocks(Array.isArray(entry.content) ? entry.content : [], toolsNormalized, toolNameById, toolCallIdAliases, lastToolCallId);
871
- if (toolCalls.length)
872
- messages.push({ role: 'assistant', tool_calls: toolCalls });
873
- for (const msg of toolMessages)
874
- messages.push(msg);
875
- const normalizedRole = normalizeResponseRole(entry.role || 'user');
876
- if (typeof text === 'string' && text.trim().length) {
877
- messages.push({ role: normalizedRole, content: text.trim() });
878
- }
879
- lastToolCallId = lastCallId;
880
- }
881
- // Finally, handle top-level text items (e.g., { type: 'input_text', text: '...' })
882
- try {
883
- const t = String(entry.type || '').toLowerCase();
884
- if ((t === 'input_text' || t === 'text' || t === 'output_text' || t === 'commentary') && typeof entry.text === 'string') {
885
- const normalizedRole = normalizeResponseRole(entry.role || 'user');
886
- const s = entry.text;
887
- if (s && s.length)
888
- messages.push({ role: normalizedRole, content: s });
889
- }
890
- }
891
- catch { /* ignore */ }
892
- }
893
- return messages;
894
- }
895
- function normalizeResponseRole(role) {
896
- if (typeof role === 'string') {
897
- const normalized = role.toLowerCase();
898
- if (normalized === 'system' || normalized === 'assistant' || normalized === 'user' || normalized === 'tool')
899
- return normalized;
900
- }
901
- return 'user';
902
- }
903
- function processMessageBlocks(blocks, toolsNormalized, toolNameById, toolCallIdAliases, lastToolCallId) {
904
- const textParts = [];
905
- const toolCalls = [];
906
- const toolMessages = [];
907
- let currentLastCall = lastToolCallId;
908
- const toolArgsByIdLocal = new Map();
909
- for (const block of blocks) {
910
- if (!block || typeof block !== 'object')
911
- continue;
912
- const type = typeof block.type === 'string' ? block.type.toLowerCase() : '';
913
- if (type === 'input_text' || type === 'output_text' || type === 'text' || type === 'commentary') {
914
- if (typeof block.text === 'string')
915
- textParts.push(block.text);
916
- else if (typeof block.content === 'string')
917
- textParts.push(block.content);
918
- continue;
919
- }
920
- if (type === 'message' && Array.isArray(block.content)) {
921
- const nested = processMessageBlocks(block.content, toolsNormalized, toolNameById, toolCallIdAliases, currentLastCall);
922
- if (nested.text)
923
- textParts.push(nested.text);
924
- for (const tc of nested.toolCalls)
925
- toolCalls.push(tc);
926
- for (const tm of nested.toolMessages)
927
- toolMessages.push(tm);
928
- currentLastCall = nested.lastCallId;
929
- continue;
930
- }
931
- if (type === 'function_call') {
932
- const rawName = typeof block.name === 'string' ? block.name : (typeof block?.function?.name === 'string' ? block.function.name : undefined);
933
- const name = (typeof rawName === 'string' && rawName.includes('.')) ? rawName.slice(rawName.indexOf('.') + 1).trim() : rawName;
934
- const args = block.arguments ?? block?.function?.arguments ?? {};
935
- const parsedArgs = args; // 不解析
936
- const callIdRaw = typeof block.id === 'string' ? block.id : (typeof block.call_id === 'string' ? block.call_id : `call_${Math.random().toString(36).slice(2, 8)}`);
937
- const callId = normalizeFunctionCallId({ callId: callIdRaw, fallback: `fc_call_${toolCalls.length + 1}` });
938
- if (callIdRaw && callIdRaw !== callId) {
939
- toolCallIdAliases.set(callIdRaw, callId);
940
- }
941
- if (typeof name !== 'string' || !name.trim()) {
942
- // 缺少函数名:不生成 function_call,避免 downstream 进入错误循环
943
- // 将内容留给文本路径或后续消息拼接处理
944
- currentLastCall = null;
945
- continue;
946
- }
947
- const serialized = normalizeArgumentsBySchema(parsedArgs, name, toolsNormalized).trim();
948
- toolNameById.set(callId, name);
949
- toolArgsByIdLocal.set(callId, serialized);
950
- toolCalls.push({ id: callId, type: 'function', function: { name, arguments: serialized } });
951
- currentLastCall = callId;
952
- continue;
953
- }
954
- if (type === 'function_call_output' || type === 'tool_result' || type === 'tool_message') {
955
- let toolCallId = block.tool_call_id || block.call_id || block.tool_use_id || block.id || currentLastCall;
956
- if (toolCallId && toolCallIdAliases.has(String(toolCallId))) {
957
- toolCallId = toolCallIdAliases.get(String(toolCallId)) || toolCallId;
958
- }
959
- else if (typeof toolCallId === 'string' && toolCallId.trim().length) {
960
- const normalized = normalizeFunctionCallId({ callId: toolCallId, fallback: toolCallId });
961
- if (normalized !== toolCallId) {
962
- toolCallIdAliases.set(toolCallId, normalized);
963
- }
964
- toolCallId = normalized;
965
- }
966
- const output = normalizeToolOutput(block);
967
- if (toolCallId) {
968
- try {
969
- // No rcc envelope: emit plain tool role message with text content (fallback message on empty)
970
- let contentStr = output != null ? String(output) : '';
971
- if (!contentStr || contentStr.trim().length === 0) {
972
- contentStr = 'Command succeeded (no output).';
973
- }
974
- const nm = toolNameById.get(String(toolCallId));
975
- const toolMsg = { role: 'tool', tool_call_id: String(toolCallId), content: contentStr };
976
- if (typeof nm === 'string' && nm.trim().length)
977
- toolMsg.name = nm;
978
- toolMessages.push(toolMsg);
979
- }
980
- catch {
981
- const fallback = (output ?? '');
982
- const nm = toolNameById.get(String(toolCallId));
983
- const toolMsg = { role: 'tool', tool_call_id: String(toolCallId), content: String(fallback) };
984
- if (typeof nm === 'string' && nm.trim().length)
985
- toolMsg.name = nm;
986
- toolMessages.push(toolMsg);
987
- }
988
- currentLastCall = null;
989
- }
990
- continue;
991
- }
992
- }
993
- const text = textParts.length ? textParts.join('\n').trim() : null;
994
- return { text, toolCalls, toolMessages, lastCallId: currentLastCall };
995
- }
996
- function sanitizeThink(s) {
997
- try {
998
- let out = s.replace(/<think>[\s\S]*?<\/think>/gi, '');
999
- out = out.replace(/```\s*think[\s\S]*?```/gi, '');
1000
- out = out.replace(/\n{3,}/g, '\n\n');
1001
- return out.trim();
1002
- }
1003
- catch {
1004
- return s;
1005
- }
1006
- }
1007
- function convertChatContentToResponses(content) {
1008
- if (content == null)
1009
- return [];
1010
- if (typeof content === 'string')
1011
- return [{ type: 'output_text', text: content }];
1012
- if (Array.isArray(content)) {
1013
- return content.map((part) => {
1014
- if (typeof part === 'string')
1015
- return { type: 'output_text', text: sanitizeThink(part) };
1016
- if (part && typeof part === 'object') {
1017
- if (typeof part.text === 'string')
1018
- return { type: 'output_text', text: sanitizeThink(part.text) };
1019
- return { type: part.type || 'output_text', text: sanitizeThink(part.text ?? '') };
1020
- }
1021
- return { type: 'output_text', text: sanitizeThink(String(part)) };
1022
- });
1023
- }
1024
- if (typeof content === 'object') {
1025
- try {
1026
- return [{ type: 'output_text', text: JSON.stringify(content) }];
1027
- }
1028
- catch {
1029
- return [{ type: 'output_text', text: String(content) }];
1030
- }
1031
- }
1032
- return [{ type: 'output_text', text: '' }];
1033
- }
1034
- function extractOutputText(parts, _toolCalls) {
1035
- if (parts.length > 0) {
1036
- const text = parts
1037
- .filter(p => typeof p.text === 'string')
1038
- .map(p => sanitizeThink(p.text))
1039
- .join('\n')
1040
- .trim();
1041
- if (text.length)
1042
- return text;
314
+ if (out.metadata) {
315
+ stripInternalToolingMetadata(out.metadata);
1043
316
  }
1044
- return '';
317
+ return out;
1045
318
  }
1046
319
  function unwrapData(value) {
1047
320
  let current = value;
@@ -1066,265 +339,5 @@ export function extractRequestIdFromResponse(response) {
1066
339
  }
1067
340
  return undefined;
1068
341
  }
342
+ export { buildChatResponseFromResponses } from '../shared/responses-response-utils.js';
1069
343
  // (imports moved to top)
1070
- function unwrapResponsesResponse(payload) {
1071
- if (!payload || typeof payload !== 'object')
1072
- return undefined;
1073
- if (typeof payload.object === 'string' && payload.object === 'response') {
1074
- return payload;
1075
- }
1076
- if (Array.isArray(payload.output) ||
1077
- typeof payload.status === 'string' ||
1078
- payload.required_action) {
1079
- return payload;
1080
- }
1081
- let current = payload;
1082
- const visited = new Set();
1083
- while (current && typeof current === 'object' && !Array.isArray(current)) {
1084
- if (visited.has(current))
1085
- break;
1086
- visited.add(current);
1087
- if (typeof current.object === 'string' && current.object === 'response') {
1088
- return current;
1089
- }
1090
- if (current.response && typeof current.response === 'object') {
1091
- current = current.response;
1092
- continue;
1093
- }
1094
- if (current.data && typeof current.data === 'object') {
1095
- current = current.data;
1096
- continue;
1097
- }
1098
- break;
1099
- }
1100
- return undefined;
1101
- }
1102
- function collectMessageTexts(blocks) {
1103
- const parts = [];
1104
- const pushText = (value) => {
1105
- if (typeof value === 'string' && value.trim().length) {
1106
- parts.push(sanitizeThink(value));
1107
- }
1108
- };
1109
- if (typeof blocks === 'string') {
1110
- pushText(blocks);
1111
- return parts;
1112
- }
1113
- if (!Array.isArray(blocks))
1114
- return parts;
1115
- for (const block of blocks) {
1116
- if (!block || typeof block !== 'object')
1117
- continue;
1118
- const type = typeof block.type === 'string' ? String(block.type).toLowerCase() : '';
1119
- if (type === 'text' || type === 'input_text' || type === 'output_text' || type === 'commentary') {
1120
- pushText(block.text ?? block.content);
1121
- continue;
1122
- }
1123
- if (Array.isArray(block.content)) {
1124
- parts.push(...collectMessageTexts(block.content));
1125
- continue;
1126
- }
1127
- if (typeof block.text === 'string') {
1128
- pushText(block.text);
1129
- }
1130
- }
1131
- return parts;
1132
- }
1133
- function collectResponseOutput(response) {
1134
- const textParts = [];
1135
- const reasoningParts = [];
1136
- const outputItems = Array.isArray(response.output) ? response.output : [];
1137
- for (const item of outputItems) {
1138
- if (!item || typeof item !== 'object')
1139
- continue;
1140
- const type = typeof item.type === 'string' ? String(item.type).toLowerCase() : '';
1141
- if (type === 'message') {
1142
- const message = item.message && typeof item.message === 'object'
1143
- ? item.message
1144
- : item;
1145
- const content = Array.isArray(message.content) ? message.content : [];
1146
- textParts.push(...collectMessageTexts(content));
1147
- continue;
1148
- }
1149
- if (type === 'output_text') {
1150
- if (typeof item.text === 'string') {
1151
- textParts.push(sanitizeThink(item.text));
1152
- }
1153
- continue;
1154
- }
1155
- if (type === 'reasoning') {
1156
- const content = Array.isArray(item.content) ? item.content : [];
1157
- for (const block of content) {
1158
- if (block && typeof block === 'object' && typeof block.text === 'string') {
1159
- const sanitized = sanitizeThink(block.text);
1160
- if (sanitized.length)
1161
- reasoningParts.push(sanitized);
1162
- }
1163
- }
1164
- }
1165
- }
1166
- return { textParts, reasoningParts };
1167
- }
1168
- function normalizeToolCallName(rawName) {
1169
- if (typeof rawName !== 'string' || !rawName.trim().length)
1170
- return undefined;
1171
- if (!rawName.includes('.'))
1172
- return rawName.trim();
1173
- return rawName.slice(rawName.indexOf('.') + 1).trim() || undefined;
1174
- }
1175
- function selectCallId(entry) {
1176
- const candidates = [
1177
- entry?.call_id,
1178
- entry?.tool_call_id,
1179
- entry?.tool_use_id,
1180
- entry?.id
1181
- ];
1182
- for (const candidate of candidates) {
1183
- if (typeof candidate === 'string' && candidate.trim().length > 0) {
1184
- return candidate;
1185
- }
1186
- }
1187
- return undefined;
1188
- }
1189
- function normalizeToolCall(entry, fallbackPrefix) {
1190
- if (!entry || typeof entry !== 'object')
1191
- return null;
1192
- const fn = entry.function || {};
1193
- const rawName = normalizeToolCallName(fn.name ?? entry.name);
1194
- if (!rawName)
1195
- return null;
1196
- const argsRaw = fn.arguments ?? entry.arguments ?? {};
1197
- const argsStr = typeof argsRaw === 'string'
1198
- ? argsRaw
1199
- : (() => { try {
1200
- return JSON.stringify(argsRaw ?? {});
1201
- }
1202
- catch {
1203
- return '{}';
1204
- } })();
1205
- const callIdRaw = selectCallId(entry);
1206
- const callId = normalizeFunctionCallId({
1207
- callId: callIdRaw,
1208
- fallback: `${fallbackPrefix}_${Math.random().toString(36).slice(2, 10)}`
1209
- });
1210
- return {
1211
- id: callId,
1212
- type: 'function',
1213
- function: {
1214
- name: rawName,
1215
- arguments: argsStr
1216
- }
1217
- };
1218
- }
1219
- function collectToolCallsFromResponses(response) {
1220
- const collected = [];
1221
- const seenIds = new Set();
1222
- const pushCall = (call, source) => {
1223
- if (!call)
1224
- return;
1225
- const key = typeof call.id === 'string' ? call.id : `${source}_${collected.length}`;
1226
- if (key && seenIds.has(key))
1227
- return;
1228
- if (key)
1229
- seenIds.add(key);
1230
- collected.push(call);
1231
- };
1232
- const required = response?.required_action?.submit_tool_outputs?.tool_calls;
1233
- if (Array.isArray(required)) {
1234
- for (const call of required) {
1235
- pushCall(normalizeToolCall(call, 'req_call'), 'req_call');
1236
- }
1237
- }
1238
- const outputItems = Array.isArray(response.output) ? response.output : [];
1239
- for (const item of outputItems) {
1240
- if (!item || typeof item !== 'object')
1241
- continue;
1242
- const type = typeof item.type === 'string' ? String(item.type).toLowerCase() : '';
1243
- if (type !== 'function_call')
1244
- continue;
1245
- pushCall(normalizeToolCall(item, 'output_call'), 'output_call');
1246
- }
1247
- return collected;
1248
- }
1249
- function resolveFinishReason(response, toolCalls) {
1250
- const meta = response.metadata && typeof response.metadata === 'object'
1251
- ? response.metadata
1252
- : undefined;
1253
- if (meta && typeof meta.finish_reason === 'string') {
1254
- return meta.finish_reason;
1255
- }
1256
- if (toolCalls.length > 0) {
1257
- return 'tool_calls';
1258
- }
1259
- const status = typeof response.status === 'string' ? response.status.toLowerCase() : '';
1260
- if (status === 'requires_action')
1261
- return 'tool_calls';
1262
- if (status === 'in_progress' || status === 'streaming')
1263
- return 'length';
1264
- if (status === 'cancelled')
1265
- return 'cancelled';
1266
- if (status === 'failed')
1267
- return 'error';
1268
- return 'stop';
1269
- }
1270
- /**
1271
- * 将非流式 ResponsesResponse 形状还原为等价的 ChatResponse 形状(用于闭环测试)。
1272
- *
1273
- * - id / model / created(_at) / usage → 直接透传
1274
- * - output_text / output[] → choices[0].message.content
1275
- * - required_action.submit_tool_outputs.tool_calls → choices[0].message.tool_calls
1276
- * - finish_reason:metadata.finish_reason 优先,其次 status/tool_calls 推断
1277
- *
1278
- * 若 payload 已是 ChatCompletion 形状,则直接返回。
1279
- */
1280
- export function buildChatResponseFromResponses(payload) {
1281
- if (!payload || typeof payload !== 'object')
1282
- return payload;
1283
- const response = unwrapResponsesResponse(payload);
1284
- if (!response) {
1285
- if (Array.isArray(payload.choices))
1286
- return payload;
1287
- return payload;
1288
- }
1289
- const id = typeof response.id === 'string' ? response.id : `resp_${Date.now()}`;
1290
- const model = response.model;
1291
- const created = typeof response.created_at === 'number'
1292
- ? response.created_at
1293
- : (response.created ?? Math.floor(Date.now() / 1000));
1294
- const usage = response.usage;
1295
- const toolCalls = collectToolCallsFromResponses(response);
1296
- const { textParts, reasoningParts } = collectResponseOutput(response);
1297
- const explicitOutput = typeof response.output_text === 'string' && response.output_text.trim().length
1298
- ? sanitizeThink(response.output_text)
1299
- : undefined;
1300
- const messageContentText = explicitOutput || textParts.join('\n').trim();
1301
- const messageContent = messageContentText || '';
1302
- const message = {
1303
- role: 'assistant',
1304
- content: messageContent
1305
- };
1306
- if (toolCalls.length) {
1307
- message.tool_calls = toolCalls;
1308
- }
1309
- if (reasoningParts.length) {
1310
- message.reasoning_content = reasoningParts.join('\n');
1311
- }
1312
- const finishReason = resolveFinishReason(response, toolCalls);
1313
- const chat = {
1314
- id,
1315
- object: 'chat.completion',
1316
- created,
1317
- model,
1318
- choices: [
1319
- {
1320
- index: 0,
1321
- finish_reason: finishReason,
1322
- message
1323
- }
1324
- ]
1325
- };
1326
- if (usage !== undefined) {
1327
- chat.usage = usage;
1328
- }
1329
- return chat;
1330
- }