@aryee337/aery-ai 0.1.148 → 0.2.10

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 (592) hide show
  1. package/CHANGELOG.md +2914 -0
  2. package/README.md +614 -813
  3. package/dist/types/api-registry.d.ts +30 -0
  4. package/dist/types/auth-broker/client.d.ts +66 -0
  5. package/dist/types/auth-broker/index.d.ts +5 -0
  6. package/dist/types/auth-broker/refresher.d.ts +25 -0
  7. package/dist/types/auth-broker/remote-store.d.ts +96 -0
  8. package/dist/types/auth-broker/server.d.ts +32 -0
  9. package/dist/types/auth-broker/types.d.ts +105 -0
  10. package/dist/types/auth-broker/wire-schemas.d.ts +412 -0
  11. package/dist/types/auth-gateway/http.d.ts +39 -0
  12. package/dist/types/auth-gateway/index.d.ts +3 -0
  13. package/dist/types/auth-gateway/server.d.ts +36 -0
  14. package/dist/types/auth-gateway/types.d.ts +117 -0
  15. package/dist/types/auth-storage.d.ts +739 -0
  16. package/dist/types/index.d.ts +49 -0
  17. package/dist/types/model-cache.d.ts +17 -0
  18. package/dist/types/model-manager.d.ts +64 -0
  19. package/dist/types/model-thinking.d.ts +100 -0
  20. package/dist/types/models.d.ts +12 -0
  21. package/dist/types/provider-details.d.ts +24 -0
  22. package/dist/types/provider-models/bundled-references.d.ts +4 -0
  23. package/dist/types/provider-models/descriptors.d.ts +50 -0
  24. package/dist/types/provider-models/google.d.ts +24 -0
  25. package/dist/types/provider-models/index.d.ts +5 -0
  26. package/dist/types/provider-models/ollama.d.ts +7 -0
  27. package/dist/types/provider-models/openai-compat.d.ts +296 -0
  28. package/dist/types/provider-models/special.d.ts +16 -0
  29. package/dist/types/providers/aery-native-client.d.ts +13 -0
  30. package/dist/types/providers/aery-native-server.d.ts +68 -0
  31. package/dist/types/providers/amazon-bedrock.d.ts +38 -0
  32. package/dist/types/providers/anthropic-client.d.ts +99 -0
  33. package/dist/types/providers/anthropic-messages-server-schema.d.ts +465 -0
  34. package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
  35. package/dist/types/providers/anthropic-wire.d.ts +262 -0
  36. package/dist/types/providers/anthropic.d.ts +206 -0
  37. package/dist/types/providers/aws-credentials.d.ts +43 -0
  38. package/dist/types/providers/aws-eventstream.d.ts +38 -0
  39. package/dist/types/providers/aws-sigv4.d.ts +55 -0
  40. package/dist/types/providers/azure-openai-responses.d.ts +15 -0
  41. package/dist/types/providers/cursor/gen/agent_pb.d.ts +13022 -0
  42. package/dist/types/providers/cursor.d.ts +43 -0
  43. package/dist/types/providers/error-message.d.ts +27 -0
  44. package/dist/types/providers/github-copilot-headers.d.ts +40 -0
  45. package/dist/types/providers/gitlab-duo.d.ts +27 -0
  46. package/dist/types/providers/google-auth.d.ts +24 -0
  47. package/dist/types/providers/google-gemini-cli.d.ts +81 -0
  48. package/dist/types/providers/google-gemini-headers.d.ts +18 -0
  49. package/dist/types/providers/google-shared.d.ts +171 -0
  50. package/dist/types/providers/google-types.d.ts +138 -0
  51. package/dist/types/providers/google-vertex.d.ts +7 -0
  52. package/dist/types/providers/google.d.ts +4 -0
  53. package/dist/types/providers/grammar.d.ts +1 -0
  54. package/dist/types/providers/kimi.d.ts +27 -0
  55. package/dist/types/providers/mock.d.ts +173 -0
  56. package/dist/types/providers/ollama.d.ts +6 -0
  57. package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
  58. package/dist/types/providers/openai-chat-server-schema.d.ts +817 -0
  59. package/dist/types/providers/openai-chat-server.d.ts +16 -0
  60. package/dist/types/providers/openai-codex/constants.d.ts +26 -0
  61. package/dist/types/providers/openai-codex/request-transformer.d.ts +49 -0
  62. package/dist/types/providers/openai-codex/response-handler.d.ts +17 -0
  63. package/dist/types/providers/openai-codex-responses.d.ts +67 -0
  64. package/dist/types/providers/openai-completions-compat.d.ts +25 -0
  65. package/dist/types/providers/openai-completions.d.ts +54 -0
  66. package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
  67. package/dist/types/providers/openai-responses-server.d.ts +17 -0
  68. package/dist/types/providers/openai-responses-shared.d.ts +100 -0
  69. package/dist/types/providers/openai-responses.d.ts +66 -0
  70. package/dist/types/providers/register-builtins.d.ts +31 -0
  71. package/dist/types/providers/synthetic.d.ts +26 -0
  72. package/dist/{providers → types/providers}/transform-messages.d.ts +6 -2
  73. package/dist/types/providers/vision-guard.d.ts +8 -0
  74. package/dist/types/providers/xai-responses.d.ts +23 -0
  75. package/dist/types/rate-limit-utils.d.ts +19 -0
  76. package/dist/types/stream.d.ts +28 -0
  77. package/dist/types/types.d.ts +801 -0
  78. package/dist/types/usage/claude.d.ts +4 -0
  79. package/dist/types/usage/gemini.d.ts +2 -0
  80. package/dist/types/usage/github-copilot.d.ts +7 -0
  81. package/dist/types/usage/google-antigravity.d.ts +2 -0
  82. package/dist/types/usage/kimi.d.ts +2 -0
  83. package/dist/types/usage/minimax-code.d.ts +2 -0
  84. package/dist/types/usage/openai-codex.d.ts +3 -0
  85. package/dist/types/usage/shared.d.ts +1 -0
  86. package/dist/types/usage/zai.d.ts +2 -0
  87. package/dist/types/usage.d.ts +260 -0
  88. package/dist/types/utils/abort.d.ts +19 -0
  89. package/dist/types/utils/abortable-iterator.d.ts +4 -0
  90. package/dist/types/utils/anthropic-auth.d.ts +35 -0
  91. package/dist/types/utils/discovery/antigravity.d.ts +61 -0
  92. package/dist/types/utils/discovery/codex.d.ts +38 -0
  93. package/dist/types/utils/discovery/cursor.d.ts +23 -0
  94. package/dist/types/utils/discovery/gemini.d.ts +25 -0
  95. package/dist/types/utils/discovery/index.d.ts +4 -0
  96. package/dist/types/utils/discovery/openai-compatible.d.ts +72 -0
  97. package/dist/types/utils/event-stream.d.ts +28 -0
  98. package/dist/types/utils/fireworks-model-id.d.ts +10 -0
  99. package/dist/types/utils/foundry.d.ts +1 -0
  100. package/dist/types/utils/http-inspector.d.ts +31 -0
  101. package/dist/types/utils/idle-iterator.d.ts +78 -0
  102. package/dist/types/utils/json-parse.d.ts +37 -0
  103. package/dist/types/utils/oauth/__tests__/xai-oauth.test.d.ts +1 -0
  104. package/dist/types/utils/oauth/alibaba-coding-plan.d.ts +18 -0
  105. package/dist/types/utils/oauth/anthropic.d.ts +22 -0
  106. package/dist/types/utils/oauth/api-key-login.d.ts +35 -0
  107. package/dist/types/utils/oauth/api-key-validation.d.ts +27 -0
  108. package/dist/types/utils/oauth/callback-server.d.ts +57 -0
  109. package/dist/types/utils/oauth/cerebras.d.ts +1 -0
  110. package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
  111. package/dist/types/utils/oauth/cursor.d.ts +15 -0
  112. package/dist/types/utils/oauth/deepseek.d.ts +10 -0
  113. package/dist/types/utils/oauth/firepass.d.ts +1 -0
  114. package/dist/types/utils/oauth/fireworks.d.ts +1 -0
  115. package/dist/types/utils/oauth/github-copilot.d.ts +38 -0
  116. package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
  117. package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
  118. package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
  119. package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
  120. package/dist/types/utils/oauth/huggingface.d.ts +19 -0
  121. package/dist/types/utils/oauth/index.d.ts +38 -0
  122. package/dist/types/utils/oauth/kagi.d.ts +17 -0
  123. package/dist/types/utils/oauth/kilo.d.ts +5 -0
  124. package/dist/types/utils/oauth/kimi.d.ts +21 -0
  125. package/dist/types/utils/oauth/litellm.d.ts +18 -0
  126. package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
  127. package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
  128. package/dist/types/utils/oauth/moonshot.d.ts +1 -0
  129. package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
  130. package/dist/types/utils/oauth/nvidia.d.ts +18 -0
  131. package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
  132. package/dist/types/utils/oauth/ollama.d.ts +18 -0
  133. package/dist/types/utils/oauth/openai-codex.d.ts +21 -0
  134. package/dist/types/utils/oauth/opencode.d.ts +18 -0
  135. package/dist/types/utils/oauth/openrouter.d.ts +1 -0
  136. package/dist/types/utils/oauth/parallel.d.ts +17 -0
  137. package/dist/types/utils/oauth/perplexity.d.ts +9 -0
  138. package/dist/{utils → types/utils}/oauth/pkce.d.ts +0 -5
  139. package/dist/types/utils/oauth/qianfan.d.ts +17 -0
  140. package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
  141. package/dist/types/utils/oauth/synthetic.d.ts +1 -0
  142. package/dist/types/utils/oauth/tavily.d.ts +17 -0
  143. package/dist/types/utils/oauth/together.d.ts +1 -0
  144. package/dist/types/utils/oauth/types.d.ts +44 -0
  145. package/dist/types/utils/oauth/venice.d.ts +18 -0
  146. package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
  147. package/dist/types/utils/oauth/vllm.d.ts +16 -0
  148. package/dist/types/utils/oauth/wafer.d.ts +2 -0
  149. package/dist/types/utils/oauth/xai-oauth.d.ts +60 -0
  150. package/dist/types/utils/oauth/xiaomi.d.ts +19 -0
  151. package/dist/types/utils/oauth/zai.d.ts +18 -0
  152. package/dist/types/utils/oauth/zenmux.d.ts +1 -0
  153. package/dist/types/utils/oauth/zhipu.d.ts +18 -0
  154. package/dist/{utils → types/utils}/overflow.d.ts +9 -11
  155. package/dist/types/utils/parse-bind.d.ts +23 -0
  156. package/dist/types/utils/provider-response.d.ts +3 -0
  157. package/dist/types/utils/request-debug.d.ts +29 -0
  158. package/dist/types/utils/retry-after.d.ts +3 -0
  159. package/dist/types/utils/retry.d.ts +26 -0
  160. package/dist/types/utils/schema/adapt.d.ts +24 -0
  161. package/dist/types/utils/schema/compatibility.d.ts +30 -0
  162. package/dist/types/utils/schema/dereference.d.ts +11 -0
  163. package/dist/types/utils/schema/draft.d.ts +10 -0
  164. package/dist/types/utils/schema/equality.d.ts +4 -0
  165. package/dist/types/utils/schema/fields.d.ts +49 -0
  166. package/dist/types/utils/schema/index.d.ts +13 -0
  167. package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
  168. package/dist/types/utils/schema/meta-validator.d.ts +2 -0
  169. package/dist/types/utils/schema/normalize.d.ts +93 -0
  170. package/dist/types/utils/schema/spill.d.ts +8 -0
  171. package/dist/types/utils/schema/stamps.d.ts +25 -0
  172. package/dist/types/utils/schema/types.d.ts +4 -0
  173. package/dist/types/utils/schema/wire.d.ts +53 -0
  174. package/dist/types/utils/schema/zod-decontaminate.d.ts +31 -0
  175. package/dist/types/utils/sdk-stream-timeout.d.ts +33 -0
  176. package/dist/types/utils/sse-debug.d.ts +10 -0
  177. package/dist/types/utils/stream-markup-healing.d.ts +80 -0
  178. package/dist/types/utils/tool-choice.d.ts +50 -0
  179. package/dist/types/utils/validation.d.ts +17 -0
  180. package/dist/types/utils.d.ts +28 -0
  181. package/package.json +139 -105
  182. package/src/api-registry.ts +96 -0
  183. package/src/auth-broker/client.ts +358 -0
  184. package/src/auth-broker/index.ts +5 -0
  185. package/src/auth-broker/refresher.ts +117 -0
  186. package/src/auth-broker/remote-store.ts +623 -0
  187. package/src/auth-broker/server.ts +644 -0
  188. package/src/auth-broker/types.ts +127 -0
  189. package/src/auth-broker/wire-schemas.ts +200 -0
  190. package/src/auth-gateway/http.ts +194 -0
  191. package/src/auth-gateway/index.ts +3 -0
  192. package/src/auth-gateway/server.ts +818 -0
  193. package/src/auth-gateway/types.ts +143 -0
  194. package/src/auth-storage.ts +4422 -0
  195. package/src/index.ts +54 -0
  196. package/src/model-cache.ts +129 -0
  197. package/src/model-manager.ts +469 -0
  198. package/src/model-thinking.ts +782 -0
  199. package/src/models.json +83530 -0
  200. package/src/models.json.d.ts +9 -0
  201. package/src/models.ts +56 -0
  202. package/src/prompts/turn-aborted-guidance.md +4 -0
  203. package/src/provider-details.ts +90 -0
  204. package/src/provider-models/bundled-references.ts +38 -0
  205. package/src/provider-models/descriptors.ts +355 -0
  206. package/src/provider-models/google.ts +88 -0
  207. package/src/provider-models/index.ts +5 -0
  208. package/src/provider-models/ollama.ts +153 -0
  209. package/src/provider-models/openai-compat.ts +2817 -0
  210. package/src/provider-models/special.ts +67 -0
  211. package/src/providers/aery-native-client.ts +228 -0
  212. package/src/providers/aery-native-server.ts +212 -0
  213. package/src/providers/amazon-bedrock.ts +873 -0
  214. package/src/providers/anthropic-client.ts +318 -0
  215. package/src/providers/anthropic-messages-server-schema.ts +243 -0
  216. package/src/providers/anthropic-messages-server.ts +683 -0
  217. package/src/providers/anthropic-wire.ts +268 -0
  218. package/src/providers/anthropic.ts +3094 -0
  219. package/src/providers/aws-credentials.ts +501 -0
  220. package/src/providers/aws-eventstream.ts +185 -0
  221. package/src/providers/aws-sigv4.ts +218 -0
  222. package/src/providers/azure-openai-responses.ts +361 -0
  223. package/src/providers/cursor/gen/agent_pb.ts +15274 -0
  224. package/src/providers/cursor/proto/agent.proto +3526 -0
  225. package/src/providers/cursor/proto/buf.gen.yaml +6 -0
  226. package/src/providers/cursor/proto/buf.yaml +17 -0
  227. package/src/providers/cursor.ts +2621 -0
  228. package/src/providers/error-message.ts +21 -0
  229. package/src/providers/github-copilot-headers.ts +140 -0
  230. package/src/providers/gitlab-duo.ts +372 -0
  231. package/src/providers/google-auth.ts +252 -0
  232. package/src/providers/google-gemini-cli.ts +809 -0
  233. package/src/providers/google-gemini-headers.ts +41 -0
  234. package/src/providers/google-shared.ts +917 -0
  235. package/src/providers/google-types.ts +167 -0
  236. package/src/providers/google-vertex.ts +91 -0
  237. package/src/providers/google.ts +41 -0
  238. package/src/providers/grammar.ts +70 -0
  239. package/src/providers/kimi.ts +52 -0
  240. package/src/providers/mock.ts +496 -0
  241. package/src/providers/ollama.ts +644 -0
  242. package/src/providers/openai-anthropic-shim.ts +138 -0
  243. package/src/providers/openai-chat-server-schema.ts +252 -0
  244. package/src/providers/openai-chat-server.ts +647 -0
  245. package/src/providers/openai-codex/constants.ts +43 -0
  246. package/src/providers/openai-codex/request-transformer.ts +161 -0
  247. package/src/providers/openai-codex/response-handler.ts +81 -0
  248. package/src/providers/openai-codex-responses.ts +3018 -0
  249. package/src/providers/openai-completions-compat.ts +300 -0
  250. package/src/providers/openai-completions.ts +1979 -0
  251. package/src/providers/openai-responses-server-schema.ts +290 -0
  252. package/src/providers/openai-responses-server.ts +1183 -0
  253. package/src/providers/openai-responses-shared.ts +873 -0
  254. package/src/providers/openai-responses.ts +679 -0
  255. package/src/providers/register-builtins.ts +436 -0
  256. package/src/providers/synthetic.ts +50 -0
  257. package/src/providers/transform-messages.ts +382 -0
  258. package/src/providers/vision-guard.ts +31 -0
  259. package/src/providers/xai-responses.ts +82 -0
  260. package/src/rate-limit-utils.ts +84 -0
  261. package/src/stream.ts +1065 -0
  262. package/src/types.ts +944 -0
  263. package/src/usage/claude.ts +482 -0
  264. package/src/usage/gemini.ts +250 -0
  265. package/src/usage/github-copilot.ts +421 -0
  266. package/src/usage/google-antigravity.ts +201 -0
  267. package/src/usage/kimi.ts +271 -0
  268. package/src/usage/minimax-code.ts +31 -0
  269. package/src/usage/openai-codex.ts +503 -0
  270. package/src/usage/shared.ts +10 -0
  271. package/src/usage/zai.ts +247 -0
  272. package/src/usage.ts +185 -0
  273. package/src/utils/abort.ts +51 -0
  274. package/src/utils/abortable-iterator.ts +69 -0
  275. package/src/utils/anthropic-auth.ts +93 -0
  276. package/src/utils/discovery/antigravity.ts +261 -0
  277. package/src/utils/discovery/codex.ts +371 -0
  278. package/src/utils/discovery/cursor.ts +306 -0
  279. package/src/utils/discovery/gemini.ts +248 -0
  280. package/src/utils/discovery/index.ts +4 -0
  281. package/src/utils/discovery/openai-compatible.ts +224 -0
  282. package/src/utils/event-stream.ts +142 -0
  283. package/src/utils/fireworks-model-id.ts +30 -0
  284. package/src/utils/foundry.ts +8 -0
  285. package/src/utils/http-inspector.ts +176 -0
  286. package/src/utils/idle-iterator.ts +267 -0
  287. package/src/utils/json-parse.ts +182 -0
  288. package/src/utils/oauth/__tests__/xai-oauth.test.ts +107 -0
  289. package/src/utils/oauth/alibaba-coding-plan.ts +59 -0
  290. package/src/utils/oauth/anthropic.ts +273 -0
  291. package/src/utils/oauth/api-key-login.ts +87 -0
  292. package/src/utils/oauth/api-key-validation.ts +92 -0
  293. package/src/utils/oauth/callback-server.ts +276 -0
  294. package/src/utils/oauth/cerebras.ts +16 -0
  295. package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
  296. package/src/utils/oauth/cursor.ts +157 -0
  297. package/src/utils/oauth/deepseek.ts +53 -0
  298. package/src/utils/oauth/firepass.ts +24 -0
  299. package/src/utils/oauth/fireworks.ts +15 -0
  300. package/src/utils/oauth/github-copilot.ts +362 -0
  301. package/src/utils/oauth/gitlab-duo.ts +123 -0
  302. package/src/utils/oauth/google-antigravity.ts +200 -0
  303. package/src/utils/oauth/google-gemini-cli.ts +256 -0
  304. package/src/utils/oauth/google-oauth-shared.ts +110 -0
  305. package/src/utils/oauth/huggingface.ts +62 -0
  306. package/src/utils/oauth/index.ts +484 -0
  307. package/src/utils/oauth/kagi.ts +47 -0
  308. package/src/utils/oauth/kilo.ts +87 -0
  309. package/src/utils/oauth/kimi.ts +254 -0
  310. package/src/utils/oauth/litellm.ts +47 -0
  311. package/src/utils/oauth/lm-studio.ts +38 -0
  312. package/src/utils/oauth/minimax-code.ts +78 -0
  313. package/src/utils/oauth/moonshot.ts +23 -0
  314. package/src/utils/oauth/nanogpt.ts +15 -0
  315. package/src/utils/oauth/nvidia.ts +70 -0
  316. package/src/utils/oauth/oauth.html +203 -0
  317. package/src/utils/oauth/ollama-cloud.ts +28 -0
  318. package/src/utils/oauth/ollama.ts +47 -0
  319. package/src/utils/oauth/openai-codex.ts +299 -0
  320. package/src/utils/oauth/opencode.ts +49 -0
  321. package/src/utils/oauth/openrouter.ts +20 -0
  322. package/src/utils/oauth/parallel.ts +46 -0
  323. package/src/utils/oauth/perplexity.ts +206 -0
  324. package/src/utils/oauth/pkce.ts +18 -0
  325. package/src/utils/oauth/qianfan.ts +58 -0
  326. package/src/utils/oauth/qwen-portal.ts +60 -0
  327. package/src/utils/oauth/synthetic.ts +15 -0
  328. package/src/utils/oauth/tavily.ts +46 -0
  329. package/src/utils/oauth/together.ts +16 -0
  330. package/src/utils/oauth/types.ts +99 -0
  331. package/src/utils/oauth/venice.ts +59 -0
  332. package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
  333. package/src/utils/oauth/vllm.ts +40 -0
  334. package/src/utils/oauth/wafer.ts +50 -0
  335. package/src/utils/oauth/xai-oauth.ts +342 -0
  336. package/src/utils/oauth/xiaomi.ts +139 -0
  337. package/src/utils/oauth/zai.ts +60 -0
  338. package/src/utils/oauth/zenmux.ts +15 -0
  339. package/src/utils/oauth/zhipu.ts +60 -0
  340. package/src/utils/overflow.ts +137 -0
  341. package/src/utils/parse-bind.ts +54 -0
  342. package/src/utils/provider-response.ts +30 -0
  343. package/src/utils/request-debug.ts +336 -0
  344. package/src/utils/retry-after.ts +110 -0
  345. package/src/utils/retry.ts +54 -0
  346. package/src/utils/schema/CONSTRAINTS.md +164 -0
  347. package/src/utils/schema/adapt.ts +36 -0
  348. package/src/utils/schema/compatibility.ts +435 -0
  349. package/src/utils/schema/dereference.ts +98 -0
  350. package/src/utils/schema/draft.ts +341 -0
  351. package/src/utils/schema/equality.ts +97 -0
  352. package/src/utils/schema/fields.ts +191 -0
  353. package/src/utils/schema/index.ts +13 -0
  354. package/src/utils/schema/json-schema-validator.ts +577 -0
  355. package/src/utils/schema/meta-validator.ts +167 -0
  356. package/src/utils/schema/normalize.ts +1588 -0
  357. package/src/utils/schema/spill.ts +43 -0
  358. package/src/utils/schema/stamps.ts +97 -0
  359. package/src/utils/schema/types.ts +10 -0
  360. package/src/utils/schema/wire.ts +293 -0
  361. package/src/utils/schema/zod-decontaminate.ts +331 -0
  362. package/src/utils/sdk-stream-timeout.ts +43 -0
  363. package/src/utils/sse-debug.ts +289 -0
  364. package/src/utils/stream-markup-healing.ts +612 -0
  365. package/src/utils/tool-choice.ts +99 -0
  366. package/src/utils/validation.ts +1024 -0
  367. package/src/utils.ts +166 -0
  368. package/dist/api-registry.d.ts +0 -20
  369. package/dist/api-registry.d.ts.map +0 -1
  370. package/dist/api-registry.js +0 -44
  371. package/dist/api-registry.js.map +0 -1
  372. package/dist/bedrock-provider.d.ts +0 -5
  373. package/dist/bedrock-provider.d.ts.map +0 -1
  374. package/dist/bedrock-provider.js +0 -6
  375. package/dist/bedrock-provider.js.map +0 -1
  376. package/dist/cli.d.ts +0 -3
  377. package/dist/cli.d.ts.map +0 -1
  378. package/dist/cli.js +0 -130
  379. package/dist/cli.js.map +0 -1
  380. package/dist/env-api-keys.d.ts +0 -18
  381. package/dist/env-api-keys.d.ts.map +0 -1
  382. package/dist/env-api-keys.js +0 -178
  383. package/dist/env-api-keys.js.map +0 -1
  384. package/dist/image-models.d.ts +0 -10
  385. package/dist/image-models.d.ts.map +0 -1
  386. package/dist/image-models.generated.d.ts +0 -440
  387. package/dist/image-models.generated.d.ts.map +0 -1
  388. package/dist/image-models.generated.js +0 -442
  389. package/dist/image-models.generated.js.map +0 -1
  390. package/dist/image-models.js +0 -23
  391. package/dist/image-models.js.map +0 -1
  392. package/dist/images-api-registry.d.ts +0 -14
  393. package/dist/images-api-registry.d.ts.map +0 -1
  394. package/dist/images-api-registry.js +0 -22
  395. package/dist/images-api-registry.js.map +0 -1
  396. package/dist/images.d.ts +0 -4
  397. package/dist/images.d.ts.map +0 -1
  398. package/dist/images.js +0 -14
  399. package/dist/images.js.map +0 -1
  400. package/dist/index.d.ts +0 -32
  401. package/dist/index.d.ts.map +0 -1
  402. package/dist/index.js +0 -20
  403. package/dist/index.js.map +0 -1
  404. package/dist/models.d.ts +0 -18
  405. package/dist/models.d.ts.map +0 -1
  406. package/dist/models.generated.d.ts +0 -17480
  407. package/dist/models.generated.d.ts.map +0 -1
  408. package/dist/models.generated.js +0 -16339
  409. package/dist/models.generated.js.map +0 -1
  410. package/dist/models.js +0 -71
  411. package/dist/models.js.map +0 -1
  412. package/dist/oauth.d.ts +0 -2
  413. package/dist/oauth.d.ts.map +0 -1
  414. package/dist/oauth.js +0 -2
  415. package/dist/oauth.js.map +0 -1
  416. package/dist/providers/aery-error-formatting.d.ts +0 -13
  417. package/dist/providers/aery-error-formatting.d.ts.map +0 -1
  418. package/dist/providers/aery-error-formatting.js +0 -112
  419. package/dist/providers/aery-error-formatting.js.map +0 -1
  420. package/dist/providers/amazon-bedrock.d.ts +0 -38
  421. package/dist/providers/amazon-bedrock.d.ts.map +0 -1
  422. package/dist/providers/amazon-bedrock.js +0 -763
  423. package/dist/providers/amazon-bedrock.js.map +0 -1
  424. package/dist/providers/anthropic.d.ts +0 -71
  425. package/dist/providers/anthropic.d.ts.map +0 -1
  426. package/dist/providers/anthropic.js +0 -949
  427. package/dist/providers/anthropic.js.map +0 -1
  428. package/dist/providers/azure-openai-responses.d.ts +0 -15
  429. package/dist/providers/azure-openai-responses.d.ts.map +0 -1
  430. package/dist/providers/azure-openai-responses.js +0 -225
  431. package/dist/providers/azure-openai-responses.js.map +0 -1
  432. package/dist/providers/cloudflare.d.ts +0 -13
  433. package/dist/providers/cloudflare.d.ts.map +0 -1
  434. package/dist/providers/cloudflare.js +0 -26
  435. package/dist/providers/cloudflare.js.map +0 -1
  436. package/dist/providers/faux.d.ts +0 -56
  437. package/dist/providers/faux.d.ts.map +0 -1
  438. package/dist/providers/faux.js +0 -368
  439. package/dist/providers/faux.js.map +0 -1
  440. package/dist/providers/github-copilot-headers.d.ts +0 -8
  441. package/dist/providers/github-copilot-headers.d.ts.map +0 -1
  442. package/dist/providers/github-copilot-headers.js +0 -29
  443. package/dist/providers/github-copilot-headers.js.map +0 -1
  444. package/dist/providers/google-gemini-cli.d.ts +0 -74
  445. package/dist/providers/google-gemini-cli.d.ts.map +0 -1
  446. package/dist/providers/google-gemini-cli.js +0 -779
  447. package/dist/providers/google-gemini-cli.js.map +0 -1
  448. package/dist/providers/google-shared.d.ts +0 -70
  449. package/dist/providers/google-shared.d.ts.map +0 -1
  450. package/dist/providers/google-shared.js +0 -329
  451. package/dist/providers/google-shared.js.map +0 -1
  452. package/dist/providers/google-vertex.d.ts +0 -15
  453. package/dist/providers/google-vertex.d.ts.map +0 -1
  454. package/dist/providers/google-vertex.js +0 -442
  455. package/dist/providers/google-vertex.js.map +0 -1
  456. package/dist/providers/google.d.ts +0 -13
  457. package/dist/providers/google.d.ts.map +0 -1
  458. package/dist/providers/google.js +0 -400
  459. package/dist/providers/google.js.map +0 -1
  460. package/dist/providers/images/openrouter.d.ts +0 -3
  461. package/dist/providers/images/openrouter.d.ts.map +0 -1
  462. package/dist/providers/images/openrouter.js +0 -129
  463. package/dist/providers/images/openrouter.js.map +0 -1
  464. package/dist/providers/images/register-builtins.d.ts +0 -4
  465. package/dist/providers/images/register-builtins.d.ts.map +0 -1
  466. package/dist/providers/images/register-builtins.js +0 -34
  467. package/dist/providers/images/register-builtins.js.map +0 -1
  468. package/dist/providers/mistral.d.ts +0 -25
  469. package/dist/providers/mistral.d.ts.map +0 -1
  470. package/dist/providers/mistral.js +0 -535
  471. package/dist/providers/mistral.js.map +0 -1
  472. package/dist/providers/openai-codex-responses.d.ts +0 -30
  473. package/dist/providers/openai-codex-responses.d.ts.map +0 -1
  474. package/dist/providers/openai-codex-responses.js +0 -1090
  475. package/dist/providers/openai-codex-responses.js.map +0 -1
  476. package/dist/providers/openai-completions.d.ts +0 -19
  477. package/dist/providers/openai-completions.d.ts.map +0 -1
  478. package/dist/providers/openai-completions.js +0 -950
  479. package/dist/providers/openai-completions.js.map +0 -1
  480. package/dist/providers/openai-prompt-cache.d.ts +0 -3
  481. package/dist/providers/openai-prompt-cache.d.ts.map +0 -1
  482. package/dist/providers/openai-prompt-cache.js +0 -10
  483. package/dist/providers/openai-prompt-cache.js.map +0 -1
  484. package/dist/providers/openai-responses-shared.d.ts +0 -18
  485. package/dist/providers/openai-responses-shared.d.ts.map +0 -1
  486. package/dist/providers/openai-responses-shared.js +0 -492
  487. package/dist/providers/openai-responses-shared.js.map +0 -1
  488. package/dist/providers/openai-responses.d.ts +0 -13
  489. package/dist/providers/openai-responses.d.ts.map +0 -1
  490. package/dist/providers/openai-responses.js +0 -237
  491. package/dist/providers/openai-responses.js.map +0 -1
  492. package/dist/providers/register-builtins.d.ts +0 -38
  493. package/dist/providers/register-builtins.d.ts.map +0 -1
  494. package/dist/providers/register-builtins.js +0 -278
  495. package/dist/providers/register-builtins.js.map +0 -1
  496. package/dist/providers/simple-options.d.ts +0 -8
  497. package/dist/providers/simple-options.d.ts.map +0 -1
  498. package/dist/providers/simple-options.js +0 -41
  499. package/dist/providers/simple-options.js.map +0 -1
  500. package/dist/providers/transform-messages.d.ts.map +0 -1
  501. package/dist/providers/transform-messages.js +0 -184
  502. package/dist/providers/transform-messages.js.map +0 -1
  503. package/dist/session-resources.d.ts +0 -4
  504. package/dist/session-resources.d.ts.map +0 -1
  505. package/dist/session-resources.js +0 -22
  506. package/dist/session-resources.js.map +0 -1
  507. package/dist/stream.d.ts +0 -8
  508. package/dist/stream.d.ts.map +0 -1
  509. package/dist/stream.js +0 -27
  510. package/dist/stream.js.map +0 -1
  511. package/dist/types.d.ts +0 -498
  512. package/dist/types.d.ts.map +0 -1
  513. package/dist/types.js +0 -2
  514. package/dist/types.js.map +0 -1
  515. package/dist/utils/diagnostics.d.ts +0 -19
  516. package/dist/utils/diagnostics.d.ts.map +0 -1
  517. package/dist/utils/diagnostics.js +0 -25
  518. package/dist/utils/diagnostics.js.map +0 -1
  519. package/dist/utils/event-stream.d.ts +0 -21
  520. package/dist/utils/event-stream.d.ts.map +0 -1
  521. package/dist/utils/event-stream.js +0 -81
  522. package/dist/utils/event-stream.js.map +0 -1
  523. package/dist/utils/hash.d.ts +0 -3
  524. package/dist/utils/hash.d.ts.map +0 -1
  525. package/dist/utils/hash.js +0 -14
  526. package/dist/utils/hash.js.map +0 -1
  527. package/dist/utils/headers.d.ts +0 -2
  528. package/dist/utils/headers.d.ts.map +0 -1
  529. package/dist/utils/headers.js +0 -8
  530. package/dist/utils/headers.js.map +0 -1
  531. package/dist/utils/json-parse.d.ts +0 -16
  532. package/dist/utils/json-parse.d.ts.map +0 -1
  533. package/dist/utils/json-parse.js +0 -113
  534. package/dist/utils/json-parse.js.map +0 -1
  535. package/dist/utils/node-http-proxy.d.ts +0 -10
  536. package/dist/utils/node-http-proxy.d.ts.map +0 -1
  537. package/dist/utils/node-http-proxy.js +0 -97
  538. package/dist/utils/node-http-proxy.js.map +0 -1
  539. package/dist/utils/oauth/anthropic.d.ts +0 -25
  540. package/dist/utils/oauth/anthropic.d.ts.map +0 -1
  541. package/dist/utils/oauth/anthropic.js +0 -335
  542. package/dist/utils/oauth/anthropic.js.map +0 -1
  543. package/dist/utils/oauth/device-code.d.ts +0 -19
  544. package/dist/utils/oauth/device-code.d.ts.map +0 -1
  545. package/dist/utils/oauth/device-code.js +0 -55
  546. package/dist/utils/oauth/device-code.js.map +0 -1
  547. package/dist/utils/oauth/github-copilot.d.ts +0 -30
  548. package/dist/utils/oauth/github-copilot.d.ts.map +0 -1
  549. package/dist/utils/oauth/github-copilot.js +0 -268
  550. package/dist/utils/oauth/github-copilot.js.map +0 -1
  551. package/dist/utils/oauth/google-antigravity.d.ts +0 -26
  552. package/dist/utils/oauth/google-antigravity.d.ts.map +0 -1
  553. package/dist/utils/oauth/google-antigravity.js +0 -377
  554. package/dist/utils/oauth/google-antigravity.js.map +0 -1
  555. package/dist/utils/oauth/google-gemini-cli.d.ts +0 -26
  556. package/dist/utils/oauth/google-gemini-cli.d.ts.map +0 -1
  557. package/dist/utils/oauth/google-gemini-cli.js +0 -482
  558. package/dist/utils/oauth/google-gemini-cli.js.map +0 -1
  559. package/dist/utils/oauth/index.d.ts +0 -63
  560. package/dist/utils/oauth/index.d.ts.map +0 -1
  561. package/dist/utils/oauth/index.js +0 -131
  562. package/dist/utils/oauth/index.js.map +0 -1
  563. package/dist/utils/oauth/oauth-page.d.ts +0 -3
  564. package/dist/utils/oauth/oauth-page.d.ts.map +0 -1
  565. package/dist/utils/oauth/oauth-page.js +0 -105
  566. package/dist/utils/oauth/oauth-page.js.map +0 -1
  567. package/dist/utils/oauth/openai-codex.d.ts +0 -34
  568. package/dist/utils/oauth/openai-codex.d.ts.map +0 -1
  569. package/dist/utils/oauth/openai-codex.js +0 -385
  570. package/dist/utils/oauth/openai-codex.js.map +0 -1
  571. package/dist/utils/oauth/pkce.d.ts.map +0 -1
  572. package/dist/utils/oauth/pkce.js +0 -31
  573. package/dist/utils/oauth/pkce.js.map +0 -1
  574. package/dist/utils/oauth/types.d.ts +0 -64
  575. package/dist/utils/oauth/types.d.ts.map +0 -1
  576. package/dist/utils/oauth/types.js +0 -2
  577. package/dist/utils/oauth/types.js.map +0 -1
  578. package/dist/utils/overflow.d.ts.map +0 -1
  579. package/dist/utils/overflow.js +0 -151
  580. package/dist/utils/overflow.js.map +0 -1
  581. package/dist/utils/sanitize-unicode.d.ts +0 -22
  582. package/dist/utils/sanitize-unicode.d.ts.map +0 -1
  583. package/dist/utils/sanitize-unicode.js +0 -26
  584. package/dist/utils/sanitize-unicode.js.map +0 -1
  585. package/dist/utils/typebox-helpers.d.ts +0 -17
  586. package/dist/utils/typebox-helpers.d.ts.map +0 -1
  587. package/dist/utils/typebox-helpers.js +0 -21
  588. package/dist/utils/typebox-helpers.js.map +0 -1
  589. package/dist/utils/validation.d.ts +0 -18
  590. package/dist/utils/validation.d.ts.map +0 -1
  591. package/dist/utils/validation.js +0 -281
  592. package/dist/utils/validation.js.map +0 -1
