@aryee337/aery-ai 0.2.28 → 0.2.29

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 (417) hide show
  1. package/CHANGELOG.md +2914 -0
  2. package/README.md +614 -813
  3. package/package.json +140 -105
  4. package/src/api-registry.ts +96 -0
  5. package/src/auth-broker/client.ts +358 -0
  6. package/src/auth-broker/index.ts +5 -0
  7. package/src/auth-broker/refresher.ts +117 -0
  8. package/src/auth-broker/remote-store.ts +623 -0
  9. package/src/auth-broker/server.ts +644 -0
  10. package/src/auth-broker/types.ts +127 -0
  11. package/src/auth-broker/wire-schemas.ts +200 -0
  12. package/src/auth-gateway/http.ts +194 -0
  13. package/src/auth-gateway/index.ts +3 -0
  14. package/src/auth-gateway/server.ts +818 -0
  15. package/src/auth-gateway/types.ts +143 -0
  16. package/src/auth-storage.ts +4422 -0
  17. package/src/index.ts +54 -0
  18. package/src/model-cache.ts +129 -0
  19. package/src/model-manager.ts +469 -0
  20. package/src/model-thinking.ts +782 -0
  21. package/src/models.json +83530 -0
  22. package/src/models.json.d.ts +9 -0
  23. package/src/models.ts +56 -0
  24. package/src/prompts/turn-aborted-guidance.md +4 -0
  25. package/src/provider-details.ts +90 -0
  26. package/src/provider-models/bundled-references.ts +38 -0
  27. package/src/provider-models/descriptors.ts +355 -0
  28. package/src/provider-models/google.ts +88 -0
  29. package/src/provider-models/index.ts +5 -0
  30. package/src/provider-models/ollama.ts +153 -0
  31. package/src/provider-models/openai-compat.ts +2817 -0
  32. package/src/provider-models/special.ts +67 -0
  33. package/src/providers/aery-native-client.ts +228 -0
  34. package/src/providers/aery-native-server.ts +212 -0
  35. package/src/providers/amazon-bedrock.ts +873 -0
  36. package/src/providers/anthropic-client.ts +318 -0
  37. package/src/providers/anthropic-messages-server-schema.ts +243 -0
  38. package/src/providers/anthropic-messages-server.ts +683 -0
  39. package/src/providers/anthropic-wire.ts +268 -0
  40. package/src/providers/anthropic.ts +3094 -0
  41. package/src/providers/aws-credentials.ts +501 -0
  42. package/src/providers/aws-eventstream.ts +185 -0
  43. package/src/providers/aws-sigv4.ts +218 -0
  44. package/src/providers/azure-openai-responses.ts +361 -0
  45. package/src/providers/cursor/gen/agent_pb.ts +15274 -0
  46. package/src/providers/cursor/proto/agent.proto +3526 -0
  47. package/src/providers/cursor/proto/buf.gen.yaml +6 -0
  48. package/src/providers/cursor/proto/buf.yaml +17 -0
  49. package/src/providers/cursor.ts +2621 -0
  50. package/src/providers/error-message.ts +21 -0
  51. package/src/providers/github-copilot-headers.ts +140 -0
  52. package/src/providers/gitlab-duo.ts +372 -0
  53. package/src/providers/google-auth.ts +252 -0
  54. package/src/providers/google-gemini-cli.ts +809 -0
  55. package/src/providers/google-gemini-headers.ts +41 -0
  56. package/src/providers/google-shared.ts +917 -0
  57. package/src/providers/google-types.ts +167 -0
  58. package/src/providers/google-vertex.ts +91 -0
  59. package/src/providers/google.ts +41 -0
  60. package/src/providers/grammar.ts +70 -0
  61. package/src/providers/kimi.ts +52 -0
  62. package/src/providers/mock.ts +496 -0
  63. package/src/providers/ollama.ts +644 -0
  64. package/src/providers/openai-anthropic-shim.ts +138 -0
  65. package/src/providers/openai-chat-server-schema.ts +252 -0
  66. package/src/providers/openai-chat-server.ts +647 -0
  67. package/src/providers/openai-codex/constants.ts +43 -0
  68. package/src/providers/openai-codex/request-transformer.ts +161 -0
  69. package/src/providers/openai-codex/response-handler.ts +81 -0
  70. package/src/providers/openai-codex-responses.ts +3018 -0
  71. package/src/providers/openai-completions-compat.ts +300 -0
  72. package/src/providers/openai-completions.ts +1979 -0
  73. package/src/providers/openai-responses-server-schema.ts +290 -0
  74. package/src/providers/openai-responses-server.ts +1183 -0
  75. package/src/providers/openai-responses-shared.ts +873 -0
  76. package/src/providers/openai-responses.ts +679 -0
  77. package/src/providers/register-builtins.ts +436 -0
  78. package/src/providers/synthetic.ts +50 -0
  79. package/src/providers/transform-messages.ts +382 -0
  80. package/src/providers/vision-guard.ts +31 -0
  81. package/src/providers/xai-responses.ts +82 -0
  82. package/src/rate-limit-utils.ts +84 -0
  83. package/src/stream.ts +1065 -0
  84. package/src/types.ts +944 -0
  85. package/src/usage/claude.ts +482 -0
  86. package/src/usage/gemini.ts +250 -0
  87. package/src/usage/github-copilot.ts +421 -0
  88. package/src/usage/google-antigravity.ts +201 -0
  89. package/src/usage/kimi.ts +271 -0
  90. package/src/usage/minimax-code.ts +31 -0
  91. package/src/usage/openai-codex.ts +503 -0
  92. package/src/usage/shared.ts +10 -0
  93. package/src/usage/zai.ts +247 -0
  94. package/src/usage.ts +185 -0
  95. package/src/utils/abort.ts +51 -0
  96. package/src/utils/abortable-iterator.ts +69 -0
  97. package/src/utils/anthropic-auth.ts +93 -0
  98. package/src/utils/discovery/antigravity.ts +261 -0
  99. package/src/utils/discovery/codex.ts +371 -0
  100. package/src/utils/discovery/cursor.ts +306 -0
  101. package/src/utils/discovery/gemini.ts +248 -0
  102. package/src/utils/discovery/index.ts +4 -0
  103. package/src/utils/discovery/openai-compatible.ts +224 -0
  104. package/src/utils/event-stream.ts +142 -0
  105. package/src/utils/fireworks-model-id.ts +30 -0
  106. package/src/utils/foundry.ts +8 -0
  107. package/src/utils/http-inspector.ts +176 -0
  108. package/src/utils/idle-iterator.ts +267 -0
  109. package/src/utils/json-parse.ts +182 -0
  110. package/src/utils/oauth/__tests__/xai-oauth.test.ts +107 -0
  111. package/src/utils/oauth/alibaba-coding-plan.ts +59 -0
  112. package/src/utils/oauth/anthropic.ts +273 -0
  113. package/src/utils/oauth/api-key-login.ts +87 -0
  114. package/src/utils/oauth/api-key-validation.ts +92 -0
  115. package/src/utils/oauth/callback-server.ts +276 -0
  116. package/src/utils/oauth/cerebras.ts +16 -0
  117. package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
  118. package/src/utils/oauth/cursor.ts +157 -0
  119. package/src/utils/oauth/deepseek.ts +53 -0
  120. package/src/utils/oauth/firepass.ts +24 -0
  121. package/src/utils/oauth/fireworks.ts +15 -0
  122. package/src/utils/oauth/github-copilot.ts +362 -0
  123. package/src/utils/oauth/gitlab-duo.ts +123 -0
  124. package/src/utils/oauth/google-antigravity.ts +200 -0
  125. package/src/utils/oauth/google-gemini-cli.ts +256 -0
  126. package/src/utils/oauth/google-oauth-shared.ts +110 -0
  127. package/src/utils/oauth/huggingface.ts +62 -0
  128. package/src/utils/oauth/index.ts +484 -0
  129. package/src/utils/oauth/kagi.ts +47 -0
  130. package/src/utils/oauth/kilo.ts +87 -0
  131. package/src/utils/oauth/kimi.ts +254 -0
  132. package/src/utils/oauth/litellm.ts +47 -0
  133. package/src/utils/oauth/lm-studio.ts +38 -0
  134. package/src/utils/oauth/minimax-code.ts +78 -0
  135. package/src/utils/oauth/moonshot.ts +23 -0
  136. package/src/utils/oauth/nanogpt.ts +15 -0
  137. package/src/utils/oauth/nvidia.ts +70 -0
  138. package/src/utils/oauth/oauth.html +203 -0
  139. package/src/utils/oauth/ollama-cloud.ts +28 -0
  140. package/src/utils/oauth/ollama.ts +47 -0
  141. package/src/utils/oauth/openai-codex.ts +299 -0
  142. package/src/utils/oauth/opencode.ts +49 -0
  143. package/src/utils/oauth/openrouter.ts +20 -0
  144. package/src/utils/oauth/parallel.ts +46 -0
  145. package/src/utils/oauth/perplexity.ts +206 -0
  146. package/src/utils/oauth/pkce.ts +18 -0
  147. package/src/utils/oauth/qianfan.ts +58 -0
  148. package/src/utils/oauth/qwen-portal.ts +60 -0
  149. package/src/utils/oauth/synthetic.ts +15 -0
  150. package/src/utils/oauth/tavily.ts +46 -0
  151. package/src/utils/oauth/together.ts +16 -0
  152. package/src/utils/oauth/types.ts +99 -0
  153. package/src/utils/oauth/venice.ts +59 -0
  154. package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
  155. package/src/utils/oauth/vllm.ts +40 -0
  156. package/src/utils/oauth/wafer.ts +50 -0
  157. package/src/utils/oauth/xai-oauth.ts +342 -0
  158. package/src/utils/oauth/xiaomi.ts +139 -0
  159. package/src/utils/oauth/zai.ts +60 -0
  160. package/src/utils/oauth/zenmux.ts +15 -0
  161. package/src/utils/oauth/zhipu.ts +60 -0
  162. package/src/utils/overflow.ts +137 -0
  163. package/src/utils/parse-bind.ts +54 -0
  164. package/src/utils/provider-response.ts +30 -0
  165. package/src/utils/request-debug.ts +336 -0
  166. package/src/utils/retry-after.ts +110 -0
  167. package/src/utils/retry.ts +54 -0
  168. package/src/utils/schema/CONSTRAINTS.md +164 -0
  169. package/src/utils/schema/adapt.ts +36 -0
  170. package/src/utils/schema/compatibility.ts +435 -0
  171. package/src/utils/schema/dereference.ts +98 -0
  172. package/src/utils/schema/draft.ts +341 -0
  173. package/src/utils/schema/equality.ts +97 -0
  174. package/src/utils/schema/fields.ts +191 -0
  175. package/src/utils/schema/index.ts +13 -0
  176. package/src/utils/schema/json-schema-validator.ts +577 -0
  177. package/src/utils/schema/meta-validator.ts +167 -0
  178. package/src/utils/schema/normalize.ts +1588 -0
  179. package/src/utils/schema/spill.ts +43 -0
  180. package/src/utils/schema/stamps.ts +97 -0
  181. package/src/utils/schema/types.ts +10 -0
  182. package/src/utils/schema/wire.ts +293 -0
  183. package/src/utils/schema/zod-decontaminate.ts +331 -0
  184. package/src/utils/sdk-stream-timeout.ts +43 -0
  185. package/src/utils/sse-debug.ts +289 -0
  186. package/src/utils/stream-markup-healing.ts +612 -0
  187. package/src/utils/tool-choice.ts +99 -0
  188. package/src/utils/validation.ts +1024 -0
  189. package/src/utils.ts +166 -0
  190. package/dist/api-registry.d.ts +0 -20
  191. package/dist/api-registry.d.ts.map +0 -1
  192. package/dist/api-registry.js +0 -44
  193. package/dist/api-registry.js.map +0 -1
  194. package/dist/bedrock-provider.d.ts +0 -5
  195. package/dist/bedrock-provider.d.ts.map +0 -1
  196. package/dist/bedrock-provider.js +0 -6
  197. package/dist/bedrock-provider.js.map +0 -1
  198. package/dist/cli.d.ts +0 -3
  199. package/dist/cli.d.ts.map +0 -1
  200. package/dist/cli.js +0 -130
  201. package/dist/cli.js.map +0 -1
  202. package/dist/env-api-keys.d.ts +0 -18
  203. package/dist/env-api-keys.d.ts.map +0 -1
  204. package/dist/env-api-keys.js +0 -178
  205. package/dist/env-api-keys.js.map +0 -1
  206. package/dist/image-models.d.ts +0 -10
  207. package/dist/image-models.d.ts.map +0 -1
  208. package/dist/image-models.generated.d.ts +0 -440
  209. package/dist/image-models.generated.d.ts.map +0 -1
  210. package/dist/image-models.generated.js +0 -442
  211. package/dist/image-models.generated.js.map +0 -1
  212. package/dist/image-models.js +0 -23
  213. package/dist/image-models.js.map +0 -1
  214. package/dist/images-api-registry.d.ts +0 -14
  215. package/dist/images-api-registry.d.ts.map +0 -1
  216. package/dist/images-api-registry.js +0 -22
  217. package/dist/images-api-registry.js.map +0 -1
  218. package/dist/images.d.ts +0 -4
  219. package/dist/images.d.ts.map +0 -1
  220. package/dist/images.js +0 -14
  221. package/dist/images.js.map +0 -1
  222. package/dist/index.d.ts +0 -32
  223. package/dist/index.d.ts.map +0 -1
  224. package/dist/index.js +0 -20
  225. package/dist/index.js.map +0 -1
  226. package/dist/models.d.ts +0 -18
  227. package/dist/models.d.ts.map +0 -1
  228. package/dist/models.generated.d.ts +0 -17707
  229. package/dist/models.generated.d.ts.map +0 -1
  230. package/dist/models.generated.js +0 -16561
  231. package/dist/models.generated.js.map +0 -1
  232. package/dist/models.js +0 -71
  233. package/dist/models.js.map +0 -1
  234. package/dist/oauth.d.ts +0 -2
  235. package/dist/oauth.d.ts.map +0 -1
  236. package/dist/oauth.js +0 -2
  237. package/dist/oauth.js.map +0 -1
  238. package/dist/providers/aery-error-formatting.d.ts +0 -13
  239. package/dist/providers/aery-error-formatting.d.ts.map +0 -1
  240. package/dist/providers/aery-error-formatting.js +0 -112
  241. package/dist/providers/aery-error-formatting.js.map +0 -1
  242. package/dist/providers/amazon-bedrock.d.ts +0 -38
  243. package/dist/providers/amazon-bedrock.d.ts.map +0 -1
  244. package/dist/providers/amazon-bedrock.js +0 -763
  245. package/dist/providers/amazon-bedrock.js.map +0 -1
  246. package/dist/providers/anthropic.d.ts +0 -71
  247. package/dist/providers/anthropic.d.ts.map +0 -1
  248. package/dist/providers/anthropic.js +0 -949
  249. package/dist/providers/anthropic.js.map +0 -1
  250. package/dist/providers/azure-openai-responses.d.ts +0 -15
  251. package/dist/providers/azure-openai-responses.d.ts.map +0 -1
  252. package/dist/providers/azure-openai-responses.js +0 -225
  253. package/dist/providers/azure-openai-responses.js.map +0 -1
  254. package/dist/providers/cloudflare.d.ts +0 -13
  255. package/dist/providers/cloudflare.d.ts.map +0 -1
  256. package/dist/providers/cloudflare.js +0 -26
  257. package/dist/providers/cloudflare.js.map +0 -1
  258. package/dist/providers/faux.d.ts +0 -56
  259. package/dist/providers/faux.d.ts.map +0 -1
  260. package/dist/providers/faux.js +0 -368
  261. package/dist/providers/faux.js.map +0 -1
  262. package/dist/providers/github-copilot-headers.d.ts +0 -8
  263. package/dist/providers/github-copilot-headers.d.ts.map +0 -1
  264. package/dist/providers/github-copilot-headers.js +0 -29
  265. package/dist/providers/github-copilot-headers.js.map +0 -1
  266. package/dist/providers/google-gemini-cli.d.ts +0 -74
  267. package/dist/providers/google-gemini-cli.d.ts.map +0 -1
  268. package/dist/providers/google-gemini-cli.js +0 -779
  269. package/dist/providers/google-gemini-cli.js.map +0 -1
  270. package/dist/providers/google-shared.d.ts +0 -70
  271. package/dist/providers/google-shared.d.ts.map +0 -1
  272. package/dist/providers/google-shared.js +0 -329
  273. package/dist/providers/google-shared.js.map +0 -1
  274. package/dist/providers/google-vertex.d.ts +0 -15
  275. package/dist/providers/google-vertex.d.ts.map +0 -1
  276. package/dist/providers/google-vertex.js +0 -442
  277. package/dist/providers/google-vertex.js.map +0 -1
  278. package/dist/providers/google.d.ts +0 -13
  279. package/dist/providers/google.d.ts.map +0 -1
  280. package/dist/providers/google.js +0 -400
  281. package/dist/providers/google.js.map +0 -1
  282. package/dist/providers/images/openrouter.d.ts +0 -3
  283. package/dist/providers/images/openrouter.d.ts.map +0 -1
  284. package/dist/providers/images/openrouter.js +0 -129
  285. package/dist/providers/images/openrouter.js.map +0 -1
  286. package/dist/providers/images/register-builtins.d.ts +0 -4
  287. package/dist/providers/images/register-builtins.d.ts.map +0 -1
  288. package/dist/providers/images/register-builtins.js +0 -34
  289. package/dist/providers/images/register-builtins.js.map +0 -1
  290. package/dist/providers/mistral.d.ts +0 -25
  291. package/dist/providers/mistral.d.ts.map +0 -1
  292. package/dist/providers/mistral.js +0 -535
  293. package/dist/providers/mistral.js.map +0 -1
  294. package/dist/providers/openai-codex-responses.d.ts +0 -30
  295. package/dist/providers/openai-codex-responses.d.ts.map +0 -1
  296. package/dist/providers/openai-codex-responses.js +0 -1090
  297. package/dist/providers/openai-codex-responses.js.map +0 -1
  298. package/dist/providers/openai-completions.d.ts +0 -19
  299. package/dist/providers/openai-completions.d.ts.map +0 -1
  300. package/dist/providers/openai-completions.js +0 -950
  301. package/dist/providers/openai-completions.js.map +0 -1
  302. package/dist/providers/openai-prompt-cache.d.ts +0 -3
  303. package/dist/providers/openai-prompt-cache.d.ts.map +0 -1
  304. package/dist/providers/openai-prompt-cache.js +0 -10
  305. package/dist/providers/openai-prompt-cache.js.map +0 -1
  306. package/dist/providers/openai-responses-shared.d.ts +0 -18
  307. package/dist/providers/openai-responses-shared.d.ts.map +0 -1
  308. package/dist/providers/openai-responses-shared.js +0 -492
  309. package/dist/providers/openai-responses-shared.js.map +0 -1
  310. package/dist/providers/openai-responses.d.ts +0 -13
  311. package/dist/providers/openai-responses.d.ts.map +0 -1
  312. package/dist/providers/openai-responses.js +0 -237
  313. package/dist/providers/openai-responses.js.map +0 -1
  314. package/dist/providers/register-builtins.d.ts +0 -38
  315. package/dist/providers/register-builtins.d.ts.map +0 -1
  316. package/dist/providers/register-builtins.js +0 -278
  317. package/dist/providers/register-builtins.js.map +0 -1
  318. package/dist/providers/simple-options.d.ts +0 -8
  319. package/dist/providers/simple-options.d.ts.map +0 -1
  320. package/dist/providers/simple-options.js +0 -41
  321. package/dist/providers/simple-options.js.map +0 -1
  322. package/dist/providers/transform-messages.d.ts +0 -8
  323. package/dist/providers/transform-messages.d.ts.map +0 -1
  324. package/dist/providers/transform-messages.js +0 -184
  325. package/dist/providers/transform-messages.js.map +0 -1
  326. package/dist/session-resources.d.ts +0 -4
  327. package/dist/session-resources.d.ts.map +0 -1
  328. package/dist/session-resources.js +0 -22
  329. package/dist/session-resources.js.map +0 -1
  330. package/dist/stream.d.ts +0 -8
  331. package/dist/stream.d.ts.map +0 -1
  332. package/dist/stream.js +0 -27
  333. package/dist/stream.js.map +0 -1
  334. package/dist/types.d.ts +0 -498
  335. package/dist/types.d.ts.map +0 -1
  336. package/dist/types.js +0 -2
  337. package/dist/types.js.map +0 -1
  338. package/dist/utils/diagnostics.d.ts +0 -19
  339. package/dist/utils/diagnostics.d.ts.map +0 -1
  340. package/dist/utils/diagnostics.js +0 -25
  341. package/dist/utils/diagnostics.js.map +0 -1
  342. package/dist/utils/event-stream.d.ts +0 -21
  343. package/dist/utils/event-stream.d.ts.map +0 -1
  344. package/dist/utils/event-stream.js +0 -81
  345. package/dist/utils/event-stream.js.map +0 -1
  346. package/dist/utils/hash.d.ts +0 -3
  347. package/dist/utils/hash.d.ts.map +0 -1
  348. package/dist/utils/hash.js +0 -14
  349. package/dist/utils/hash.js.map +0 -1
  350. package/dist/utils/headers.d.ts +0 -2
  351. package/dist/utils/headers.d.ts.map +0 -1
  352. package/dist/utils/headers.js +0 -8
  353. package/dist/utils/headers.js.map +0 -1
  354. package/dist/utils/json-parse.d.ts +0 -16
  355. package/dist/utils/json-parse.d.ts.map +0 -1
  356. package/dist/utils/json-parse.js +0 -113
  357. package/dist/utils/json-parse.js.map +0 -1
  358. package/dist/utils/node-http-proxy.d.ts +0 -10
  359. package/dist/utils/node-http-proxy.d.ts.map +0 -1
  360. package/dist/utils/node-http-proxy.js +0 -97
  361. package/dist/utils/node-http-proxy.js.map +0 -1
  362. package/dist/utils/oauth/anthropic.d.ts +0 -25
  363. package/dist/utils/oauth/anthropic.d.ts.map +0 -1
  364. package/dist/utils/oauth/anthropic.js +0 -335
  365. package/dist/utils/oauth/anthropic.js.map +0 -1
  366. package/dist/utils/oauth/device-code.d.ts +0 -19
  367. package/dist/utils/oauth/device-code.d.ts.map +0 -1
  368. package/dist/utils/oauth/device-code.js +0 -55
  369. package/dist/utils/oauth/device-code.js.map +0 -1
  370. package/dist/utils/oauth/github-copilot.d.ts +0 -30
  371. package/dist/utils/oauth/github-copilot.d.ts.map +0 -1
  372. package/dist/utils/oauth/github-copilot.js +0 -268
  373. package/dist/utils/oauth/github-copilot.js.map +0 -1
  374. package/dist/utils/oauth/google-antigravity.d.ts +0 -26
  375. package/dist/utils/oauth/google-antigravity.d.ts.map +0 -1
  376. package/dist/utils/oauth/google-antigravity.js +0 -377
  377. package/dist/utils/oauth/google-antigravity.js.map +0 -1
  378. package/dist/utils/oauth/google-gemini-cli.d.ts +0 -26
  379. package/dist/utils/oauth/google-gemini-cli.d.ts.map +0 -1
  380. package/dist/utils/oauth/google-gemini-cli.js +0 -482
  381. package/dist/utils/oauth/google-gemini-cli.js.map +0 -1
  382. package/dist/utils/oauth/index.d.ts +0 -63
  383. package/dist/utils/oauth/index.d.ts.map +0 -1
  384. package/dist/utils/oauth/index.js +0 -131
  385. package/dist/utils/oauth/index.js.map +0 -1
  386. package/dist/utils/oauth/oauth-page.d.ts +0 -3
  387. package/dist/utils/oauth/oauth-page.d.ts.map +0 -1
  388. package/dist/utils/oauth/oauth-page.js +0 -105
  389. package/dist/utils/oauth/oauth-page.js.map +0 -1
  390. package/dist/utils/oauth/openai-codex.d.ts +0 -34
  391. package/dist/utils/oauth/openai-codex.d.ts.map +0 -1
  392. package/dist/utils/oauth/openai-codex.js +0 -385
  393. package/dist/utils/oauth/openai-codex.js.map +0 -1
  394. package/dist/utils/oauth/pkce.d.ts +0 -13
  395. package/dist/utils/oauth/pkce.d.ts.map +0 -1
  396. package/dist/utils/oauth/pkce.js +0 -31
  397. package/dist/utils/oauth/pkce.js.map +0 -1
  398. package/dist/utils/oauth/types.d.ts +0 -64
  399. package/dist/utils/oauth/types.d.ts.map +0 -1
  400. package/dist/utils/oauth/types.js +0 -2
  401. package/dist/utils/oauth/types.js.map +0 -1
  402. package/dist/utils/overflow.d.ts +0 -56
  403. package/dist/utils/overflow.d.ts.map +0 -1
  404. package/dist/utils/overflow.js +0 -151
  405. package/dist/utils/overflow.js.map +0 -1
  406. package/dist/utils/sanitize-unicode.d.ts +0 -22
  407. package/dist/utils/sanitize-unicode.d.ts.map +0 -1
  408. package/dist/utils/sanitize-unicode.js +0 -26
  409. package/dist/utils/sanitize-unicode.js.map +0 -1
  410. package/dist/utils/typebox-helpers.d.ts +0 -17
  411. package/dist/utils/typebox-helpers.d.ts.map +0 -1
  412. package/dist/utils/typebox-helpers.js +0 -21
  413. package/dist/utils/typebox-helpers.js.map +0 -1
  414. package/dist/utils/validation.d.ts +0 -18
  415. package/dist/utils/validation.d.ts.map +0 -1
  416. package/dist/utils/validation.js +0 -281
  417. package/dist/utils/validation.js.map +0 -1
