@jsonstudio/llms 0.4.2

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 (538) hide show
  1. package/README.md +265 -0
  2. package/dist/api/index.d.ts +10 -0
  3. package/dist/api/index.js +11 -0
  4. package/dist/api/llmswitch-config.d.ts +15 -0
  5. package/dist/api/llmswitch-config.js +415 -0
  6. package/dist/api/llmswitch-types.d.ts +412 -0
  7. package/dist/api/llmswitch-types.js +60 -0
  8. package/dist/bridge/routecodex-adapter.d.ts +74 -0
  9. package/dist/bridge/routecodex-adapter.js +226 -0
  10. package/dist/config/index.d.ts +3 -0
  11. package/dist/config/index.js +5 -0
  12. package/dist/config-unified/enhanced-path-resolver.d.ts +5 -0
  13. package/dist/config-unified/enhanced-path-resolver.js +38 -0
  14. package/dist/config-unified/unified-config.d.ts +26 -0
  15. package/dist/config-unified/unified-config.js +187 -0
  16. package/dist/conversion/codec-registry.d.ts +10 -0
  17. package/dist/conversion/codec-registry.js +25 -0
  18. package/dist/conversion/codecs/anthropic-openai-codec.d.ts +23 -0
  19. package/dist/conversion/codecs/anthropic-openai-codec.js +546 -0
  20. package/dist/conversion/codecs/gemini-openai-codec.d.ts +16 -0
  21. package/dist/conversion/codecs/gemini-openai-codec.js +437 -0
  22. package/dist/conversion/codecs/openai-openai-codec.d.ts +12 -0
  23. package/dist/conversion/codecs/openai-openai-codec.js +125 -0
  24. package/dist/conversion/codecs/responses-openai-codec.d.ts +12 -0
  25. package/dist/conversion/codecs/responses-openai-codec.js +154 -0
  26. package/dist/conversion/config/config-manager.d.ts +212 -0
  27. package/dist/conversion/config/config-manager.js +310 -0
  28. package/dist/conversion/conversion-v3/adapters/index.d.ts +2 -0
  29. package/dist/conversion/conversion-v3/adapters/index.js +1 -0
  30. package/dist/conversion/conversion-v3/adapters/v3-to-standard-adapter.d.ts +38 -0
  31. package/dist/conversion/conversion-v3/adapters/v3-to-standard-adapter.js +55 -0
  32. package/dist/conversion/conversion-v3/compatibility/compatibility-profiles.d.ts +22 -0
  33. package/dist/conversion/conversion-v3/compatibility/compatibility-profiles.js +84 -0
  34. package/dist/conversion/conversion-v3/compatibility/compatibility-stages.d.ts +4 -0
  35. package/dist/conversion/conversion-v3/compatibility/compatibility-stages.js +285 -0
  36. package/dist/conversion/conversion-v3/compatibility/index.d.ts +3 -0
  37. package/dist/conversion/conversion-v3/compatibility/index.js +2 -0
  38. package/dist/conversion/conversion-v3/config/default-configs.d.ts +48 -0
  39. package/dist/conversion/conversion-v3/config/default-configs.js +1083 -0
  40. package/dist/conversion/conversion-v3/config/index.d.ts +5 -0
  41. package/dist/conversion/conversion-v3/config/index.js +5 -0
  42. package/dist/conversion/conversion-v3/config/pipeline-config-manager.d.ts +49 -0
  43. package/dist/conversion/conversion-v3/config/pipeline-config-manager.js +65 -0
  44. package/dist/conversion/conversion-v3/index.d.ts +11 -0
  45. package/dist/conversion/conversion-v3/index.js +17 -0
  46. package/dist/conversion/conversion-v3/nodes/index.d.ts +56 -0
  47. package/dist/conversion/conversion-v3/nodes/index.js +149 -0
  48. package/dist/conversion/conversion-v3/nodes/input/anthropic-input-node.d.ts +25 -0
  49. package/dist/conversion/conversion-v3/nodes/input/anthropic-input-node.js +56 -0
  50. package/dist/conversion/conversion-v3/nodes/input/base-input-node.d.ts +75 -0
  51. package/dist/conversion/conversion-v3/nodes/input/base-input-node.js +237 -0
  52. package/dist/conversion/conversion-v3/nodes/input/chat-input-node.d.ts +25 -0
  53. package/dist/conversion/conversion-v3/nodes/input/chat-input-node.js +56 -0
  54. package/dist/conversion/conversion-v3/nodes/input/chat-shape-helpers.d.ts +4 -0
  55. package/dist/conversion/conversion-v3/nodes/input/chat-shape-helpers.js +197 -0
  56. package/dist/conversion/conversion-v3/nodes/input/gemini-input-node.d.ts +16 -0
  57. package/dist/conversion/conversion-v3/nodes/input/gemini-input-node.js +125 -0
  58. package/dist/conversion/conversion-v3/nodes/input/index.d.ts +8 -0
  59. package/dist/conversion/conversion-v3/nodes/input/index.js +8 -0
  60. package/dist/conversion/conversion-v3/nodes/input/input-decision.d.ts +46 -0
  61. package/dist/conversion/conversion-v3/nodes/input/input-decision.js +125 -0
  62. package/dist/conversion/conversion-v3/nodes/input/responses-input-node.d.ts +20 -0
  63. package/dist/conversion/conversion-v3/nodes/input/responses-input-node.js +51 -0
  64. package/dist/conversion/conversion-v3/nodes/output/anthropic-output-node.d.ts +71 -0
  65. package/dist/conversion/conversion-v3/nodes/output/anthropic-output-node.js +320 -0
  66. package/dist/conversion/conversion-v3/nodes/output/base-output-node.d.ts +116 -0
  67. package/dist/conversion/conversion-v3/nodes/output/base-output-node.js +512 -0
  68. package/dist/conversion/conversion-v3/nodes/output/index.d.ts +7 -0
  69. package/dist/conversion/conversion-v3/nodes/output/index.js +7 -0
  70. package/dist/conversion/conversion-v3/nodes/output/openai-output-node.d.ts +71 -0
  71. package/dist/conversion/conversion-v3/nodes/output/openai-output-node.js +293 -0
  72. package/dist/conversion/conversion-v3/nodes/output/output-decision.d.ts +68 -0
  73. package/dist/conversion/conversion-v3/nodes/output/output-decision.js +161 -0
  74. package/dist/conversion/conversion-v3/nodes/output/responses-output-node.d.ts +64 -0
  75. package/dist/conversion/conversion-v3/nodes/output/responses-output-node.js +323 -0
  76. package/dist/conversion/conversion-v3/nodes/process/base-process-node.d.ts +72 -0
  77. package/dist/conversion/conversion-v3/nodes/process/base-process-node.js +246 -0
  78. package/dist/conversion/conversion-v3/nodes/process/chat-process-node.d.ts +135 -0
  79. package/dist/conversion/conversion-v3/nodes/process/chat-process-node.js +854 -0
  80. package/dist/conversion/conversion-v3/nodes/process/compatibility-process-node.d.ts +29 -0
  81. package/dist/conversion/conversion-v3/nodes/process/compatibility-process-node.js +181 -0
  82. package/dist/conversion/conversion-v3/nodes/process/index.d.ts +10 -0
  83. package/dist/conversion/conversion-v3/nodes/process/index.js +10 -0
  84. package/dist/conversion/conversion-v3/nodes/process/passthrough-process-node.d.ts +59 -0
  85. package/dist/conversion/conversion-v3/nodes/process/passthrough-process-node.js +243 -0
  86. package/dist/conversion/conversion-v3/nodes/process/response-process-node.d.ts +17 -0
  87. package/dist/conversion/conversion-v3/nodes/process/response-process-node.js +213 -0
  88. package/dist/conversion/conversion-v3/nodes/process/tool-process-node.d.ts +26 -0
  89. package/dist/conversion/conversion-v3/nodes/process/tool-process-node.js +299 -0
  90. package/dist/conversion/conversion-v3/nodes/process/virtual-router-process-node.d.ts +40 -0
  91. package/dist/conversion/conversion-v3/nodes/process/virtual-router-process-node.js +430 -0
  92. package/dist/conversion/conversion-v3/nodes/response/anthropic-response-input-node.d.ts +12 -0
  93. package/dist/conversion/conversion-v3/nodes/response/anthropic-response-input-node.js +129 -0
  94. package/dist/conversion/conversion-v3/nodes/response/chat-to-responses-response-node.d.ts +15 -0
  95. package/dist/conversion/conversion-v3/nodes/response/chat-to-responses-response-node.js +57 -0
  96. package/dist/conversion/conversion-v3/nodes/response/index.d.ts +4 -0
  97. package/dist/conversion/conversion-v3/nodes/response/index.js +4 -0
  98. package/dist/conversion/conversion-v3/nodes/response/openai-response-input-node.d.ts +15 -0
  99. package/dist/conversion/conversion-v3/nodes/response/openai-response-input-node.js +87 -0
  100. package/dist/conversion/conversion-v3/nodes/response/response-utils.d.ts +1 -0
  101. package/dist/conversion/conversion-v3/nodes/response/response-utils.js +1 -0
  102. package/dist/conversion/conversion-v3/nodes/response/responses-response-input-node.d.ts +12 -0
  103. package/dist/conversion/conversion-v3/nodes/response/responses-response-input-node.js +67 -0
  104. package/dist/conversion/conversion-v3/nodes/sse/index.d.ts +3 -0
  105. package/dist/conversion/conversion-v3/nodes/sse/index.js +3 -0
  106. package/dist/conversion/conversion-v3/nodes/sse/sse-input-node.d.ts +27 -0
  107. package/dist/conversion/conversion-v3/nodes/sse/sse-input-node.js +165 -0
  108. package/dist/conversion/conversion-v3/nodes/sse/sse-output-node.d.ts +19 -0
  109. package/dist/conversion/conversion-v3/nodes/sse/sse-output-node.js +267 -0
  110. package/dist/conversion/conversion-v3/nodes/sse/sse-passthrough-node.d.ts +18 -0
  111. package/dist/conversion/conversion-v3/nodes/sse/sse-passthrough-node.js +48 -0
  112. package/dist/conversion/conversion-v3/pipelines/index.d.ts +6 -0
  113. package/dist/conversion/conversion-v3/pipelines/index.js +6 -0
  114. package/dist/conversion/conversion-v3/pipelines/super-pipeline.d.ts +112 -0
  115. package/dist/conversion/conversion-v3/pipelines/super-pipeline.js +566 -0
  116. package/dist/conversion/conversion-v3/response/provider-response-converter.d.ts +28 -0
  117. package/dist/conversion/conversion-v3/response/provider-response-converter.js +249 -0
  118. package/dist/conversion/conversion-v3/sse/index.d.ts +140 -0
  119. package/dist/conversion/conversion-v3/sse/index.js +115 -0
  120. package/dist/conversion/conversion-v3/sse/json-to-sse/anthropic-json-to-sse-converter.d.ts +11 -0
  121. package/dist/conversion/conversion-v3/sse/json-to-sse/anthropic-json-to-sse-converter.js +79 -0
  122. package/dist/conversion/conversion-v3/sse/json-to-sse/chat-json-to-sse-converter.d.ts +79 -0
  123. package/dist/conversion/conversion-v3/sse/json-to-sse/chat-json-to-sse-converter.js +296 -0
  124. package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/chat.d.ts +55 -0
  125. package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/chat.js +233 -0
  126. package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/responses.d.ts +99 -0
  127. package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/responses.js +599 -0
  128. package/dist/conversion/conversion-v3/sse/json-to-sse/index.d.ts +6 -0
  129. package/dist/conversion/conversion-v3/sse/json-to-sse/index.js +7 -0
  130. package/dist/conversion/conversion-v3/sse/json-to-sse/responses-json-to-sse-converter.d.ts +79 -0
  131. package/dist/conversion/conversion-v3/sse/json-to-sse/responses-json-to-sse-converter.js +322 -0
  132. package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/chat-sequencer.d.ts +37 -0
  133. package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/chat-sequencer.js +218 -0
  134. package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/responses-sequencer.d.ts +40 -0
  135. package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/responses-sequencer.js +263 -0
  136. package/dist/conversion/conversion-v3/sse/registry/sse-codec-registry.d.ts +32 -0
  137. package/dist/conversion/conversion-v3/sse/registry/sse-codec-registry.js +106 -0
  138. package/dist/conversion/conversion-v3/sse/shared/chat-serializer.d.ts +4 -0
  139. package/dist/conversion/conversion-v3/sse/shared/chat-serializer.js +40 -0
  140. package/dist/conversion/conversion-v3/sse/shared/constants.d.ts +272 -0
  141. package/dist/conversion/conversion-v3/sse/shared/constants.js +321 -0
  142. package/dist/conversion/conversion-v3/sse/shared/serializers/base-serializer.d.ts +158 -0
  143. package/dist/conversion/conversion-v3/sse/shared/serializers/base-serializer.js +210 -0
  144. package/dist/conversion/conversion-v3/sse/shared/serializers/chat-event-serializer.d.ts +82 -0
  145. package/dist/conversion/conversion-v3/sse/shared/serializers/chat-event-serializer.js +275 -0
  146. package/dist/conversion/conversion-v3/sse/shared/serializers/index.d.ts +39 -0
  147. package/dist/conversion/conversion-v3/sse/shared/serializers/index.js +54 -0
  148. package/dist/conversion/conversion-v3/sse/shared/serializers/responses-event-serializer.d.ts +123 -0
  149. package/dist/conversion/conversion-v3/sse/shared/serializers/responses-event-serializer.js +356 -0
  150. package/dist/conversion/conversion-v3/sse/shared/serializers/types.d.ts +51 -0
  151. package/dist/conversion/conversion-v3/sse/shared/serializers/types.js +4 -0
  152. package/dist/conversion/conversion-v3/sse/shared/utils.d.ts +254 -0
  153. package/dist/conversion/conversion-v3/sse/shared/utils.js +543 -0
  154. package/dist/conversion/conversion-v3/sse/shared/writer.d.ts +111 -0
  155. package/dist/conversion/conversion-v3/sse/shared/writer.js +268 -0
  156. package/dist/conversion/conversion-v3/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +13 -0
  157. package/dist/conversion/conversion-v3/sse/sse-to-json/anthropic-sse-to-json-converter.js +139 -0
  158. package/dist/conversion/conversion-v3/sse/sse-to-json/builders/response-builder.d.ts +165 -0
  159. package/dist/conversion/conversion-v3/sse/sse-to-json/builders/response-builder.js +776 -0
  160. package/dist/conversion/conversion-v3/sse/sse-to-json/chat-sse-to-json-converter.d.ts +106 -0
  161. package/dist/conversion/conversion-v3/sse/sse-to-json/chat-sse-to-json-converter.js +540 -0
  162. package/dist/conversion/conversion-v3/sse/sse-to-json/index.d.ts +6 -0
  163. package/dist/conversion/conversion-v3/sse/sse-to-json/index.js +7 -0
  164. package/dist/conversion/conversion-v3/sse/sse-to-json/parsers/sse-parser.d.ts +73 -0
  165. package/dist/conversion/conversion-v3/sse/sse-to-json/parsers/sse-parser.js +332 -0
  166. package/dist/conversion/conversion-v3/sse/sse-to-json/responses-sse-to-json-converter.d.ts +59 -0
  167. package/dist/conversion/conversion-v3/sse/sse-to-json/responses-sse-to-json-converter.js +270 -0
  168. package/dist/conversion/conversion-v3/sse/types/anthropic-types.d.ts +87 -0
  169. package/dist/conversion/conversion-v3/sse/types/anthropic-types.js +5 -0
  170. package/dist/conversion/conversion-v3/sse/types/chat-types.d.ts +308 -0
  171. package/dist/conversion/conversion-v3/sse/types/chat-types.js +32 -0
  172. package/dist/conversion/conversion-v3/sse/types/conversion-context.d.ts +211 -0
  173. package/dist/conversion/conversion-v3/sse/types/conversion-context.js +20 -0
  174. package/dist/conversion/conversion-v3/sse/types/core-interfaces.d.ts +90 -0
  175. package/dist/conversion/conversion-v3/sse/types/core-interfaces.js +5 -0
  176. package/dist/conversion/conversion-v3/sse/types/index.d.ts +14 -0
  177. package/dist/conversion/conversion-v3/sse/types/index.js +7 -0
  178. package/dist/conversion/conversion-v3/sse/types/responses-types.d.ts +328 -0
  179. package/dist/conversion/conversion-v3/sse/types/responses-types.js +38 -0
  180. package/dist/conversion/conversion-v3/sse/types/sse-events.d.ts +180 -0
  181. package/dist/conversion/conversion-v3/sse/types/sse-events.js +150 -0
  182. package/dist/conversion/conversion-v3/sse/types/stream-state.d.ts +204 -0
  183. package/dist/conversion/conversion-v3/sse/types/stream-state.js +44 -0
  184. package/dist/conversion/conversion-v3/sse/types/utility-types.d.ts +230 -0
  185. package/dist/conversion/conversion-v3/sse/types/utility-types.js +49 -0
  186. package/dist/conversion/conversion-v3/standards/context-adapter.d.ts +146 -0
  187. package/dist/conversion/conversion-v3/standards/context-adapter.js +438 -0
  188. package/dist/conversion/conversion-v3/standards/errors.d.ts +38 -0
  189. package/dist/conversion/conversion-v3/standards/errors.js +27 -0
  190. package/dist/conversion/conversion-v3/standards/index.d.ts +15 -0
  191. package/dist/conversion/conversion-v3/standards/index.js +11 -0
  192. package/dist/conversion/conversion-v3/standards/node-capabilities.d.ts +123 -0
  193. package/dist/conversion/conversion-v3/standards/node-capabilities.js +330 -0
  194. package/dist/conversion/conversion-v3/standards/pipeline-context.d.ts +237 -0
  195. package/dist/conversion/conversion-v3/standards/pipeline-context.js +84 -0
  196. package/dist/conversion/conversion-v3/standards/pipeline-node.d.ts +196 -0
  197. package/dist/conversion/conversion-v3/standards/pipeline-node.js +316 -0
  198. package/dist/conversion/conversion-v3/standards/snapshot-handles.d.ts +24 -0
  199. package/dist/conversion/conversion-v3/standards/snapshot-handles.js +49 -0
  200. package/dist/conversion/conversion-v3/types/config-types.d.ts +242 -0
  201. package/dist/conversion/conversion-v3/types/config-types.js +13 -0
  202. package/dist/conversion/conversion-v3/types/index.d.ts +8 -0
  203. package/dist/conversion/conversion-v3/types/index.js +11 -0
  204. package/dist/conversion/conversion-v3/types/node-types.d.ts +211 -0
  205. package/dist/conversion/conversion-v3/types/node-types.js +20 -0
  206. package/dist/conversion/conversion-v3/types/pipeline-types.d.ts +246 -0
  207. package/dist/conversion/conversion-v3/types/pipeline-types.js +26 -0
  208. package/dist/conversion/conversion-v3/types/request-types.d.ts +293 -0
  209. package/dist/conversion/conversion-v3/types/request-types.js +26 -0
  210. package/dist/conversion/conversion-v3/utils/provider-payload-sanitizer.d.ts +10 -0
  211. package/dist/conversion/conversion-v3/utils/provider-payload-sanitizer.js +103 -0
  212. package/dist/conversion/conversion-v3/validations/index.d.ts +8 -0
  213. package/dist/conversion/conversion-v3/validations/index.js +7 -0
  214. package/dist/conversion/conversion-v3/validations/node-graph-validator.d.ts +116 -0
  215. package/dist/conversion/conversion-v3/validations/node-graph-validator.js +505 -0
  216. package/dist/conversion/conversion-v3/validations/tool-governance-enforcer.d.ts +139 -0
  217. package/dist/conversion/conversion-v3/validations/tool-governance-enforcer.js +338 -0
  218. package/dist/conversion/hub/config/types.d.ts +26 -0
  219. package/dist/conversion/hub/config/types.js +1 -0
  220. package/dist/conversion/hub/core/detour-registry.d.ts +9 -0
  221. package/dist/conversion/hub/core/detour-registry.js +23 -0
  222. package/dist/conversion/hub/core/hub-context.d.ts +21 -0
  223. package/dist/conversion/hub/core/hub-context.js +1 -0
  224. package/dist/conversion/hub/core/index.d.ts +3 -0
  225. package/dist/conversion/hub/core/index.js +3 -0
  226. package/dist/conversion/hub/core/stage-driver.d.ts +30 -0
  227. package/dist/conversion/hub/core/stage-driver.js +31 -0
  228. package/dist/conversion/hub/format-adapters/anthropic-format-adapter.d.ts +16 -0
  229. package/dist/conversion/hub/format-adapters/anthropic-format-adapter.js +23 -0
  230. package/dist/conversion/hub/format-adapters/chat-format-adapter.d.ts +17 -0
  231. package/dist/conversion/hub/format-adapters/chat-format-adapter.js +23 -0
  232. package/dist/conversion/hub/format-adapters/gemini-format-adapter.d.ts +16 -0
  233. package/dist/conversion/hub/format-adapters/gemini-format-adapter.js +23 -0
  234. package/dist/conversion/hub/format-adapters/index.d.ts +21 -0
  235. package/dist/conversion/hub/format-adapters/index.js +4 -0
  236. package/dist/conversion/hub/format-adapters/responses-format-adapter.d.ts +17 -0
  237. package/dist/conversion/hub/format-adapters/responses-format-adapter.js +23 -0
  238. package/dist/conversion/hub/hub-feature.d.ts +1 -0
  239. package/dist/conversion/hub/hub-feature.js +25 -0
  240. package/dist/conversion/hub/node-support.d.ts +19 -0
  241. package/dist/conversion/hub/node-support.js +115 -0
  242. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +68 -0
  243. package/dist/conversion/hub/pipeline/hub-pipeline.js +421 -0
  244. package/dist/conversion/hub/pipelines/inbound.d.ts +22 -0
  245. package/dist/conversion/hub/pipelines/inbound.js +64 -0
  246. package/dist/conversion/hub/pipelines/outbound.d.ts +22 -0
  247. package/dist/conversion/hub/pipelines/outbound.js +57 -0
  248. package/dist/conversion/hub/process/chat-process.d.ts +13 -0
  249. package/dist/conversion/hub/process/chat-process.js +50 -0
  250. package/dist/conversion/hub/registry.d.ts +28 -0
  251. package/dist/conversion/hub/registry.js +98 -0
  252. package/dist/conversion/hub/response/chat-response-utils.d.ts +6 -0
  253. package/dist/conversion/hub/response/chat-response-utils.js +89 -0
  254. package/dist/conversion/hub/response/provider-response.d.ts +20 -0
  255. package/dist/conversion/hub/response/provider-response.js +196 -0
  256. package/dist/conversion/hub/response/response-mappers.d.ts +19 -0
  257. package/dist/conversion/hub/response/response-mappers.js +23 -0
  258. package/dist/conversion/hub/response/response-runtime.d.ts +3 -0
  259. package/dist/conversion/hub/response/response-runtime.js +206 -0
  260. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.d.ts +7 -0
  261. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +308 -0
  262. package/dist/conversion/hub/semantic-mappers/chat-mapper.d.ts +7 -0
  263. package/dist/conversion/hub/semantic-mappers/chat-mapper.js +304 -0
  264. package/dist/conversion/hub/semantic-mappers/gemini-mapper.d.ts +7 -0
  265. package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +477 -0
  266. package/dist/conversion/hub/semantic-mappers/index.d.ts +4 -0
  267. package/dist/conversion/hub/semantic-mappers/index.js +4 -0
  268. package/dist/conversion/hub/semantic-mappers/responses-mapper.d.ts +21 -0
  269. package/dist/conversion/hub/semantic-mappers/responses-mapper.js +379 -0
  270. package/dist/conversion/hub/snapshot-recorder.d.ts +12 -0
  271. package/dist/conversion/hub/snapshot-recorder.js +69 -0
  272. package/dist/conversion/hub/standardized-bridge.d.ts +12 -0
  273. package/dist/conversion/hub/standardized-bridge.js +248 -0
  274. package/dist/conversion/hub/types/chat-envelope.d.ts +67 -0
  275. package/dist/conversion/hub/types/chat-envelope.js +1 -0
  276. package/dist/conversion/hub/types/chat-schema.d.ts +112 -0
  277. package/dist/conversion/hub/types/chat-schema.js +1 -0
  278. package/dist/conversion/hub/types/errors.d.ts +5 -0
  279. package/dist/conversion/hub/types/errors.js +13 -0
  280. package/dist/conversion/hub/types/format-envelope.d.ts +7 -0
  281. package/dist/conversion/hub/types/format-envelope.js +1 -0
  282. package/dist/conversion/hub/types/index.d.ts +6 -0
  283. package/dist/conversion/hub/types/index.js +6 -0
  284. package/dist/conversion/hub/types/json.d.ts +9 -0
  285. package/dist/conversion/hub/types/json.js +9 -0
  286. package/dist/conversion/hub/types/node.d.ts +31 -0
  287. package/dist/conversion/hub/types/node.js +1 -0
  288. package/dist/conversion/hub/types/standardized.d.ts +94 -0
  289. package/dist/conversion/hub/types/standardized.js +1 -0
  290. package/dist/conversion/index.d.ts +28 -0
  291. package/dist/conversion/index.js +28 -0
  292. package/dist/conversion/responses/responses-openai-bridge.d.ts +95 -0
  293. package/dist/conversion/responses/responses-openai-bridge.js +1330 -0
  294. package/dist/conversion/schema-validator.d.ts +7 -0
  295. package/dist/conversion/schema-validator.js +67 -0
  296. package/dist/conversion/shared/args-mapping.d.ts +18 -0
  297. package/dist/conversion/shared/args-mapping.js +213 -0
  298. package/dist/conversion/shared/chat-request-filters.d.ts +9 -0
  299. package/dist/conversion/shared/chat-request-filters.js +74 -0
  300. package/dist/conversion/shared/jsonish.d.ts +3 -0
  301. package/dist/conversion/shared/jsonish.js +177 -0
  302. package/dist/conversion/shared/mcp-injection.d.ts +2 -0
  303. package/dist/conversion/shared/mcp-injection.js +89 -0
  304. package/dist/conversion/shared/media.d.ts +1 -0
  305. package/dist/conversion/shared/media.js +9 -0
  306. package/dist/conversion/shared/openai-finalizer.d.ts +9 -0
  307. package/dist/conversion/shared/openai-finalizer.js +104 -0
  308. package/dist/conversion/shared/openai-message-normalize.d.ts +1 -0
  309. package/dist/conversion/shared/openai-message-normalize.js +442 -0
  310. package/dist/conversion/shared/payload-budget.d.ts +13 -0
  311. package/dist/conversion/shared/payload-budget.js +248 -0
  312. package/dist/conversion/shared/reasoning-mapping.d.ts +5 -0
  313. package/dist/conversion/shared/reasoning-mapping.js +8 -0
  314. package/dist/conversion/shared/responses-conversation-store.d.ts +41 -0
  315. package/dist/conversion/shared/responses-conversation-store.js +285 -0
  316. package/dist/conversion/shared/responses-id-utils.d.ts +7 -0
  317. package/dist/conversion/shared/responses-id-utils.js +29 -0
  318. package/dist/conversion/shared/responses-instructions.d.ts +1 -0
  319. package/dist/conversion/shared/responses-instructions.js +113 -0
  320. package/dist/conversion/shared/responses-metadata.d.ts +1 -0
  321. package/dist/conversion/shared/responses-metadata.js +1 -0
  322. package/dist/conversion/shared/responses-request-adapter.d.ts +66 -0
  323. package/dist/conversion/shared/responses-request-adapter.js +461 -0
  324. package/dist/conversion/shared/snapshot-hooks.d.ts +12 -0
  325. package/dist/conversion/shared/snapshot-hooks.js +7 -0
  326. package/dist/conversion/shared/streaming-text-extractor.d.ts +26 -0
  327. package/dist/conversion/shared/streaming-text-extractor.js +145 -0
  328. package/dist/conversion/shared/text-markup-normalizer.d.ts +9 -0
  329. package/dist/conversion/shared/text-markup-normalizer.js +319 -0
  330. package/dist/conversion/shared/tool-canonicalizer.d.ts +2 -0
  331. package/dist/conversion/shared/tool-canonicalizer.js +50 -0
  332. package/dist/conversion/shared/tool-filter-pipeline.d.ts +17 -0
  333. package/dist/conversion/shared/tool-filter-pipeline.js +79 -0
  334. package/dist/conversion/shared/tool-governor.d.ts +27 -0
  335. package/dist/conversion/shared/tool-governor.js +269 -0
  336. package/dist/conversion/shared/tool-harvester.d.ts +31 -0
  337. package/dist/conversion/shared/tool-harvester.js +321 -0
  338. package/dist/conversion/shared/tool-mapping.d.ts +10 -0
  339. package/dist/conversion/shared/tool-mapping.js +10 -0
  340. package/dist/conversion/shared/tooling.d.ts +26 -0
  341. package/dist/conversion/shared/tooling.js +143 -0
  342. package/dist/conversion/types.d.ts +33 -0
  343. package/dist/conversion/types.js +1 -0
  344. package/dist/core/index.d.ts +6 -0
  345. package/dist/core/index.js +9 -0
  346. package/dist/core/llmswitch-engine-v2.d.ts +132 -0
  347. package/dist/core/llmswitch-engine-v2.js +649 -0
  348. package/dist/core/llmswitch-factory-v2.d.ts +123 -0
  349. package/dist/core/llmswitch-factory-v2.js +521 -0
  350. package/dist/endpoints/base-endpoint-handler.d.ts +128 -0
  351. package/dist/endpoints/base-endpoint-handler.js +545 -0
  352. package/dist/endpoints/chat-endpoint-handler.d.ts +115 -0
  353. package/dist/endpoints/chat-endpoint-handler.js +218 -0
  354. package/dist/endpoints/endpoint-router.d.ts +127 -0
  355. package/dist/endpoints/endpoint-router.js +438 -0
  356. package/dist/endpoints/index.d.ts +13 -0
  357. package/dist/endpoints/index.js +11 -0
  358. package/dist/endpoints/messages-endpoint-handler.d.ts +171 -0
  359. package/dist/endpoints/messages-endpoint-handler.js +238 -0
  360. package/dist/endpoints/responses-endpoint-handler.d.ts +147 -0
  361. package/dist/endpoints/responses-endpoint-handler.js +233 -0
  362. package/dist/filters/builtin/add-fields-filter.d.ts +8 -0
  363. package/dist/filters/builtin/add-fields-filter.js +16 -0
  364. package/dist/filters/builtin/blacklist-filter.d.ts +8 -0
  365. package/dist/filters/builtin/blacklist-filter.js +19 -0
  366. package/dist/filters/builtin/whitelist-filter.d.ts +8 -0
  367. package/dist/filters/builtin/whitelist-filter.js +19 -0
  368. package/dist/filters/engine.d.ts +16 -0
  369. package/dist/filters/engine.js +167 -0
  370. package/dist/filters/index.d.ts +19 -0
  371. package/dist/filters/index.js +24 -0
  372. package/dist/filters/special/request-streaming-to-nonstreaming.d.ts +12 -0
  373. package/dist/filters/special/request-streaming-to-nonstreaming.js +27 -0
  374. package/dist/filters/special/request-tool-choice-policy.d.ts +11 -0
  375. package/dist/filters/special/request-tool-choice-policy.js +27 -0
  376. package/dist/filters/special/request-tool-list-filter.d.ts +11 -0
  377. package/dist/filters/special/request-tool-list-filter.js +167 -0
  378. package/dist/filters/special/request-toolcalls-stringify.d.ts +10 -0
  379. package/dist/filters/special/request-toolcalls-stringify.js +44 -0
  380. package/dist/filters/special/request-tools-normalize.d.ts +12 -0
  381. package/dist/filters/special/request-tools-normalize.js +140 -0
  382. package/dist/filters/special/response-finish-invariants.d.ts +11 -0
  383. package/dist/filters/special/response-finish-invariants.js +30 -0
  384. package/dist/filters/special/response-openai-to-responses-bridge.d.ts +13 -0
  385. package/dist/filters/special/response-openai-to-responses-bridge.js +24 -0
  386. package/dist/filters/special/response-tool-arguments-blacklist.d.ts +12 -0
  387. package/dist/filters/special/response-tool-arguments-blacklist.js +63 -0
  388. package/dist/filters/special/response-tool-arguments-schema-converge.d.ts +13 -0
  389. package/dist/filters/special/response-tool-arguments-schema-converge.js +63 -0
  390. package/dist/filters/special/response-tool-arguments-stringify.d.ts +9 -0
  391. package/dist/filters/special/response-tool-arguments-stringify.js +134 -0
  392. package/dist/filters/special/response-tool-arguments-toon-decode.d.ts +10 -0
  393. package/dist/filters/special/response-tool-arguments-toon-decode.js +94 -0
  394. package/dist/filters/special/response-tool-arguments-whitelist.d.ts +11 -0
  395. package/dist/filters/special/response-tool-arguments-whitelist.js +56 -0
  396. package/dist/filters/special/response-tool-text-canonicalize.d.ts +10 -0
  397. package/dist/filters/special/response-tool-text-canonicalize.js +20 -0
  398. package/dist/filters/special/tool-filter-hooks.d.ts +19 -0
  399. package/dist/filters/special/tool-filter-hooks.js +341 -0
  400. package/dist/filters/special/tool-post-constraints.d.ts +31 -0
  401. package/dist/filters/special/tool-post-constraints.js +120 -0
  402. package/dist/filters/types.d.ts +68 -0
  403. package/dist/filters/types.js +3 -0
  404. package/dist/filters/utils/fieldmap-loader.d.ts +2 -0
  405. package/dist/filters/utils/fieldmap-loader.js +16 -0
  406. package/dist/filters/utils/snapshot-writer.d.ts +10 -0
  407. package/dist/filters/utils/snapshot-writer.js +47 -0
  408. package/dist/guidance/index.d.ts +3 -0
  409. package/dist/guidance/index.js +228 -0
  410. package/dist/hooks/hooks-integration.d.ts +161 -0
  411. package/dist/hooks/hooks-integration.js +519 -0
  412. package/dist/hooks/index.d.ts +10 -0
  413. package/dist/hooks/index.js +13 -0
  414. package/dist/html-to-markdown.d.ts +5 -0
  415. package/dist/html-to-markdown.js +66 -0
  416. package/dist/http/sse-response.d.ts +22 -0
  417. package/dist/http/sse-response.js +103 -0
  418. package/dist/index.d.ts +10 -0
  419. package/dist/index.js +10 -0
  420. package/dist/router/virtual-router/bootstrap.d.ts +6 -0
  421. package/dist/router/virtual-router/bootstrap.js +620 -0
  422. package/dist/router/virtual-router/classifier.d.ts +10 -0
  423. package/dist/router/virtual-router/classifier.js +99 -0
  424. package/dist/router/virtual-router/engine.d.ts +35 -0
  425. package/dist/router/virtual-router/engine.js +260 -0
  426. package/dist/router/virtual-router/error-center.d.ts +10 -0
  427. package/dist/router/virtual-router/error-center.js +39 -0
  428. package/dist/router/virtual-router/features.d.ts +3 -0
  429. package/dist/router/virtual-router/features.js +162 -0
  430. package/dist/router/virtual-router/health-manager.d.ts +18 -0
  431. package/dist/router/virtual-router/health-manager.js +98 -0
  432. package/dist/router/virtual-router/load-balancer.d.ts +18 -0
  433. package/dist/router/virtual-router/load-balancer.js +67 -0
  434. package/dist/router/virtual-router/provider-registry.d.ts +11 -0
  435. package/dist/router/virtual-router/provider-registry.js +74 -0
  436. package/dist/router/virtual-router/types.d.ts +206 -0
  437. package/dist/router/virtual-router/types.js +31 -0
  438. package/dist/sse/index.d.ts +140 -0
  439. package/dist/sse/index.js +115 -0
  440. package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.d.ts +11 -0
  441. package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.js +79 -0
  442. package/dist/sse/json-to-sse/chat-json-to-sse-converter.d.ts +79 -0
  443. package/dist/sse/json-to-sse/chat-json-to-sse-converter.js +296 -0
  444. package/dist/sse/json-to-sse/event-generators/chat.d.ts +55 -0
  445. package/dist/sse/json-to-sse/event-generators/chat.js +233 -0
  446. package/dist/sse/json-to-sse/event-generators/responses.d.ts +99 -0
  447. package/dist/sse/json-to-sse/event-generators/responses.js +599 -0
  448. package/dist/sse/json-to-sse/index.d.ts +6 -0
  449. package/dist/sse/json-to-sse/index.js +7 -0
  450. package/dist/sse/json-to-sse/responses-json-to-sse-converter.d.ts +79 -0
  451. package/dist/sse/json-to-sse/responses-json-to-sse-converter.js +322 -0
  452. package/dist/sse/json-to-sse/sequencers/chat-sequencer.d.ts +37 -0
  453. package/dist/sse/json-to-sse/sequencers/chat-sequencer.js +218 -0
  454. package/dist/sse/json-to-sse/sequencers/responses-sequencer.d.ts +40 -0
  455. package/dist/sse/json-to-sse/sequencers/responses-sequencer.js +263 -0
  456. package/dist/sse/registry/sse-codec-registry.d.ts +32 -0
  457. package/dist/sse/registry/sse-codec-registry.js +106 -0
  458. package/dist/sse/shared/chat-serializer.d.ts +4 -0
  459. package/dist/sse/shared/chat-serializer.js +40 -0
  460. package/dist/sse/shared/constants.d.ts +272 -0
  461. package/dist/sse/shared/constants.js +321 -0
  462. package/dist/sse/shared/serializers/base-serializer.d.ts +158 -0
  463. package/dist/sse/shared/serializers/base-serializer.js +210 -0
  464. package/dist/sse/shared/serializers/chat-event-serializer.d.ts +82 -0
  465. package/dist/sse/shared/serializers/chat-event-serializer.js +275 -0
  466. package/dist/sse/shared/serializers/index.d.ts +39 -0
  467. package/dist/sse/shared/serializers/index.js +54 -0
  468. package/dist/sse/shared/serializers/responses-event-serializer.d.ts +123 -0
  469. package/dist/sse/shared/serializers/responses-event-serializer.js +356 -0
  470. package/dist/sse/shared/serializers/types.d.ts +51 -0
  471. package/dist/sse/shared/serializers/types.js +4 -0
  472. package/dist/sse/shared/utils.d.ts +254 -0
  473. package/dist/sse/shared/utils.js +543 -0
  474. package/dist/sse/shared/writer.d.ts +111 -0
  475. package/dist/sse/shared/writer.js +268 -0
  476. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +13 -0
  477. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +139 -0
  478. package/dist/sse/sse-to-json/builders/response-builder.d.ts +165 -0
  479. package/dist/sse/sse-to-json/builders/response-builder.js +776 -0
  480. package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +106 -0
  481. package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +540 -0
  482. package/dist/sse/sse-to-json/index.d.ts +6 -0
  483. package/dist/sse/sse-to-json/index.js +7 -0
  484. package/dist/sse/sse-to-json/parsers/sse-parser.d.ts +73 -0
  485. package/dist/sse/sse-to-json/parsers/sse-parser.js +340 -0
  486. package/dist/sse/sse-to-json/responses-sse-to-json-converter.d.ts +59 -0
  487. package/dist/sse/sse-to-json/responses-sse-to-json-converter.js +270 -0
  488. package/dist/sse/types/anthropic-types.d.ts +87 -0
  489. package/dist/sse/types/anthropic-types.js +5 -0
  490. package/dist/sse/types/chat-types.d.ts +308 -0
  491. package/dist/sse/types/chat-types.js +32 -0
  492. package/dist/sse/types/conversion-context.d.ts +211 -0
  493. package/dist/sse/types/conversion-context.js +20 -0
  494. package/dist/sse/types/core-interfaces.d.ts +90 -0
  495. package/dist/sse/types/core-interfaces.js +5 -0
  496. package/dist/sse/types/index.d.ts +14 -0
  497. package/dist/sse/types/index.js +7 -0
  498. package/dist/sse/types/responses-types.d.ts +328 -0
  499. package/dist/sse/types/responses-types.js +38 -0
  500. package/dist/sse/types/sse-events.d.ts +180 -0
  501. package/dist/sse/types/sse-events.js +150 -0
  502. package/dist/sse/types/stream-state.d.ts +204 -0
  503. package/dist/sse/types/stream-state.js +44 -0
  504. package/dist/sse/types/utility-types.d.ts +230 -0
  505. package/dist/sse/types/utility-types.js +49 -0
  506. package/dist/tools/proxy/anthropic-tool-proxy.d.ts +19 -0
  507. package/dist/tools/proxy/anthropic-tool-proxy.js +57 -0
  508. package/dist/tools/proxy/executors/web-fetch.d.ts +6 -0
  509. package/dist/tools/proxy/executors/web-fetch.js +39 -0
  510. package/dist/tools/proxy/registry.d.ts +8 -0
  511. package/dist/tools/proxy/registry.js +14 -0
  512. package/dist/tools/proxy/types.d.ts +29 -0
  513. package/dist/tools/proxy/types.js +1 -0
  514. package/dist/tools/tool-registry.d.ts +8 -0
  515. package/dist/tools/tool-registry.js +154 -0
  516. package/dist/tools/web-fetch-html.d.ts +15 -0
  517. package/dist/tools/web-fetch-html.js +83 -0
  518. package/dist/utils/conversion-adapter.d.ts +65 -0
  519. package/dist/utils/conversion-adapter.js +183 -0
  520. package/dist/utils/error-factory.d.ts +88 -0
  521. package/dist/utils/error-factory.js +138 -0
  522. package/dist/utils/error-utils.d.ts +334 -0
  523. package/dist/utils/error-utils.js +782 -0
  524. package/dist/utils/index.d.ts +8 -0
  525. package/dist/utils/index.js +13 -0
  526. package/dist/utils/performance-utils.d.ts +205 -0
  527. package/dist/utils/performance-utils.js +440 -0
  528. package/dist/utils/profile-mapper.d.ts +32 -0
  529. package/dist/utils/profile-mapper.js +269 -0
  530. package/dist/utils/request-processor.d.ts +52 -0
  531. package/dist/utils/request-processor.js +210 -0
  532. package/dist/utils/request-utils.d.ts +117 -0
  533. package/dist/utils/request-utils.js +333 -0
  534. package/dist/utils/response-utils.d.ts +127 -0
  535. package/dist/utils/response-utils.js +516 -0
  536. package/dist/utils/token-counter.d.ts +89 -0
  537. package/dist/utils/token-counter.js +541 -0
  538. package/package.json +65 -0