@@ -0,0 +1,1183 @@
1
+ /**
2
+ * OpenAI Responses HTTP wire-format ↔ aery Context bridge for the auth-gateway.
3
+ *
4
+ * Inbound: parses `POST /v1/responses` request bodies into a {@link ParsedRequest}.
5
+ * Outbound: encodes aery's {@link AssistantMessage} (and event stream) back into
6
+ * the documented `response.*` SSE taxonomy or the non-streaming JSON shape.
7
+ *
8
+ * Spec: https://platform.openai.com/docs/api-reference/responses
9
+ * Inverse direction (source-of-truth for item shapes): ../../providers/openai-responses.ts
10
+ */
11
+
12
+ import { logger } from "@aryee337/aery-utils";
13
+ import { resolvePromptCacheKey } from "../auth-gateway/http";
14
+ import type { AuthGatewayParsedRequest as ParsedRequest } from "../auth-gateway/types";
15
+ import type {
16
+ AssistantMessage,
17
+ AssistantMessageEventStream,
18
+ Context,
19
+ Message,
20
+ TextContent,
21
+ ThinkingContent,
22
+ Tool,
23
+ ToolCall,
24
+ } from "../types";
25
+ import {
26
+ type OpenAIResponsesFunctionCallItem,
27
+ type OpenAIResponsesFunctionCallOutputItem,
28
+ type OpenAIResponsesInputContent,
29
+ type OpenAIResponsesOutputContent,
30
+ type OpenAIResponsesReasoningItem,
31
+ type OpenAIResponsesTool,
32
+ openaiResponsesRequestSchema,
33
+ } from "./openai-responses-server-schema";
34
+
35
+ export type { ParsedRequest };
36
+
37
+ // ─── narrow guards ──────────────────────────────────────────────────────────
38
+
39
+ function isReasoningEffort(value: unknown): value is NonNullable<ParsedRequest["options"]["reasoning"]> {
40
+ return value === "minimal" || value === "low" || value === "medium" || value === "high" || value === "xhigh";
41
+ }
42
+
43
+ function isServiceTier(value: unknown): value is NonNullable<ParsedRequest["options"]["serviceTier"]> {
44
+ return value === "auto" || value === "default" || value === "flex" || value === "scale" || value === "priority";
45
+ }
46
+
47
+ function isObj(v: unknown): v is Record<string, unknown> {
48
+ return typeof v === "object" && v !== null && !Array.isArray(v);
49
+ }
50
+
51
+ function asString(v: unknown): string | undefined {
52
+ return typeof v === "string" ? v : undefined;
53
+ }
54
+
55
+ // ─── id helpers ─────────────────────────────────────────────────────────────
56
+
57
+ function uuidNoDashes(): string {
58
+ return crypto.randomUUID().replace(/-/g, "");
59
+ }
60
+
61
+ function makeRespId(): string {
62
+ return `resp_${uuidNoDashes()}`;
63
+ }
64
+
65
+ function makeMsgId(): string {
66
+ return `msg_${uuidNoDashes()}`;
67
+ }
68
+
69
+ function makeReasoningId(): string {
70
+ return `rs_${uuidNoDashes()}`;
71
+ }
72
+
73
+ function makeFuncCallId(): string {
74
+ return `fc_${uuidNoDashes()}`;
75
+ }
76
+
77
+ function makeCustomCallId(): string {
78
+ return `ctc_${uuidNoDashes()}`;
79
+ }
80
+
81
+ // ─── once-only warnings ─────────────────────────────────────────────────────
82
+ // Module-scoped so we don't spam logs once per turn.
83
+
84
+ let warnedImageNotSupported = false;
85
+ let warnedFileNotSupported = false;
86
+ let warnedReasoningSummaryLevel = false;
87
+
88
+ // ─── inbound parser helpers ─────────────────────────────────────────────────
89
+
90
+ function extractReasoningTextFromItem(item: OpenAIResponsesReasoningItem): string {
91
+ // Prefer `summary[]` — mirrors real OpenAI and the openai-responses provider
92
+ // which writes the surfaced reasoning summary into `summary[].text`.
93
+ const fromSummary = (item.summary ?? []).map(c => c.text).join("");
94
+ if (fromSummary) return fromSummary;
95
+ return (item.content ?? []).map(c => c.text).join("");
96
+ }
97
+
98
+ type InputBlockUnion =
99
+ | { type: "input_text"; text: string }
100
+ | { type: "text"; text: string }
101
+ | { type: "input_image"; detail?: "auto" | "low" | "high"; image_url?: string; file_id?: string }
102
+ | { type: "input_file"; file_id?: string; filename?: string; file_data?: string };
103
+
104
+ /**
105
+ * Walk an input message's content array and produce aery-ai's `TextContent[]`.
106
+ * `input_image`/`input_file` blocks become bracketed text placeholders since
107
+ * aery-ai's `ImageContent` only carries inline base64 data and we have no
108
+ * resolver for OpenAI `image_url` / `file_id` references. Logs once per kind.
109
+ */
110
+ function inputContentParts(blocks: OpenAIResponsesInputContent[] | string | undefined): string | TextContent[] {
111
+ if (typeof blocks === "string") return blocks;
112
+ if (!blocks) return [];
113
+ const parts: TextContent[] = [];
114
+ for (const raw of blocks) {
115
+ const block = raw as InputBlockUnion;
116
+ if (block.type === "input_text" || block.type === "text") {
117
+ parts.push({ type: "text", text: block.text });
118
+ } else if (block.type === "input_image") {
119
+ if (!warnedImageNotSupported) {
120
+ warnedImageNotSupported = true;
121
+ logger.warn("openai-responses-server: input_image dropped (no aery-ai bridge for image_url/file_id)", {
122
+ hasUrl: typeof block.image_url === "string",
123
+ hasFileId: typeof block.file_id === "string",
124
+ });
125
+ }
126
+ const ref = block.image_url ?? block.file_id ?? "?";
127
+ parts.push({ type: "text", text: `[image: ${ref}]` });
128
+ } else if (block.type === "input_file") {
129
+ if (!warnedFileNotSupported) {
130
+ warnedFileNotSupported = true;
131
+ logger.warn("openai-responses-server: input_file dropped (no aery-ai bridge for file_id/file_data)", {
132
+ hasFileId: typeof block.file_id === "string",
133
+ hasFileData: typeof block.file_data === "string",
134
+ });
135
+ }
136
+ const ref = block.file_id ?? block.filename ?? "?";
137
+ parts.push({ type: "text", text: `[file: ${ref}]` });
138
+ }
139
+ }
140
+ return parts.length === 1 ? parts[0].text : parts;
141
+ }
142
+
143
+ type OutputBlockUnion =
144
+ | { type: "output_text"; text: string }
145
+ | { type: "text"; text: string }
146
+ | { type: "refusal"; refusal: string };
147
+
148
+ function outputTextOf(blocks: OpenAIResponsesOutputContent[] | string | undefined): TextContent[] {
149
+ if (typeof blocks === "string") return blocks.length > 0 ? [{ type: "text", text: blocks }] : [];
150
+ if (!blocks) return [];
151
+ const out: TextContent[] = [];
152
+ for (const raw of blocks) {
153
+ const block = raw as OutputBlockUnion;
154
+ if (block.type === "output_text" || block.type === "text") {
155
+ out.push({ type: "text", text: block.text });
156
+ } else if (block.type === "refusal") {
157
+ // Preserve the refusal reason so history replay still carries it.
158
+ out.push({ type: "text", text: `[refusal: ${block.refusal}]` });
159
+ }
160
+ }
161
+ return out;
162
+ }
163
+
164
+ // The schema accepts a much wider tool_choice union than the SDK type so the
165
+ // walker narrows against the local schema shape.
166
+ type ParsedToolChoice =
167
+ | "auto"
168
+ | "none"
169
+ | "required"
170
+ | { type: "function"; name: string }
171
+ | { type: "custom"; name: string }
172
+ | {
173
+ type:
174
+ | "web_search_preview"
175
+ | "file_search"
176
+ | "computer_use_preview"
177
+ | "code_interpreter"
178
+ | "image_generation"
179
+ | "mcp";
180
+ }
181
+ | { type: "allowed_tools"; mode: "auto" | "required"; tools: Array<{ type: string; name?: string }> };
182
+
183
+ function mapToolChoice(value: ParsedToolChoice | undefined): ParsedRequest["options"]["toolChoice"] {
184
+ if (value === undefined) return undefined;
185
+ if (value === "auto" || value === "none" || value === "required") return value;
186
+ if ("type" in value) {
187
+ // `custom` (codex apply_patch) and `function` both resolve to the same
188
+ // aery-ai shape: aery-ai's dispatcher matches `Tool.name` AND `customWireName`,
189
+ // so passing the wire name works for either.
190
+ if (value.type === "function" || value.type === "custom") return { name: value.name };
191
+ // Hosted tools + allowed_tools — we don't surface these to aery-ai; fall
192
+ // back to letting the model pick a tool freely.
193
+ return "auto";
194
+ }
195
+ return undefined;
196
+ }
197
+
198
+ function buildTools(tools: Array<OpenAIResponsesTool | { type: string }> | undefined): Tool[] | undefined {
199
+ if (!tools) return undefined;
200
+ const out: Tool[] = [];
201
+ for (const t of tools) {
202
+ // Skip non-function tools (web_search, file_search, …).
203
+ if (t.type !== "function") continue;
204
+ const fn = t as Extract<OpenAIResponsesTool, { type: "function" }>;
205
+ const tool: Tool = {
206
+ name: fn.name,
207
+ description: fn.description ?? "",
208
+ parameters: (fn.parameters ?? {}) as Tool["parameters"],
209
+ };
210
+ if (fn.strict !== undefined && fn.strict !== null) tool.strict = fn.strict;
211
+ out.push(tool);
212
+ }
213
+ return out.length > 0 ? out : undefined;
214
+ }
215
+
216
+ function ensureAssistantPlaceholder(messages: Message[], modelId: string, now: number): AssistantMessage {
217
+ const last = messages[messages.length - 1];
218
+ if (last && last.role === "assistant") return last;
219
+ const placeholder: AssistantMessage = {
220
+ role: "assistant",
221
+ content: [],
222
+ api: "openai-responses",
223
+ provider: "openai",
224
+ model: modelId,
225
+ usage: {
226
+ input: 0,
227
+ output: 0,
228
+ cacheRead: 0,
229
+ cacheWrite: 0,
230
+ totalTokens: 0,
231
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
232
+ },
233
+ stopReason: "stop",
234
+ timestamp: now,
235
+ };
236
+ messages.push(placeholder);
237
+ return placeholder;
238
+ }
239
+
240
+ /** Flatten a function_call_output array form (text + refusal) into a single string. */
241
+ function flattenFunctionOutputArray(blocks: readonly unknown[]): string {
242
+ const parts: string[] = [];
243
+ for (const raw of blocks) {
244
+ if (!isObj(raw)) continue;
245
+ const t = raw.type;
246
+ if (t === "output_text" || t === "text") {
247
+ const text = asString(raw.text);
248
+ if (text) parts.push(text);
249
+ } else if (t === "refusal") {
250
+ const refusal = asString(raw.refusal);
251
+ if (refusal) parts.push(`[refusal: ${refusal}]`);
252
+ }
253
+ }
254
+ return parts.join("");
255
+ }
256
+
257
+ // ─── parseRequest ───────────────────────────────────────────────────────────
258
+
259
+ export function parseRequest(body: unknown, headers?: Headers): ParsedRequest {
260
+ // Header capture is centralized in `auth-gateway/server.ts` (the
261
+ // allow-listed set lands on `options.headers` automatically). We also
262
+ // consult `headers` here to populate `options.promptCacheKey` when the
263
+ // client signals a cache identity outside the body — see the
264
+ // `resolvePromptCacheKey` call further down.
265
+
266
+ const parsed = openaiResponsesRequestSchema.safeParse(body);
267
+ if (!parsed.success) {
268
+ throw new Error(`openai-responses: ${parsed.error.message}`);
269
+ }
270
+ const data = parsed.data;
271
+
272
+ const now = Date.now();
273
+ const messages: Message[] = [];
274
+ const systemPrompt: string[] = [];
275
+
276
+ if (typeof data.instructions === "string" && data.instructions.length > 0) {
277
+ systemPrompt.push(data.instructions);
278
+ }
279
+
280
+ if (typeof data.input === "string") {
281
+ messages.push({ role: "user", content: data.input, timestamp: now });
282
+ } else if (data.input) {
283
+ for (const item of data.input) {
284
+ // Items may omit `type` and rely on `role` (the convenience shape).
285
+ const effectiveType = item.type ?? ("role" in item ? "message" : undefined);
286
+ if (effectiveType === "message") {
287
+ const msg = item as {
288
+ role?: string;
289
+ content?: OpenAIResponsesInputContent[] | OpenAIResponsesOutputContent[] | string;
290
+ };
291
+ switch (msg.role) {
292
+ case "system": {
293
+ const text = inputContentParts(msg.content as OpenAIResponsesInputContent[] | string | undefined);
294
+ const flat = typeof text === "string" ? text : text.map(p => p.text).join("");
295
+ if (flat.length > 0) systemPrompt.push(flat);
296
+ break;
297
+ }
298
+ case "user":
299
+ case "developer": {
300
+ const content = inputContentParts(msg.content as OpenAIResponsesInputContent[] | string | undefined);
301
+ messages.push({ role: msg.role, content, timestamp: now });
302
+ break;
303
+ }
304
+ case "assistant": {
305
+ const parts = outputTextOf(msg.content as OpenAIResponsesOutputContent[] | string | undefined);
306
+ messages.push({
307
+ role: "assistant",
308
+ content: parts,
309
+ api: "openai-responses",
310
+ provider: "openai",
311
+ model: data.model,
312
+ usage: {
313
+ input: 0,
314
+ output: 0,
315
+ cacheRead: 0,
316
+ cacheWrite: 0,
317
+ totalTokens: 0,
318
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
319
+ },
320
+ stopReason: "stop",
321
+ timestamp: now,
322
+ });
323
+ break;
324
+ }
325
+ }
326
+ continue;
327
+ }
328
+ if (effectiveType === "reasoning") {
329
+ const reasoning = item as OpenAIResponsesReasoningItem;
330
+ const text = extractReasoningTextFromItem(reasoning);
331
+ const thinking: ThinkingContent = {
332
+ type: "thinking",
333
+ thinking: text,
334
+ thinkingSignature: JSON.stringify(reasoning),
335
+ ...(reasoning.id ? { itemId: reasoning.id } : {}),
336
+ };
337
+ ensureAssistantPlaceholder(messages, data.model, now).content.push(thinking);
338
+ continue;
339
+ }
340
+ if (effectiveType === "function_call") {
341
+ const call = item as OpenAIResponsesFunctionCallItem;
342
+ const argsRaw = call.arguments ?? "{}";
343
+ let args: Record<string, unknown>;
344
+ try {
345
+ const parsedArgs: unknown = JSON.parse(argsRaw);
346
+ args = isObj(parsedArgs) ? parsedArgs : {};
347
+ } catch {
348
+ throw new Error(`openai-responses: function_call ${call.call_id} has invalid JSON arguments`);
349
+ }
350
+ const toolCall: ToolCall = {
351
+ type: "toolCall",
352
+ id: call.call_id,
353
+ name: call.name,
354
+ arguments: args,
355
+ ...(call.id ? { thoughtSignature: call.id } : {}),
356
+ };
357
+ ensureAssistantPlaceholder(messages, data.model, now).content.push(toolCall);
358
+ continue;
359
+ }
360
+ if (effectiveType === "custom_tool_call") {
361
+ const call = item as { id?: string; call_id: string; name: string; input: string };
362
+ // Custom tools carry a raw input string. We stash it in `arguments.input`
363
+ // matching aery-ai's openai-responses-shared convention, and tag the call
364
+ // with `customWireName` so encoders re-emit it as `custom_tool_call`.
365
+ const toolCall: ToolCall = {
366
+ type: "toolCall",
367
+ id: call.call_id,
368
+ name: call.name,
369
+ arguments: { input: call.input ?? "" },
370
+ customWireName: call.name,
371
+ ...(call.id ? { thoughtSignature: call.id } : {}),
372
+ };
373
+ ensureAssistantPlaceholder(messages, data.model, now).content.push(toolCall);
374
+ continue;
375
+ }
376
+ if (effectiveType === "function_call_output") {
377
+ const output = item as OpenAIResponsesFunctionCallOutputItem;
378
+ const toolName = findToolNameById(messages, output.call_id);
379
+ const text =
380
+ typeof output.output === "string"
381
+ ? output.output
382
+ : Array.isArray(output.output)
383
+ ? flattenFunctionOutputArray(output.output)
384
+ : "";
385
+ messages.push({
386
+ role: "toolResult",
387
+ toolCallId: output.call_id,
388
+ toolName,
389
+ content: [{ type: "text", text }],
390
+ isError: false,
391
+ timestamp: now,
392
+ });
393
+ continue;
394
+ }
395
+ if (effectiveType === "custom_tool_call_output") {
396
+ const output = item as { call_id: string; output: string };
397
+ const toolName = findToolNameById(messages, output.call_id);
398
+ messages.push({
399
+ role: "toolResult",
400
+ toolCallId: output.call_id,
401
+ toolName,
402
+ content: [{ type: "text", text: output.output ?? "" }],
403
+ isError: false,
404
+ timestamp: now,
405
+ });
406
+ }
407
+ // Other item types are tolerated but not bridged.
408
+ }
409
+ }
410
+
411
+ const tools = buildTools(data.tools);
412
+ const context: Context = {
413
+ ...(systemPrompt.length > 0 ? { systemPrompt } : {}),
414
+ messages,
415
+ ...(tools ? { tools } : {}),
416
+ };
417
+
418
+ const options: ParsedRequest["options"] = {};
419
+ if (data.max_output_tokens !== undefined) options.maxOutputTokens = data.max_output_tokens;
420
+ if (data.temperature !== undefined) options.temperature = data.temperature;
421
+ if (data.top_p !== undefined) options.topP = data.top_p;
422
+ if (data.stop !== undefined && data.stop !== null) {
423
+ options.stopSequences = typeof data.stop === "string" ? [data.stop] : data.stop;
424
+ }
425
+ const toolChoice = mapToolChoice(data.tool_choice as ParsedToolChoice | undefined);
426
+ if (toolChoice !== undefined) options.toolChoice = toolChoice;
427
+ if (data.reasoning?.effort && isReasoningEffort(data.reasoning.effort)) {
428
+ options.reasoning = data.reasoning.effort;
429
+ }
430
+ // OpenAI summary: `none` → suppress; `auto`/`concise`/`detailed` → request
431
+ // visible summary. aery-ai has no per-level plumbing — log once and let the
432
+ // provider default kick in.
433
+ if (data.reasoning?.summary === "none") {
434
+ options.hideThinkingSummary = true;
435
+ } else if (
436
+ data.reasoning?.summary === "auto" ||
437
+ data.reasoning?.summary === "concise" ||
438
+ data.reasoning?.summary === "detailed"
439
+ ) {
440
+ if (!warnedReasoningSummaryLevel) {
441
+ warnedReasoningSummaryLevel = true;
442
+ logger.debug("openai-responses-server: reasoning.summary level not differentiated", {
443
+ level: data.reasoning.summary,
444
+ });
445
+ }
446
+ }
447
+ if (data.service_tier !== undefined && isServiceTier(data.service_tier)) {
448
+ options.serviceTier = data.service_tier;
449
+ }
450
+ if (data.presence_penalty !== undefined) options.presencePenalty = data.presence_penalty;
451
+ if (data.frequency_penalty !== undefined) options.frequencyPenalty = data.frequency_penalty;
452
+ if (data.parallel_tool_calls !== undefined) options.parallelToolCalls = data.parallel_tool_calls;
453
+ const cacheKey = resolvePromptCacheKey(body, headers);
454
+ if (cacheKey !== undefined) options.promptCacheKey = cacheKey;
455
+ if (data.previous_response_id !== undefined) options.previousResponseId = data.previous_response_id;
456
+ if (data.user !== undefined) options.user = data.user;
457
+ if (isObj(data.metadata)) options.metadata = data.metadata;
458
+ // `store` is a stateful-storage hint that aery's gateway doesn't honour;
459
+ // silently accepted by the schema. No typed slot — drop.
460
+
461
+ return {
462
+ modelId: data.model,
463
+ context,
464
+ stream: data.stream === true,
465
+ options,
466
+ };
467
+ }
468
+
469
+ function findToolNameById(messages: Message[], callId: string): string {
470
+ for (let i = messages.length - 1; i >= 0; i--) {
471
+ const m = messages[i];
472
+ if (m.role !== "assistant") continue;
473
+ for (const c of m.content) {
474
+ if (c.type === "toolCall" && c.id === callId) return c.name;
475
+ }
476
+ }
477
+ return "";
478
+ }
479
+
480
+ // ─── formatError ────────────────────────────────────────────────────────────
481
+
482
+ export function formatError(status: number, type: string, message: string): Response {
483
+ return new Response(JSON.stringify({ error: { message, type } }), {
484
+ status,
485
+ headers: { "Content-Type": "application/json" },
486
+ });
487
+ }
488
+
489
+ // ─── output item builders (shared by streaming + non-streaming encoders) ────
490
+
491
+ type ReasoningOutputItem = {
492
+ type: "reasoning";
493
+ id: string;
494
+ summary: Array<{ type: "summary_text"; text: string }>;
495
+ } & Record<string, unknown>;
496
+
497
+ type MessageOutputItem = {
498
+ type: "message";
499
+ id: string;
500
+ role: "assistant";
501
+ status: "completed";
502
+ content: Array<{ type: "output_text"; text: string; annotations: never[] }>;
503
+ };
504
+
505
+ type FunctionCallOutputItem = {
506
+ type: "function_call";
507
+ id: string;
508
+ call_id: string;
509
+ name: string;
510
+ arguments: string;
511
+ status: "completed";
512
+ };
513
+
514
+ type CustomToolCallOutputItem = {
515
+ type: "custom_tool_call";
516
+ id: string;
517
+ call_id: string;
518
+ name: string;
519
+ input: string;
520
+ status: "completed";
521
+ };
522
+
523
+ type OutputItem = ReasoningOutputItem | MessageOutputItem | FunctionCallOutputItem | CustomToolCallOutputItem;
524
+
525
+ type ResponseStatus = "completed" | "in_progress" | "failed" | "incomplete";
526
+
527
+ function responseStatusForStopReason(message: AssistantMessage): ResponseStatus {
528
+ if (message.stopReason === "length") return "incomplete";
529
+ if (message.stopReason === "error" || message.stopReason === "aborted") return "failed";
530
+ return "completed";
531
+ }
532
+
533
+ function buildReasoningItem(part: ThinkingContent): ReasoningOutputItem {
534
+ const baseId = part.itemId ?? makeReasoningId();
535
+ if (part.thinkingSignature) {
536
+ try {
537
+ const sigParsed: unknown = JSON.parse(part.thinkingSignature);
538
+ if (isObj(sigParsed) && sigParsed.type === "reasoning") {
539
+ const id = part.itemId ?? asString(sigParsed.id) ?? makeReasoningId();
540
+ // Preserve any extra fields (encrypted_content, …) the original carried,
541
+ // but normalize the summary into the canonical `{type, text}[]` shape.
542
+ const merged: Record<string, unknown> = { ...sigParsed, type: "reasoning", id };
543
+ merged.summary = [{ type: "summary_text", text: part.thinking }];
544
+ // `content[]` is the encrypted/raw side-channel; leave whatever was
545
+ // already there. If absent, omit — real OpenAI only emits `content[]`
546
+ // when `include=['reasoning.encrypted_content']` is set.
547
+ return merged as ReasoningOutputItem;
548
+ }
549
+ } catch {
550
+ // Not a serialized Responses reasoning item; fall through to fresh build.
551
+ }
552
+ }
553
+ return {
554
+ type: "reasoning",
555
+ id: baseId,
556
+ summary: [{ type: "summary_text", text: part.thinking }],
557
+ };
558
+ }
559
+
560
+ function reasoningItemId(part: ThinkingContent): string {
561
+ if (part.itemId) return part.itemId;
562
+ if (part.thinkingSignature) {
563
+ try {
564
+ const sigParsed: unknown = JSON.parse(part.thinkingSignature);
565
+ if (isObj(sigParsed)) {
566
+ const id = asString(sigParsed.id);
567
+ if (id) return id;
568
+ }
569
+ } catch {
570
+ // Not a serialized Responses reasoning item.
571
+ }
572
+ }
573
+ return makeReasoningId();
574
+ }
575
+
576
+ /**
577
+ * Walk the assistant content array and group consecutive TextContent into a
578
+ * single message item; each ThinkingContent / ToolCall is its own item.
579
+ */
580
+ function buildOutputItems(message: AssistantMessage): OutputItem[] {
581
+ const out: OutputItem[] = [];
582
+ let pendingMessage: MessageOutputItem | null = null;
583
+ const flushMessage = () => {
584
+ if (pendingMessage) {
585
+ out.push(pendingMessage);
586
+ pendingMessage = null;
587
+ }
588
+ };
589
+
590
+ for (const part of message.content) {
591
+ if (part.type === "text") {
592
+ if (!pendingMessage) {
593
+ pendingMessage = {
594
+ type: "message",
595
+ id: makeMsgId(),
596
+ role: "assistant",
597
+ status: "completed",
598
+ content: [],
599
+ };
600
+ }
601
+ pendingMessage.content.push({ type: "output_text", text: part.text, annotations: [] });
602
+ } else if (part.type === "thinking") {
603
+ flushMessage();
604
+ out.push(buildReasoningItem(part));
605
+ } else if (part.type === "toolCall") {
606
+ flushMessage();
607
+ if (part.customWireName) {
608
+ const rawInput = typeof part.arguments?.input === "string" ? (part.arguments.input as string) : "";
609
+ out.push({
610
+ type: "custom_tool_call",
611
+ id: part.thoughtSignature ?? makeCustomCallId(),
612
+ call_id: part.id,
613
+ name: part.customWireName,
614
+ input: rawInput,
615
+ status: "completed",
616
+ });
617
+ } else {
618
+ out.push({
619
+ type: "function_call",
620
+ id: part.thoughtSignature ?? makeFuncCallId(),
621
+ call_id: part.id,
622
+ name: part.name,
623
+ arguments: JSON.stringify(part.arguments ?? {}),
624
+ status: "completed",
625
+ });
626
+ }
627
+ }
628
+ // RedactedThinking / Image are silently dropped — no direct Responses wire representation.
629
+ }
630
+ flushMessage();
631
+ return out;
632
+ }
633
+
634
+ function buildUsage(message: AssistantMessage): Record<string, unknown> {
635
+ const u = message.usage;
636
+ const inputTokens = u.input + u.cacheRead + u.cacheWrite;
637
+ return {
638
+ input_tokens: inputTokens,
639
+ input_tokens_details: { cached_tokens: u.cacheRead },
640
+ output_tokens: u.output,
641
+ output_tokens_details: { reasoning_tokens: u.reasoningTokens ?? 0 },
642
+ total_tokens: inputTokens + u.output,
643
+ };
644
+ }
645
+
646
+ function buildResponseEnvelope(
647
+ message: AssistantMessage,
648
+ requestedModelId: string,
649
+ id: string,
650
+ status: ResponseStatus,
651
+ items: OutputItem[] | [],
652
+ usage: Record<string, unknown> | null,
653
+ ): Record<string, unknown> {
654
+ return {
655
+ id,
656
+ object: "response",
657
+ created_at: Math.floor(message.timestamp / 1000),
658
+ status,
659
+ model: requestedModelId,
660
+ output: items,
661
+ usage,
662
+ ...(status === "incomplete" ? { incomplete_details: { reason: "max_output_tokens" } } : {}),
663
+ ...(status === "failed" ? { error: { message: message.errorMessage ?? "response failed" } } : {}),
664
+ };
665
+ }
666
+
667
+ // ─── encodeResponse (non-streaming) ─────────────────────────────────────────
668
+
669
+ export function encodeResponse(message: AssistantMessage, requestedModelId: string): Record<string, unknown> {
670
+ const items = buildOutputItems(message);
671
+ return buildResponseEnvelope(
672
+ message,
673
+ requestedModelId,
674
+ makeRespId(),
675
+ responseStatusForStopReason(message),
676
+ items,
677
+ buildUsage(message),
678
+ );
679
+ }
680
+
681
+ // ─── encodeStream ───────────────────────────────────────────────────────────
682
+
683
+ interface OpenMessage {
684
+ kind: "message";
685
+ itemId: string;
686
+ outputIndex: number;
687
+ contentIndex: number;
688
+ currentPartText: string;
689
+ content: Array<{ type: "output_text"; text: string; annotations: never[] }>;
690
+ }
691
+ interface OpenReasoning {
692
+ kind: "reasoning";
693
+ itemId: string;
694
+ outputIndex: number;
695
+ reasoningText: string;
696
+ }
697
+ interface OpenFunctionCall {
698
+ kind: "function_call";
699
+ itemId: string;
700
+ outputIndex: number;
701
+ callId: string;
702
+ name: string;
703
+ argsText: string;
704
+ /** Set when the underlying ToolCall is a custom-tool emission. */
705
+ customWireName?: string;
706
+ }
707
+ type OpenItem = OpenMessage | OpenReasoning | OpenFunctionCall;
708
+
709
+ function sseEvent(name: string, data: unknown): string {
710
+ return `event: ${name}\ndata: ${JSON.stringify(data)}\n\n`;
711
+ }
712
+
713
+ export function encodeStream(
714
+ events: AssistantMessageEventStream,
715
+ requestedModelId: string,
716
+ ): ReadableStream<Uint8Array> {
717
+ const encoder = new TextEncoder();
718
+ const responseId = makeRespId();
719
+ let sequenceNumber = 0;
720
+ const seq = () => sequenceNumber++;
721
+
722
+ return new ReadableStream<Uint8Array>({
723
+ async start(controller) {
724
+ const emit = (name: string, data: Record<string, unknown>) => {
725
+ controller.enqueue(encoder.encode(sseEvent(name, { type: name, sequence_number: seq(), ...data })));
726
+ };
727
+ const emitDone = () => controller.enqueue(encoder.encode("data: [DONE]\n\n"));
728
+
729
+ let createdAt = Math.floor(Date.now() / 1000);
730
+ let outputIndex = 0;
731
+ const state: { open: OpenItem | null } = { open: null };
732
+ const finishedItems: OutputItem[] = [];
733
+
734
+ const responseSnapshot = (status: ResponseStatus, output: OutputItem[] | []) => ({
735
+ id: responseId,
736
+ object: "response",
737
+ created_at: createdAt,
738
+ status,
739
+ model: requestedModelId,
740
+ output,
741
+ usage: null,
742
+ });
743
+
744
+ const openMessage = (): OpenMessage => {
745
+ const itemId = makeMsgId();
746
+ const item = {
747
+ type: "message" as const,
748
+ id: itemId,
749
+ status: "in_progress",
750
+ role: "assistant" as const,
751
+ content: [] as Array<{ type: "output_text"; text: string; annotations: never[] }>,
752
+ };
753
+ emit("response.output_item.added", { output_index: outputIndex, item });
754
+ const next: OpenMessage = {
755
+ kind: "message",
756
+ itemId,
757
+ outputIndex,
758
+ contentIndex: 0,
759
+ currentPartText: "",
760
+ content: [],
761
+ };
762
+ state.open = next;
763
+ return next;
764
+ };
765
+
766
+ const openReasoning = (partial: AssistantMessage, contentIndex: number): OpenReasoning => {
767
+ const part = partial.content[contentIndex];
768
+ const itemId = part && part.type === "thinking" ? reasoningItemId(part) : makeReasoningId();
769
+ const item = {
770
+ type: "reasoning" as const,
771
+ id: itemId,
772
+ summary: [] as Array<{ type: "summary_text"; text: string }>,
773
+ };
774
+ emit("response.output_item.added", { output_index: outputIndex, item });
775
+ // Open the summary part. Real OpenAI streams summary text in the
776
+ // canonical `reasoning_summary_*` lifecycle; aery-ai's own decoder
777
+ // reads `summary[].text` from the eventual `output_item.done`.
778
+ emit("response.reasoning_summary_part.added", {
779
+ item_id: itemId,
780
+ output_index: outputIndex,
781
+ summary_index: 0,
782
+ part: { type: "summary_text", text: "" },
783
+ });
784
+ const next: OpenReasoning = { kind: "reasoning", itemId, outputIndex, reasoningText: "" };
785
+ state.open = next;
786
+ return next;
787
+ };
788
+
789
+ const openToolCall = (partial: AssistantMessage, contentIndex: number): OpenFunctionCall => {
790
+ const part = partial.content[contentIndex];
791
+ const tc = part && part.type === "toolCall" ? part : undefined;
792
+ const customWireName: string | undefined =
793
+ tc && typeof tc.customWireName === "string" && tc.customWireName.length > 0
794
+ ? tc.customWireName
795
+ : undefined;
796
+ const isCustom = customWireName !== undefined;
797
+ const itemId = tc?.thoughtSignature ?? (isCustom ? makeCustomCallId() : makeFuncCallId());
798
+ const callId = tc?.id ?? "";
799
+ const name = customWireName ?? tc?.name ?? "";
800
+ const item = isCustom
801
+ ? {
802
+ type: "custom_tool_call" as const,
803
+ id: itemId,
804
+ call_id: callId,
805
+ name,
806
+ input: "",
807
+ status: "in_progress",
808
+ }
809
+ : {
810
+ type: "function_call" as const,
811
+ id: itemId,
812
+ call_id: callId,
813
+ name,
814
+ arguments: "",
815
+ status: "in_progress",
816
+ };
817
+ emit("response.output_item.added", { output_index: outputIndex, item });
818
+ const next: OpenFunctionCall = {
819
+ kind: "function_call",
820
+ itemId,
821
+ outputIndex,
822
+ callId,
823
+ name,
824
+ argsText: "",
825
+ ...(isCustom ? { customWireName } : {}),
826
+ };
827
+ state.open = next;
828
+ return next;
829
+ };
830
+
831
+ const closeOpen = () => {
832
+ if (!state.open) return;
833
+ if (state.open.kind === "message") {
834
+ const item = {
835
+ type: "message",
836
+ id: state.open.itemId,
837
+ status: "completed",
838
+ role: "assistant",
839
+ content: state.open.content,
840
+ };
841
+ emit("response.output_item.done", { output_index: state.open.outputIndex, item });
842
+ finishedItems.push({
843
+ type: "message",
844
+ id: state.open.itemId,
845
+ role: "assistant",
846
+ status: "completed",
847
+ content: state.open.content,
848
+ });
849
+ } else if (state.open.kind === "reasoning") {
850
+ const summary = [{ type: "summary_text" as const, text: state.open.reasoningText ?? "" }];
851
+ const item = {
852
+ type: "reasoning",
853
+ id: state.open.itemId,
854
+ summary,
855
+ };
856
+ emit("response.output_item.done", { output_index: state.open.outputIndex, item });
857
+ finishedItems.push({
858
+ type: "reasoning",
859
+ id: state.open.itemId,
860
+ summary,
861
+ });
862
+ } else {
863
+ const text = state.open.argsText ?? "";
864
+ if (state.open.customWireName) {
865
+ const item = {
866
+ type: "custom_tool_call",
867
+ id: state.open.itemId,
868
+ call_id: state.open.callId ?? "",
869
+ name: state.open.customWireName,
870
+ input: text,
871
+ status: "completed",
872
+ };
873
+ emit("response.output_item.done", { output_index: state.open.outputIndex, item });
874
+ finishedItems.push({
875
+ type: "custom_tool_call",
876
+ id: state.open.itemId,
877
+ call_id: state.open.callId ?? "",
878
+ name: state.open.customWireName,
879
+ input: text,
880
+ status: "completed",
881
+ });
882
+ } else {
883
+ const item = {
884
+ type: "function_call",
885
+ id: state.open.itemId,
886
+ call_id: state.open.callId ?? "",
887
+ name: state.open.name ?? "",
888
+ arguments: text,
889
+ status: "completed",
890
+ };
891
+ emit("response.output_item.done", { output_index: state.open.outputIndex, item });
892
+ finishedItems.push({
893
+ type: "function_call",
894
+ id: state.open.itemId,
895
+ call_id: state.open.callId ?? "",
896
+ name: state.open.name ?? "",
897
+ arguments: text,
898
+ status: "completed",
899
+ });
900
+ }
901
+ }
902
+ outputIndex++;
903
+ state.open = null;
904
+ };
905
+
906
+ try {
907
+ let finalMessage: AssistantMessage | null = null;
908
+ let failureMessage: AssistantMessage | null = null;
909
+
910
+ for await (const ev of events) {
911
+ switch (ev.type) {
912
+ case "start": {
913
+ createdAt = Math.floor((ev.partial.timestamp || Date.now()) / 1000);
914
+ // response.created — initial envelope.
915
+ controller.enqueue(
916
+ encoder.encode(
917
+ sseEvent("response.created", {
918
+ type: "response.created",
919
+ sequence_number: seq(),
920
+ response: responseSnapshot("in_progress", []),
921
+ }),
922
+ ),
923
+ );
924
+ // response.in_progress — mirrors real OpenAI; some clients gate
925
+ // on it before reading items.
926
+ controller.enqueue(
927
+ encoder.encode(
928
+ sseEvent("response.in_progress", {
929
+ type: "response.in_progress",
930
+ sequence_number: seq(),
931
+ response: responseSnapshot("in_progress", []),
932
+ }),
933
+ ),
934
+ );
935
+ break;
936
+ }
937
+ case "text_start": {
938
+ let cur: OpenMessage;
939
+ if (state.open && state.open.kind === "message") {
940
+ // continue same message item, new content part
941
+ cur = state.open;
942
+ cur.currentPartText = "";
943
+ } else {
944
+ if (state.open) closeOpen();
945
+ cur = openMessage();
946
+ }
947
+ const part = { type: "output_text", text: "", annotations: [] as never[] };
948
+ emit("response.content_part.added", {
949
+ item_id: cur.itemId,
950
+ output_index: cur.outputIndex,
951
+ content_index: cur.contentIndex,
952
+ part,
953
+ });
954
+ break;
955
+ }
956
+ case "text_delta": {
957
+ if (state.open?.kind !== "message") break;
958
+ const cur: OpenMessage = state.open;
959
+ cur.currentPartText += ev.delta;
960
+ emit("response.output_text.delta", {
961
+ item_id: cur.itemId,
962
+ output_index: cur.outputIndex,
963
+ content_index: cur.contentIndex,
964
+ delta: ev.delta,
965
+ logprobs: [],
966
+ });
967
+ // TODO: when aery-ai surfaces output_text annotations
968
+ // (web_search citations, …), emit
969
+ // `response.output_text.annotation.added` here.
970
+ break;
971
+ }
972
+ case "text_end": {
973
+ if (state.open?.kind !== "message") break;
974
+ const cur: OpenMessage = state.open;
975
+ const text = ev.content ?? cur.currentPartText;
976
+ emit("response.output_text.done", {
977
+ item_id: cur.itemId,
978
+ output_index: cur.outputIndex,
979
+ content_index: cur.contentIndex,
980
+ text,
981
+ logprobs: [],
982
+ });
983
+ cur.content.push({ type: "output_text", text, annotations: [] });
984
+ emit("response.content_part.done", {
985
+ item_id: cur.itemId,
986
+ output_index: cur.outputIndex,
987
+ content_index: cur.contentIndex,
988
+ part: { type: "output_text", text, annotations: [] },
989
+ });
990
+ cur.contentIndex += 1;
991
+ cur.currentPartText = "";
992
+ break;
993
+ }
994
+ case "thinking_start": {
995
+ if (state.open) closeOpen();
996
+ openReasoning(ev.partial, ev.contentIndex);
997
+ break;
998
+ }
999
+ case "thinking_delta": {
1000
+ if (state.open?.kind !== "reasoning") break;
1001
+ const cur: OpenReasoning = state.open;
1002
+ cur.reasoningText += ev.delta;
1003
+ emit("response.reasoning_summary_text.delta", {
1004
+ item_id: cur.itemId,
1005
+ output_index: cur.outputIndex,
1006
+ summary_index: 0,
1007
+ delta: ev.delta,
1008
+ });
1009
+ break;
1010
+ }
1011
+ case "thinking_end": {
1012
+ if (state.open?.kind !== "reasoning") break;
1013
+ const cur: OpenReasoning = state.open;
1014
+ const text = ev.content ?? cur.reasoningText;
1015
+ cur.reasoningText = text;
1016
+ emit("response.reasoning_summary_text.done", {
1017
+ item_id: cur.itemId,
1018
+ output_index: cur.outputIndex,
1019
+ summary_index: 0,
1020
+ text,
1021
+ });
1022
+ emit("response.reasoning_summary_part.done", {
1023
+ item_id: cur.itemId,
1024
+ output_index: cur.outputIndex,
1025
+ summary_index: 0,
1026
+ part: { type: "summary_text", text },
1027
+ });
1028
+ closeOpen();
1029
+ break;
1030
+ }
1031
+ case "toolcall_start": {
1032
+ if (state.open) closeOpen();
1033
+ openToolCall(ev.partial, ev.contentIndex);
1034
+ break;
1035
+ }
1036
+ case "toolcall_delta": {
1037
+ if (state.open?.kind !== "function_call") break;
1038
+ const cur: OpenFunctionCall = state.open;
1039
+ cur.argsText += ev.delta;
1040
+ if (cur.customWireName) {
1041
+ emit("response.custom_tool_call_input.delta", {
1042
+ item_id: cur.itemId,
1043
+ output_index: cur.outputIndex,
1044
+ delta: ev.delta,
1045
+ });
1046
+ } else {
1047
+ emit("response.function_call_arguments.delta", {
1048
+ item_id: cur.itemId,
1049
+ output_index: cur.outputIndex,
1050
+ delta: ev.delta,
1051
+ });
1052
+ }
1053
+ break;
1054
+ }
1055
+ case "toolcall_end": {
1056
+ if (state.open?.kind !== "function_call") break;
1057
+ const cur: OpenFunctionCall = state.open;
1058
+ // Promote possibly-late info from the canonical ToolCall.
1059
+ const tc = ev.toolCall;
1060
+ if (tc.customWireName && !cur.customWireName) cur.customWireName = tc.customWireName;
1061
+ if (tc.thoughtSignature) cur.itemId = tc.thoughtSignature;
1062
+ cur.callId = tc.id;
1063
+ cur.name = cur.customWireName ?? tc.name;
1064
+ if (cur.customWireName) {
1065
+ // Custom tool: raw input string. Streamed deltas accumulated
1066
+ // the wire-level body; fall back to `arguments.input` from
1067
+ // the finalized ToolCall when nothing streamed (rare).
1068
+ const rawInput =
1069
+ cur.argsText ||
1070
+ (typeof tc.arguments?.input === "string" ? (tc.arguments.input as string) : "");
1071
+ cur.argsText = rawInput;
1072
+ emit("response.custom_tool_call_input.done", {
1073
+ item_id: cur.itemId,
1074
+ output_index: cur.outputIndex,
1075
+ input: rawInput,
1076
+ name: cur.name,
1077
+ });
1078
+ } else {
1079
+ // Standard JSON tool: arguments object on the aery side, the
1080
+ // wire wants the JSON string the model emitted (= streamed deltas).
1081
+ const argsJson = cur.argsText || JSON.stringify(tc.arguments ?? {});
1082
+ cur.argsText = argsJson;
1083
+ emit("response.function_call_arguments.done", {
1084
+ item_id: cur.itemId,
1085
+ output_index: cur.outputIndex,
1086
+ arguments: argsJson,
1087
+ name: cur.name,
1088
+ });
1089
+ }
1090
+ closeOpen();
1091
+ break;
1092
+ }
1093
+ case "done": {
1094
+ finalMessage = ev.message;
1095
+ break;
1096
+ }
1097
+ case "error": {
1098
+ failureMessage = ev.error;
1099
+ break;
1100
+ }
1101
+ }
1102
+ }
1103
+
1104
+ if (failureMessage) {
1105
+ if (state.open) closeOpen();
1106
+ controller.enqueue(
1107
+ encoder.encode(
1108
+ sseEvent("response.failed", {
1109
+ type: "response.failed",
1110
+ sequence_number: seq(),
1111
+ response: {
1112
+ ...responseSnapshot("failed", finishedItems),
1113
+ error: { message: failureMessage.errorMessage ?? "stream failed" },
1114
+ },
1115
+ }),
1116
+ ),
1117
+ );
1118
+ emitDone();
1119
+ controller.close();
1120
+ return;
1121
+ }
1122
+
1123
+ if (state.open) closeOpen();
1124
+ const message = finalMessage ?? ((await events.result().catch(() => null)) as AssistantMessage | null);
1125
+
1126
+ // Build the canonical output from the final message so non-streaming
1127
+ // readers see the exact same shape they'd get from encodeResponse().
1128
+ const items = message ? buildOutputItems(message) : finishedItems;
1129
+ const usage = message ? buildUsage(message) : null;
1130
+ const status = message ? responseStatusForStopReason(message) : "completed";
1131
+ const terminalEvent =
1132
+ status === "incomplete"
1133
+ ? "response.incomplete"
1134
+ : status === "failed"
1135
+ ? "response.failed"
1136
+ : "response.completed";
1137
+ controller.enqueue(
1138
+ encoder.encode(
1139
+ sseEvent(terminalEvent, {
1140
+ type: terminalEvent,
1141
+ sequence_number: seq(),
1142
+ response: {
1143
+ id: responseId,
1144
+ object: "response",
1145
+ created_at: createdAt,
1146
+ status,
1147
+ model: requestedModelId,
1148
+ output: items,
1149
+ usage,
1150
+ ...(status === "incomplete" ? { incomplete_details: { reason: "max_output_tokens" } } : {}),
1151
+ ...(status === "failed"
1152
+ ? { error: { message: message?.errorMessage ?? "response failed" } }
1153
+ : {}),
1154
+ },
1155
+ }),
1156
+ ),
1157
+ );
1158
+ emitDone();
1159
+ controller.close();
1160
+ } catch (err) {
1161
+ controller.enqueue(
1162
+ encoder.encode(
1163
+ sseEvent("response.failed", {
1164
+ type: "response.failed",
1165
+ sequence_number: seq(),
1166
+ response: {
1167
+ id: responseId,
1168
+ object: "response",
1169
+ created_at: Math.floor(Date.now() / 1000),
1170
+ status: "failed",
1171
+ model: requestedModelId,
1172
+ output: [],
1173
+ error: { message: err instanceof Error ? err.message : String(err) },
1174
+ },
1175
+ }),
1176
+ ),
1177
+ );
1178
+ emitDone();
1179
+ controller.close();
1180
+ }
1181
+ },
1182
+ });
1183
+ }