@@ -0,0 +1,679 @@
1
+ import { $env, extractHttpStatusFromError, structuredCloneJSON } from "@aryee337/aery-utils";
2
+ import OpenAI, { APIConnectionTimeoutError as OpenAIConnectionTimeoutError } from "openai";
3
+ import type {
4
+ Tool as OpenAITool,
5
+ ResponseCreateParamsStreaming,
6
+ ResponseInput,
7
+ } from "openai/resources/responses/responses";
8
+ import { getEnvApiKey } from "../stream";
9
+ import type {
10
+ AssistantMessage,
11
+ CacheRetention,
12
+ Context,
13
+ FetchImpl,
14
+ MessageAttribution,
15
+ Model,
16
+ OpenAICompat,
17
+ ProviderSessionState,
18
+ ServiceTier,
19
+ StreamFunction,
20
+ StreamOptions,
21
+ Tool,
22
+ ToolChoice,
23
+ } from "../types";
24
+ import {
25
+ createOpenAIResponsesHistoryPayload,
26
+ getOpenAIResponsesHistoryItems,
27
+ getOpenAIResponsesHistoryPayload,
28
+ normalizeSystemPrompts,
29
+ resolveCacheRetention,
30
+ sanitizeOpenAIResponsesHistoryItemsForReplay,
31
+ } from "../utils";
32
+ import { createAbortSourceTracker } from "../utils/abort";
33
+ import { AssistantMessageEventStream } from "../utils/event-stream";
34
+ import { finalizeErrorMessage, type RawHttpRequestDump, rewriteCopilotError } from "../utils/http-inspector";
35
+ import {
36
+ getOpenAIStreamFirstEventTimeoutMs,
37
+ getOpenAIStreamIdleTimeoutMs,
38
+ iterateWithIdleTimeout,
39
+ } from "../utils/idle-iterator";
40
+ import { parseGitHubCopilotApiKey } from "../utils/oauth/github-copilot";
41
+ import { notifyProviderResponse } from "../utils/provider-response";
42
+ import { callWithCopilotModelRetry } from "../utils/retry";
43
+ import { adaptSchemaForStrict, NO_STRICT, sanitizeSchemaForOpenAIResponses, toolWireSchema } from "../utils/schema";
44
+ import { createSdkStreamRequestOptions } from "../utils/sdk-stream-timeout";
45
+ import { wrapFetchForSseDebug } from "../utils/sse-debug";
46
+ import { mapToOpenAIResponsesToolChoice, type OpenAIResponsesToolChoice } from "../utils/tool-choice";
47
+ import {
48
+ buildCopilotDynamicHeaders,
49
+ hasCopilotVisionInput,
50
+ resolveGitHubCopilotBaseUrl,
51
+ } from "./github-copilot-headers";
52
+ import { compactGrammarDefinition } from "./grammar";
53
+ import {
54
+ appendResponsesToolResultMessages,
55
+ applyCommonResponsesSamplingParams,
56
+ applyResponsesReasoningParams,
57
+ collectCustomCallIds,
58
+ collectKnownCallIds,
59
+ convertResponsesAssistantMessage,
60
+ convertResponsesInputContent,
61
+ createInitialResponsesAssistantMessage,
62
+ isOpenAIResponsesProgressEvent,
63
+ normalizeResponsesToolCallIdForTransform,
64
+ processResponsesStream,
65
+ repairOrphanResponsesToolOutputs,
66
+ } from "./openai-responses-shared";
67
+ import { transformMessages } from "./transform-messages";
68
+
69
+ /**
70
+ * Get prompt cache retention based on cacheRetention and base URL.
71
+ * Only applies to direct OpenAI API calls (api.openai.com).
72
+ */
73
+ function getPromptCacheRetention(baseUrl: string, cacheRetention: CacheRetention): "24h" | undefined {
74
+ if (cacheRetention !== "long") {
75
+ return undefined;
76
+ }
77
+ if (baseUrl.includes("api.openai.com")) {
78
+ return "24h";
79
+ }
80
+ return undefined;
81
+ }
82
+
83
+ export function normalizeOpenAIResponsesPromptCacheKey(sessionId: string | undefined): string | undefined {
84
+ if (!sessionId || sessionId.length === 0) return undefined;
85
+ const wellFormed = sessionId.toWellFormed();
86
+ if (wellFormed.length <= 64) return wellFormed;
87
+ return `pc_${Bun.hash(wellFormed).toString(36)}`;
88
+ }
89
+
90
+ // OpenAI Responses-specific options
91
+ export interface OpenAIResponsesOptions extends StreamOptions {
92
+ reasoning?: "minimal" | "low" | "medium" | "high" | "xhigh";
93
+ reasoningSummary?: "auto" | "detailed" | "concise" | null;
94
+ serviceTier?: ServiceTier;
95
+ toolChoice?: ToolChoice;
96
+ /**
97
+ * Enforce strict tool call/result pairing when building Responses API inputs.
98
+ * Azure OpenAI and GitHub Copilot Responses paths require tool results to match prior tool calls.
99
+ */
100
+ strictResponsesPairing?: boolean;
101
+ /**
102
+ * Pass `include: ["reasoning.encrypted_content"]` on requests when the
103
+ * model supports reasoning. Default: true (preserves current behavior).
104
+ * Set to false when the upstream Responses endpoint rejects replayed
105
+ * encrypted reasoning (e.g., xAI Grok under SuperGrok OAuth).
106
+ */
107
+ includeEncryptedReasoning?: boolean;
108
+ /**
109
+ * Strip `type: "reasoning"` items from replayed conversation history
110
+ * before they hit the wire. Default: false (preserves current behavior).
111
+ * Set to true when the upstream rejects replayed reasoning wrappers.
112
+ */
113
+ filterReasoningHistory?: boolean;
114
+ /**
115
+ * Suppress the `reasoning.effort` wire param when set, even if
116
+ * `options.reasoning` is requested. Default: false. xAI Grok models
117
+ * outside the effort-capable allowlist 400 with "Model X does not
118
+ * support parameter reasoningEffort" — the xAI Responses adapter sets
119
+ * this when the target model is not in GROK_EFFORT_CAPABLE_PREFIXES.
120
+ */
121
+ omitReasoningEffort?: boolean;
122
+ /**
123
+ * Extra request headers merged onto the underlying client's
124
+ * defaultHeaders. Used by adapter wrappers to inject provider-specific
125
+ * routing or cache hints.
126
+ */
127
+ headers?: Record<string, string>;
128
+ /**
129
+ * Extra body fields merged into the Responses request payload. Used by
130
+ * adapter wrappers to inject provider-specific body keys (e.g.,
131
+ * prompt_cache_key for prompt-cache routing).
132
+ */
133
+ extraBody?: Record<string, unknown>;
134
+ }
135
+
136
+ const OPENAI_RESPONSES_PROVIDER_SESSION_STATE_PREFIX = "openai-responses:";
137
+ const OPENAI_RESPONSES_FIRST_EVENT_TIMEOUT_MESSAGE =
138
+ "OpenAI responses stream timed out while waiting for the first event";
139
+
140
+ interface OpenAIResponsesProviderSessionState extends ProviderSessionState {
141
+ nativeHistoryReplayWarmed: boolean;
142
+ }
143
+
144
+ function createOpenAIResponsesProviderSessionState(): OpenAIResponsesProviderSessionState {
145
+ const state: OpenAIResponsesProviderSessionState = {
146
+ nativeHistoryReplayWarmed: false,
147
+ close: () => {
148
+ state.nativeHistoryReplayWarmed = false;
149
+ },
150
+ };
151
+ return state;
152
+ }
153
+
154
+ function getOpenAIResponsesProviderSessionStateKey(model: Model<"openai-responses">): string {
155
+ return `${OPENAI_RESPONSES_PROVIDER_SESSION_STATE_PREFIX}${model.provider}`;
156
+ }
157
+
158
+ function getOpenAIResponsesProviderSessionState(
159
+ model: Model<"openai-responses">,
160
+ providerSessionState: Map<string, ProviderSessionState> | undefined,
161
+ ): OpenAIResponsesProviderSessionState | undefined {
162
+ if (!providerSessionState) return undefined;
163
+ const key = getOpenAIResponsesProviderSessionStateKey(model);
164
+ const existing = providerSessionState.get(key) as OpenAIResponsesProviderSessionState | undefined;
165
+ if (existing) return existing;
166
+ const created = createOpenAIResponsesProviderSessionState();
167
+ providerSessionState.set(key, created);
168
+ return created;
169
+ }
170
+
171
+ function canReplayOpenAIResponsesNativeHistory(
172
+ providerSessionState: OpenAIResponsesProviderSessionState | undefined,
173
+ ): boolean {
174
+ return providerSessionState?.nativeHistoryReplayWarmed ?? true;
175
+ }
176
+
177
+ type OpenAIResponsesSamplingParams = ResponseCreateParamsStreaming & {
178
+ top_p?: number;
179
+ top_k?: number;
180
+ min_p?: number;
181
+ presence_penalty?: number;
182
+ repetition_penalty?: number;
183
+ stream_options?: { include_obfuscation?: boolean };
184
+ };
185
+
186
+ /**
187
+ * Generate function for OpenAI Responses API
188
+ */
189
+ export const streamOpenAIResponses: StreamFunction<"openai-responses"> = (
190
+ model: Model<"openai-responses">,
191
+ context: Context,
192
+ options?: OpenAIResponsesOptions,
193
+ ): AssistantMessageEventStream => {
194
+ const stream = new AssistantMessageEventStream();
195
+
196
+ // Start async processing
197
+ (async () => {
198
+ const startTime = Date.now();
199
+ let firstTokenTime: number | undefined;
200
+
201
+ const output: AssistantMessage = createInitialResponsesAssistantMessage(
202
+ "openai-responses",
203
+ model.provider,
204
+ model.id,
205
+ );
206
+ let rawRequestDump: RawHttpRequestDump | undefined;
207
+ const abortTracker = createAbortSourceTracker(options?.signal);
208
+ const firstEventTimeoutAbortError = new Error(OPENAI_RESPONSES_FIRST_EVENT_TIMEOUT_MESSAGE);
209
+ const { requestAbortController, requestSignal } = abortTracker;
210
+
211
+ try {
212
+ // Keep request routing on `sessionId` while allowing callers to pin a
213
+ // stable prompt-cache key independently. Side-channel calls use this to
214
+ // avoid perturbing provider conversation state without cold-starting the cache.
215
+ const routingSessionId = getOpenAIResponsesRoutingSessionId(options);
216
+ const apiKey = options?.apiKey || getEnvApiKey(model.provider) || "";
217
+ const { client, copilotPremiumRequests, baseUrl } = createClient(
218
+ model,
219
+ context,
220
+ apiKey,
221
+ options?.headers,
222
+ options?.initiatorOverride,
223
+ routingSessionId,
224
+ options?.onSseEvent,
225
+ options?.fetch,
226
+ );
227
+ const premiumRequestsTotal = copilotPremiumRequests;
228
+ const providerSessionState = getOpenAIResponsesProviderSessionState(model, options?.providerSessionState);
229
+ const { params } = buildParams(model, context, options, providerSessionState, baseUrl);
230
+ const idleTimeoutMs = options?.streamIdleTimeoutMs ?? getOpenAIStreamIdleTimeoutMs();
231
+ const firstEventTimeoutMs =
232
+ options?.streamFirstEventTimeoutMs ?? getOpenAIStreamFirstEventTimeoutMs(idleTimeoutMs);
233
+ const requestTimeoutMs =
234
+ firstEventTimeoutMs !== undefined && firstEventTimeoutMs > 0 ? firstEventTimeoutMs : undefined;
235
+ options?.onPayload?.(params);
236
+ rawRequestDump = {
237
+ provider: model.provider,
238
+ api: output.api,
239
+ model: model.id,
240
+ method: "POST",
241
+ url: `${baseUrl ?? "https://api.openai.com/v1"}/responses`,
242
+ body: params,
243
+ };
244
+ const openaiStream = await callWithCopilotModelRetry(
245
+ async () => {
246
+ const requestOptions = createSdkStreamRequestOptions(requestSignal, requestTimeoutMs);
247
+ let requestTimeout: NodeJS.Timeout | undefined;
248
+ if (requestTimeoutMs !== undefined) {
249
+ requestTimeout = setTimeout(
250
+ () => abortTracker.abortLocally(firstEventTimeoutAbortError),
251
+ requestTimeoutMs,
252
+ );
253
+ }
254
+ try {
255
+ const { data, response, request_id } = await client.responses
256
+ .create(params, requestOptions)
257
+ .withResponse();
258
+ await notifyProviderResponse(options, response, model, request_id);
259
+ return data;
260
+ } catch (error) {
261
+ if (error instanceof OpenAIConnectionTimeoutError && !abortTracker.wasCallerAbort()) {
262
+ throw firstEventTimeoutAbortError;
263
+ }
264
+ throw error;
265
+ } finally {
266
+ if (requestTimeout !== undefined) clearTimeout(requestTimeout);
267
+ }
268
+ },
269
+ { provider: model.provider, signal: requestSignal },
270
+ );
271
+ if (premiumRequestsTotal !== undefined) output.usage.premiumRequests = premiumRequestsTotal;
272
+ stream.push({ type: "start", partial: output });
273
+
274
+ const nativeOutputItems: Array<Record<string, unknown>> = [];
275
+ await processResponsesStream(
276
+ iterateWithIdleTimeout(openaiStream, {
277
+ idleTimeoutMs,
278
+ firstItemTimeoutMs: firstEventTimeoutMs,
279
+ firstItemErrorMessage: OPENAI_RESPONSES_FIRST_EVENT_TIMEOUT_MESSAGE,
280
+ errorMessage: "OpenAI responses stream stalled while waiting for the next event",
281
+ onFirstItemTimeout: () => abortTracker.abortLocally(firstEventTimeoutAbortError),
282
+ onIdle: () => requestAbortController.abort(),
283
+ abortSignal: options?.signal,
284
+ isProgressItem: isOpenAIResponsesProgressEvent,
285
+ }),
286
+ output,
287
+ stream,
288
+ model,
289
+ {
290
+ onFirstToken: () => {
291
+ if (!firstTokenTime) firstTokenTime = Date.now();
292
+ },
293
+ onOutputItemDone: item => {
294
+ nativeOutputItems.push(structuredCloneJSON<unknown>(item) as unknown as Record<string, unknown>);
295
+ },
296
+ },
297
+ );
298
+ if (premiumRequestsTotal !== undefined) output.usage.premiumRequests = premiumRequestsTotal;
299
+
300
+ const firstEventTimeoutError = abortTracker.getLocalAbortReason();
301
+ if (firstEventTimeoutError) {
302
+ throw firstEventTimeoutError;
303
+ }
304
+ if (abortTracker.wasCallerAbort()) {
305
+ throw new Error("Request was aborted");
306
+ }
307
+
308
+ if (output.stopReason === "aborted" || output.stopReason === "error") {
309
+ throw new Error(output.errorMessage ?? "An unknown error occurred");
310
+ }
311
+
312
+ output.providerPayload = createOpenAIResponsesHistoryPayload(model.provider, nativeOutputItems);
313
+ if (providerSessionState) providerSessionState.nativeHistoryReplayWarmed = true;
314
+
315
+ output.duration = Date.now() - startTime;
316
+ if (firstTokenTime) output.ttft = firstTokenTime - startTime;
317
+ stream.push({ type: "done", reason: output.stopReason, message: output });
318
+ stream.end();
319
+ } catch (error) {
320
+ for (const block of output.content) delete (block as { index?: number }).index;
321
+ const firstEventTimeoutError = abortTracker.getLocalAbortReason();
322
+ output.stopReason = abortTracker.wasCallerAbort() ? "aborted" : "error";
323
+ output.errorStatus = extractHttpStatusFromError(error);
324
+ output.errorMessage = firstEventTimeoutError?.message ?? (await finalizeErrorMessage(error, rawRequestDump));
325
+ output.errorMessage = rewriteCopilotError(output.errorMessage, error, model.provider);
326
+ output.duration = Date.now() - startTime;
327
+ if (firstTokenTime) output.ttft = firstTokenTime - startTime;
328
+ stream.push({ type: "error", reason: output.stopReason, error: output });
329
+ stream.end();
330
+ }
331
+ })();
332
+
333
+ return stream;
334
+ };
335
+
336
+ function createClient(
337
+ model: Model<"openai-responses">,
338
+ context: Context,
339
+ apiKey?: string,
340
+ extraHeaders?: Record<string, string>,
341
+ initiatorOverride?: MessageAttribution,
342
+ sessionId?: string,
343
+ onSseEvent?: OpenAIResponsesOptions["onSseEvent"],
344
+ fetchOverride?: FetchImpl,
345
+ ): {
346
+ client: OpenAI;
347
+ copilotPremiumRequests: number | undefined;
348
+ baseUrl: string | undefined;
349
+ } {
350
+ if (!apiKey) {
351
+ if (!$env.OPENAI_API_KEY) {
352
+ throw new Error(
353
+ "OpenAI API key is required. Set OPENAI_API_KEY environment variable or pass it as an argument.",
354
+ );
355
+ }
356
+ apiKey = $env.OPENAI_API_KEY;
357
+ }
358
+ const rawApiKey = apiKey;
359
+
360
+ const headers = { ...(model.headers ?? {}), ...(extraHeaders ?? {}) };
361
+ let copilotPremiumRequests: number | undefined;
362
+
363
+ let baseUrl = model.baseUrl;
364
+ if (model.provider === "github-copilot") {
365
+ apiKey = parseGitHubCopilotApiKey(rawApiKey).accessToken;
366
+ const hasImages = hasCopilotVisionInput(context.messages);
367
+ const copilot = buildCopilotDynamicHeaders({
368
+ messages: context.messages,
369
+ hasImages,
370
+ premiumMultiplier: model.premiumMultiplier,
371
+ headers,
372
+ initiatorOverride,
373
+ });
374
+ Object.assign(headers, copilot.headers);
375
+ copilotPremiumRequests = copilot.premiumRequests;
376
+ baseUrl = resolveGitHubCopilotBaseUrl(model.baseUrl, rawApiKey) ?? model.baseUrl;
377
+ }
378
+ if (sessionId && model.provider === "openai" && (baseUrl ?? "").toLowerCase().includes("api.openai.com")) {
379
+ headers.session_id ??= sessionId;
380
+ headers["x-client-request-id"] ??= sessionId;
381
+ }
382
+ const baseFetch = fetchOverride ?? fetch;
383
+ return {
384
+ client: new OpenAI({
385
+ apiKey,
386
+ baseURL: baseUrl,
387
+ dangerouslyAllowBrowser: true,
388
+ maxRetries: 5,
389
+ defaultHeaders: headers,
390
+ fetch: onSseEvent ? wrapFetchForSseDebug(baseFetch, event => onSseEvent(event, model)) : baseFetch,
391
+ }),
392
+ copilotPremiumRequests,
393
+ baseUrl,
394
+ };
395
+ }
396
+
397
+ function getOpenAIResponsesPromptCacheKey(
398
+ options: Pick<OpenAIResponsesOptions, "cacheRetention" | "promptCacheKey" | "sessionId"> | undefined,
399
+ ): string | undefined {
400
+ if (resolveCacheRetention(options?.cacheRetention) === "none") return undefined;
401
+ return normalizeOpenAIResponsesPromptCacheKey(options?.promptCacheKey ?? options?.sessionId);
402
+ }
403
+
404
+ export function getOpenAIResponsesCacheSessionId(
405
+ options: Pick<OpenAIResponsesOptions, "cacheRetention" | "sessionId" | "promptCacheKey"> | undefined,
406
+ ): string | undefined {
407
+ return getOpenAIResponsesPromptCacheKey(options);
408
+ }
409
+ function getOpenAIResponsesRoutingSessionId(
410
+ options: Pick<OpenAIResponsesOptions, "cacheRetention" | "sessionId"> | undefined,
411
+ ): string | undefined {
412
+ if (resolveCacheRetention(options?.cacheRetention) === "none") return undefined;
413
+ return normalizeOpenAIResponsesPromptCacheKey(options?.sessionId);
414
+ }
415
+
416
+ function buildParams(
417
+ model: Model<"openai-responses">,
418
+ context: Context,
419
+ options: OpenAIResponsesOptions | undefined,
420
+ providerSessionState: OpenAIResponsesProviderSessionState | undefined,
421
+ resolvedBaseUrl?: string,
422
+ ): { conversationMessages: ResponseInput; params: OpenAIResponsesSamplingParams } {
423
+ const strictResponsesPairing =
424
+ options?.strictResponsesPairing ??
425
+ (isAzureOpenAIBaseUrl(model.baseUrl ?? "") || model.provider === "github-copilot");
426
+ const conversationMessages = convertConversationMessages(
427
+ model,
428
+ context,
429
+ strictResponsesPairing,
430
+ providerSessionState,
431
+ options,
432
+ );
433
+ const messages: ResponseInput = [...conversationMessages];
434
+
435
+ const systemPrompts = normalizeSystemPrompts(context.systemPrompt);
436
+ let systemInstructions: string | undefined;
437
+ if (systemPrompts.length > 0) {
438
+ const needsDeveloperRole = model.reasoning && supportsDeveloperRole(resolvedBaseUrl ?? model);
439
+ if (needsDeveloperRole) {
440
+ // Reasoning models on known OpenAI-compatible endpoints require the
441
+ // `developer` role. Send all system prompts inline in `input`.
442
+ messages.unshift(
443
+ ...systemPrompts.map(systemPrompt => ({ role: "developer" as const, content: systemPrompt })),
444
+ );
445
+ } else {
446
+ // All other endpoints (including third-party /v1/responses proxies) use
447
+ // the canonical top-level `instructions` field so that proxies that
448
+ // reject `input[{role:"system"}]` work out of the box.
449
+ systemInstructions = systemPrompts.join("\n\n");
450
+ }
451
+ }
452
+
453
+ const cacheRetention = resolveCacheRetention(options?.cacheRetention);
454
+ const promptCacheKey = getOpenAIResponsesPromptCacheKey(options);
455
+ const params: OpenAIResponsesSamplingParams = {
456
+ model: model.id,
457
+ input: messages,
458
+ instructions: systemInstructions,
459
+ stream: true,
460
+ prompt_cache_key: promptCacheKey,
461
+ prompt_cache_retention: promptCacheKey ? getPromptCacheRetention(model.baseUrl, cacheRetention) : undefined,
462
+ store: false,
463
+ stream_options: model.provider === "openai" ? { include_obfuscation: false } : undefined,
464
+ };
465
+
466
+ applyCommonResponsesSamplingParams(params, options, model.provider);
467
+ // TODO: openai responses has no top-level `stop`/`stop_sequences`; surface via reasoning.stop?
468
+ // `StreamOptions.stopSequences` is intentionally dropped for this provider.
469
+ // TODO: openai responses has no top-level `frequency_penalty` field as of the current SDK;
470
+ // `StreamOptions.frequencyPenalty` is intentionally dropped for this provider.
471
+
472
+ if (context.tools) {
473
+ params.tools = convertTools(context.tools, supportsStrictMode(model), model);
474
+ if (options?.toolChoice) {
475
+ params.tool_choice = mapOpenAIResponsesToolChoiceForTools(options.toolChoice, context.tools, model);
476
+ }
477
+ // The apply_patch spec §1 marks only `apply_patch` itself as
478
+ // `supports_parallel_tool_calls = false`. OpenAI's Responses API
479
+ // exposes `parallel_tool_calls` as a request-scoped flag, not a
480
+ // per-tool one, so when a custom grammar tool is in the list we
481
+ // disable parallelism for the whole turn. Slightly coarser than
482
+ // the spec requires — but the platform API offers no finer knob.
483
+ if (params.tools.some(t => (t as { type?: string }).type === "custom")) {
484
+ params.parallel_tool_calls = false;
485
+ }
486
+ }
487
+
488
+ applyResponsesReasoningParams(
489
+ params,
490
+ model,
491
+ options,
492
+ messages,
493
+ effort =>
494
+ mapReasoningEffort(
495
+ effort as NonNullable<OpenAIResponsesOptions["reasoning"]>,
496
+ model.compat?.reasoningEffortMap,
497
+ ),
498
+ options?.includeEncryptedReasoning ?? true,
499
+ options?.omitReasoningEffort ?? false,
500
+ );
501
+
502
+ if (options?.extraBody) {
503
+ Object.assign(params, options.extraBody);
504
+ }
505
+
506
+ return { conversationMessages, params };
507
+ }
508
+
509
+ function mapReasoningEffort(
510
+ effort: NonNullable<OpenAIResponsesOptions["reasoning"]>,
511
+ reasoningEffortMap: OpenAICompat["reasoningEffortMap"] | undefined,
512
+ ): string {
513
+ return reasoningEffortMap?.[effort] ?? effort;
514
+ }
515
+
516
+ function isAzureOpenAIBaseUrl(baseUrl: string): boolean {
517
+ return baseUrl.includes(".openai.azure.com") || baseUrl.includes("azure.com/openai");
518
+ }
519
+
520
+ function supportsStrictMode(model: Model<"openai-responses">): boolean {
521
+ if (model.provider === "openai" || model.provider === "azure" || model.provider === "github-copilot") return true;
522
+
523
+ const baseUrl = model.baseUrl.toLowerCase();
524
+ return (
525
+ baseUrl.includes("api.openai.com") ||
526
+ baseUrl.includes(".openai.azure.com") ||
527
+ baseUrl.includes("models.inference.ai.azure.com")
528
+ );
529
+ }
530
+
531
+ export function supportsDeveloperRole(modelOrBaseUrl: Pick<Model, "provider" | "baseUrl"> | string): boolean {
532
+ const baseUrl =
533
+ typeof modelOrBaseUrl === "string" ? modelOrBaseUrl.toLowerCase() : (modelOrBaseUrl.baseUrl ?? "").toLowerCase();
534
+ return (
535
+ baseUrl.includes("api.openai.com") ||
536
+ baseUrl.includes(".openai.azure.com") ||
537
+ baseUrl.includes("azure.com/openai") ||
538
+ baseUrl.includes("models.inference.ai.azure.com") ||
539
+ baseUrl.includes("githubcopilot.com") ||
540
+ baseUrl.includes("copilot-api.")
541
+ );
542
+ }
543
+
544
+ function convertConversationMessages(
545
+ model: Model<"openai-responses">,
546
+ context: Context,
547
+ strictResponsesPairing: boolean,
548
+ providerSessionState: OpenAIResponsesProviderSessionState | undefined,
549
+ options?: OpenAIResponsesOptions,
550
+ ): ResponseInput {
551
+ const filterReasoning = <T extends { type?: string }>(items: T[]): T[] =>
552
+ options?.filterReasoningHistory ? items.filter(i => i?.type !== "reasoning") : items;
553
+ const messages: ResponseInput = [];
554
+ let knownCallIds = new Set<string>();
555
+ const customCallIds = new Set<string>();
556
+ const shouldReplayNativeHistory = canReplayOpenAIResponsesNativeHistory(providerSessionState);
557
+ const transformedMessages = transformMessages(context.messages, model, normalizeResponsesToolCallIdForTransform);
558
+
559
+ let msgIndex = 0;
560
+ for (const msg of transformedMessages) {
561
+ if (msg.role === "user" || msg.role === "developer") {
562
+ const providerPayload = (msg as { providerPayload?: AssistantMessage["providerPayload"] }).providerPayload;
563
+ const historyItems = getOpenAIResponsesHistoryItems(providerPayload, model.provider);
564
+ const shouldReplayPayloadItems =
565
+ shouldReplayNativeHistory ||
566
+ (historyItems?.some(item => {
567
+ if (!item || typeof item !== "object") return false;
568
+ const candidate = item as { type?: unknown };
569
+ return candidate.type === "compaction" || candidate.type === "compaction_summary";
570
+ }) ??
571
+ false);
572
+ if (historyItems && shouldReplayPayloadItems) {
573
+ messages.push(...sanitizeOpenAIResponsesHistoryItemsForReplay(filterReasoning(historyItems)));
574
+ knownCallIds = collectKnownCallIds(messages);
575
+ for (const id of collectCustomCallIds(messages)) customCallIds.add(id);
576
+ msgIndex++;
577
+ continue;
578
+ }
579
+ const content = convertResponsesInputContent(msg.content, model.input.includes("image"));
580
+ if (!content) continue;
581
+ messages.push({ role: "user", content });
582
+ } else if (msg.role === "assistant") {
583
+ const assistantMsg = msg as AssistantMessage;
584
+ const providerPayload = shouldReplayNativeHistory
585
+ ? getOpenAIResponsesHistoryPayload(assistantMsg.providerPayload, model.provider, assistantMsg.provider)
586
+ : undefined;
587
+ const historyItems = providerPayload?.items;
588
+ if (historyItems) {
589
+ const sanitizedHistoryItems = sanitizeOpenAIResponsesHistoryItemsForReplay(filterReasoning(historyItems));
590
+ if (providerPayload?.dt) {
591
+ messages.push(...sanitizedHistoryItems);
592
+ } else {
593
+ messages.splice(0, messages.length, ...sanitizedHistoryItems);
594
+ }
595
+ knownCallIds = collectKnownCallIds(messages);
596
+ for (const id of collectCustomCallIds(messages)) customCallIds.add(id);
597
+ msgIndex++;
598
+ continue;
599
+ }
600
+
601
+ const outputItems = convertResponsesAssistantMessage(
602
+ assistantMsg,
603
+ model,
604
+ msgIndex,
605
+ knownCallIds,
606
+ shouldReplayNativeHistory,
607
+ customCallIds,
608
+ );
609
+ if (outputItems.length === 0) continue;
610
+ messages.push(...outputItems);
611
+ } else if (msg.role === "toolResult") {
612
+ appendResponsesToolResultMessages(messages, msg, model, strictResponsesPairing, knownCallIds, customCallIds);
613
+ }
614
+ msgIndex++;
615
+ }
616
+
617
+ return repairOrphanResponsesToolOutputs(messages);
618
+ }
619
+
620
+ /**
621
+ * Whether this model should get the OpenAI custom-tool grammar variant
622
+ * for `apply_patch`. The generated model catalog sets
623
+ * `model.applyPatchToolType` for first-party GPT-5 Responses models; this
624
+ * runtime path only consumes that metadata.
625
+ * @internal Exported for tests.
626
+ */
627
+ export function supportsFreeformApplyPatch(model: Model<"openai-responses">): boolean {
628
+ return model.applyPatchToolType === "freeform";
629
+ }
630
+
631
+ /** @internal Exported for tests. */
632
+ export function mapOpenAIResponsesToolChoiceForTools(
633
+ choice: ToolChoice | undefined,
634
+ tools: Tool[],
635
+ model: Model<"openai-responses">,
636
+ ): OpenAIResponsesToolChoice {
637
+ const mapped = mapToOpenAIResponsesToolChoice(choice);
638
+ if (!mapped || typeof mapped === "string" || mapped.type !== "function" || !supportsFreeformApplyPatch(model)) {
639
+ return mapped;
640
+ }
641
+
642
+ const customTool = tools.find(
643
+ tool => tool.customFormat && (tool.name === mapped.name || tool.customWireName === mapped.name),
644
+ );
645
+ return customTool ? { type: "custom", name: customTool.customWireName ?? customTool.name } : mapped;
646
+ }
647
+
648
+ /** @internal Exported for tests. */
649
+ export function convertTools(tools: Tool[], strictMode: boolean, model: Model<"openai-responses">): OpenAITool[] {
650
+ const allowFreeform = supportsFreeformApplyPatch(model);
651
+ return tools.map(tool => {
652
+ if (allowFreeform && tool.customFormat) {
653
+ return {
654
+ type: "custom",
655
+ // Tool advertises its wire-level name (e.g. `apply_patch`) — the
656
+ // agent-loop dispatcher will match incoming calls by either the
657
+ // internal `name` or `customWireName`.
658
+ name: tool.customWireName ?? tool.name,
659
+ description: tool.description || "",
660
+ format: {
661
+ type: "grammar",
662
+ syntax: tool.customFormat.syntax,
663
+ definition: compactGrammarDefinition(tool.customFormat.syntax, tool.customFormat.definition),
664
+ },
665
+ } as unknown as OpenAITool;
666
+ }
667
+ const strict = !NO_STRICT && strictMode && tool.strict !== false;
668
+ const baseParameters = toolWireSchema(tool);
669
+ const responseParameters = sanitizeSchemaForOpenAIResponses(baseParameters);
670
+ const { schema: parameters, strict: effectiveStrict } = adaptSchemaForStrict(responseParameters, strict);
671
+ return {
672
+ type: "function",
673
+ name: tool.name,
674
+ description: tool.description || "",
675
+ parameters,
676
+ ...(effectiveStrict && { strict: true }),
677
+ } as OpenAITool;
678
+ });
679
+ }