@@ -0,0 +1,1330 @@
1
+ import { normalizeFunctionCallId, normalizeFunctionCallOutputId } from '../shared/responses-id-utils.js';
2
+ import { ensureResponsesInstructions } from '../shared/responses-instructions.js';
3
+ // --- Utilities (ported strictly) ---
4
+ import { canonicalizeChatResponseTools } from '../shared/tool-canonicalizer.js';
5
+ function isObject(v) {
6
+ return !!v && typeof v === 'object' && !Array.isArray(v);
7
+ }
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
+ // normalizeTools unified in ../shared/args-mapping.ts
13
+ // --- Structured self-repair helpers for tool failures (Responses path) ---
14
+ // use shared isImagePath
15
+ // 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
+ // --- Public bridge functions ---
78
+ export function captureResponsesContext(payload, dto) {
79
+ ensureResponsesInstructions(payload);
80
+ const context = {
81
+ requestId: dto?.route?.requestId,
82
+ instructions: typeof payload.instructions === 'string' ? payload.instructions : undefined,
83
+ input: Array.isArray(payload.input) ? payload.input : undefined,
84
+ include: payload.include,
85
+ store: payload.store,
86
+ toolChoice: payload.tool_choice,
87
+ parallelToolCalls: typeof payload.parallel_tool_calls === 'boolean' ? payload.parallel_tool_calls : undefined,
88
+ metadata: (payload.metadata && typeof payload.metadata === 'object') ? { ...payload.metadata } : undefined,
89
+ responseFormat: payload.response_format,
90
+ stream: typeof payload.stream === 'boolean' ? payload.stream : undefined,
91
+ isChatPayload: Array.isArray(payload.messages)
92
+ };
93
+ if (Array.isArray(payload.tools)) {
94
+ context.toolsRaw = payload.tools;
95
+ }
96
+ context.isResponsesPayload = !context.isChatPayload && Array.isArray(context.input);
97
+ return context;
98
+ }
99
+ export function buildChatRequestFromResponses(payload, context) {
100
+ // V3: 对 Responses 路径仅做“形状转换”,不做参数解析/修复。
101
+ // 将顶层 { type,name,description,parameters,strict } 归一为 OpenAI Chat tools 形状:
102
+ // { 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;
137
+ // 不在 Responses 路径进行 MCP 工具注入;统一由 Chat 后半段治理注入
138
+ let messages = mapResponsesInputToChat({
139
+ instructions: context.instructions,
140
+ input: context.input,
141
+ toolsNormalized
142
+ });
143
+ if (Array.isArray(context.originalSystemMessages) && context.originalSystemMessages.length) {
144
+ const preservedSystems = context.originalSystemMessages
145
+ .map(text => ({ role: 'system', content: text }))
146
+ .filter(message => typeof message.content === 'string');
147
+ if (preservedSystems.length) {
148
+ const nonSystemMessages = messages.filter((msg) => String(msg?.role).toLowerCase() !== 'system');
149
+ messages = [...preservedSystems, ...nonSystemMessages];
150
+ }
151
+ }
152
+ // 不在 Responses 路径做工具治理;统一在 Chat 后半段处理
153
+ // No system tips for MCP on OpenAI Responses path (avoid leaking tool names)
154
+ 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
+ }
192
+ }
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 */ }
201
+ const result = { model: payload.model, messages };
202
+ if (typeof payload.stream === 'boolean') {
203
+ result.stream = payload.stream;
204
+ }
205
+ for (const key of ['top_p', 'tool_choice', 'parallel_tool_calls', 'user', 'logit_bias', 'seed', 'response_format']) {
206
+ if (payload[key] !== undefined)
207
+ result[key] = payload[key];
208
+ }
209
+ if (typeof payload.max_tokens === 'number' && payload.max_output_tokens === undefined) {
210
+ payload.max_output_tokens = payload.max_tokens;
211
+ }
212
+ if (payload.max_output_tokens !== undefined) {
213
+ result.max_output_tokens = payload.max_output_tokens;
214
+ }
215
+ if (Array.isArray(toolsNormalized) && toolsNormalized.length)
216
+ result.tools = toolsNormalized;
217
+ return { request: result, toolsNormalized };
218
+ }
219
+ /**
220
+ * Chat 请求 → Responses 请求(非流),用于 V3 process=chat 且 providerWire=responses 的请求编码。
221
+ *
222
+ * 设计目标:
223
+ * - 保留 model / tools / tool_choice / parallel_tool_calls 等字段;
224
+ * - 将 system 消息折叠到 instructions;
225
+ * - 将 user/assistant/tool 消息编码为 input[] 中的 message 块,使得 mapResponsesInputToChat 能够还原为等价 Chat 请求。
226
+ */
227
+ export function buildResponsesRequestFromChat(payload, ctx) {
228
+ const chat = unwrapData(payload);
229
+ const out = {};
230
+ // 基本字段
231
+ out.model = chat.model;
232
+ // 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
+ });
252
+ }
253
+ const passthroughKeys = [
254
+ 'tool_choice',
255
+ 'parallel_tool_calls',
256
+ 'response_format',
257
+ 'user',
258
+ 'top_p',
259
+ 'max_output_tokens',
260
+ 'logit_bias',
261
+ 'seed'
262
+ ];
263
+ for (const key of passthroughKeys) {
264
+ if (chat[key] !== undefined)
265
+ out[key] = chat[key];
266
+ }
267
+ if (typeof chat.max_tokens === 'number' && chat.max_output_tokens === undefined) {
268
+ out.max_output_tokens = chat.max_tokens;
269
+ }
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}`
353
+ });
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}`
360
+ });
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;
421
+ }
422
+ }
423
+ }
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
+ }
436
+ }
437
+ }
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
+ // 不追加 metadata,以便 roundtrip 与原始 payload 对齐;系统提示直接写入 instructions。
455
+ if (input.length) {
456
+ out.input = input;
457
+ }
458
+ const streamFromChat = typeof chat.stream === 'boolean' ? chat.stream : undefined;
459
+ const streamFromParameters = chat?.parameters && typeof chat.parameters?.stream === 'boolean'
460
+ ? chat.parameters.stream
461
+ : undefined;
462
+ const resolvedStream = typeof ctx?.stream === 'boolean'
463
+ ? ctx.stream
464
+ : (streamFromChat !== undefined ? streamFromChat : streamFromParameters);
465
+ if (resolvedStream === true) {
466
+ out.stream = true;
467
+ }
468
+ else if (resolvedStream === false) {
469
+ out.stream = false;
470
+ }
471
+ ensureResponsesInstructions(out);
472
+ return { request: out, originalSystemMessages };
473
+ }
474
+ export function buildResponsesPayloadFromChat(payload, context) {
475
+ if (!payload || typeof payload !== 'object')
476
+ return payload;
477
+ const response = unwrapData(payload);
478
+ if (!response || typeof response !== 'object')
479
+ return payload;
480
+ // If provider already returned Responses shape, sanitize textual output to remove tool result envelopes
481
+ 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
+ return response;
516
+ }
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;
595
+ }
596
+ // Canonicalize response tools (Responses-style) before mapping to Responses blocks
597
+ const canonical = canonicalizeChatResponseTools(responseForBridge);
598
+ const choices = Array.isArray(canonical?.choices) ? canonical.choices : [];
599
+ const primaryChoice = choices[0] && typeof choices[0] === 'object' ? choices[0] : undefined;
600
+ 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
+ });
625
+ }
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) {
637
+ 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);
666
+ }
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
+ }
677
+ catch {
678
+ // ignore malformed tool call
679
+ }
680
+ }
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
+ }
696
+ try {
697
+ delete usage.input_tokens;
698
+ delete usage.output_tokens;
699
+ }
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
+ }
713
+ }
714
+ }
715
+ const out = {
716
+ id: response.id || `resp-${Date.now()}`,
717
+ object: 'response',
718
+ created_at: response.created_at || response.created || Math.floor(Date.now() / 1000),
719
+ model: response.model,
720
+ status,
721
+ output: outputItems,
722
+ output_text: outputText || ''
723
+ };
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 */ }
754
+ // Do not inject captured tool results here; keep Chat back-half behavior standard.
755
+ if (context) {
756
+ for (const k of ['metadata', 'instructions', 'parallel_tool_calls', 'tool_choice', 'include', 'store']) {
757
+ if (context[k] !== undefined)
758
+ out[k] = context[k];
759
+ }
760
+ }
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;
1043
+ }
1044
+ return '';
1045
+ }
1046
+ function unwrapData(value) {
1047
+ let current = value;
1048
+ const seen = new Set();
1049
+ while (current && typeof current === 'object' && !Array.isArray(current) && !seen.has(current)) {
1050
+ seen.add(current);
1051
+ if ('choices' in current || 'message' in current)
1052
+ break;
1053
+ if ('data' in current && typeof current.data === 'object') {
1054
+ current = current.data;
1055
+ continue;
1056
+ }
1057
+ break;
1058
+ }
1059
+ return current;
1060
+ }
1061
+ export function extractRequestIdFromResponse(response) {
1062
+ if (response && typeof response === 'object' && 'metadata' in response && response.metadata && typeof response.metadata === 'object') {
1063
+ const meta = response.metadata;
1064
+ if (typeof meta.requestId === 'string')
1065
+ return meta.requestId;
1066
+ }
1067
+ return undefined;
1068
+ }
1069
+ // (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
+ }