@aryee337/aery-ai 0.2.27 → 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,261 @@
1
+ import * as z from "zod/v4";
2
+ import { getAntigravityUserAgent } from "../../providers/google-gemini-headers";
3
+ import type { Model } from "../../types";
4
+ import { toPositiveNumber } from "../../utils";
5
+
6
+ const DEFAULT_ANTIGRAVITY_DISCOVERY_ENDPOINTS = [
7
+ "https://daily-cloudcode-pa.googleapis.com",
8
+ "https://daily-cloudcode-pa.sandbox.googleapis.com",
9
+ ] as const;
10
+ const FETCH_AVAILABLE_MODELS_PATH = "/v1internal:fetchAvailableModels";
11
+
12
+ const DEFAULT_CONTEXT_WINDOW = 200_000;
13
+ const DEFAULT_MAX_TOKENS = 64_000;
14
+ const ANTIGRAVITY_DISCOVERY_DENYLIST = new Set([
15
+ "chat_20706",
16
+ "chat_23310",
17
+ "gemini-2.5-flash-thinking",
18
+ "gemini-3-pro-low",
19
+ "gemini-2.5-pro",
20
+ ]);
21
+
22
+ /**
23
+ * Raw model metadata returned by Antigravity's `fetchAvailableModels` endpoint.
24
+ */
25
+ export interface AntigravityDiscoveryApiModel {
26
+ displayName?: string;
27
+ supportsImages?: boolean;
28
+ supportsThinking?: boolean;
29
+ thinkingBudget?: number;
30
+ recommended?: boolean;
31
+ maxTokens?: number;
32
+ maxOutputTokens?: number;
33
+ model?: string;
34
+ apiProvider?: string;
35
+ modelProvider?: string;
36
+ isInternal?: boolean;
37
+ supportsVideo?: boolean;
38
+ }
39
+
40
+ /**
41
+ * Grouping metadata used by Antigravity to surface recommended model ids.
42
+ */
43
+ export interface AntigravityDiscoveryAgentModelGroup {
44
+ modelIds?: string[];
45
+ }
46
+
47
+ /**
48
+ * Sort/group metadata used by Antigravity to surface recommended model ids.
49
+ */
50
+ export interface AntigravityDiscoveryAgentModelSort {
51
+ groups?: AntigravityDiscoveryAgentModelGroup[];
52
+ }
53
+
54
+ /**
55
+ * Response payload returned by Antigravity's `fetchAvailableModels` endpoint.
56
+ */
57
+ export interface AntigravityDiscoveryApiResponse {
58
+ models?: Record<string, AntigravityDiscoveryApiModel>;
59
+ agentModelSorts?: AntigravityDiscoveryAgentModelSort[];
60
+ }
61
+ const AntigravityDiscoveryApiModelSchema: z.ZodType<AntigravityDiscoveryApiModel> = z
62
+ .object({
63
+ displayName: z.preprocess(value => (typeof value === "string" ? value : undefined), z.string().optional()),
64
+ supportsImages: z.preprocess(value => (typeof value === "boolean" ? value : undefined), z.boolean().optional()),
65
+ supportsThinking: z.preprocess(value => (typeof value === "boolean" ? value : undefined), z.boolean().optional()),
66
+ thinkingBudget: z.preprocess(
67
+ value => (typeof value === "number" && Number.isFinite(value) ? value : undefined),
68
+ z.number().optional(),
69
+ ),
70
+ recommended: z.preprocess(value => (typeof value === "boolean" ? value : undefined), z.boolean().optional()),
71
+ maxTokens: z.preprocess(
72
+ value => (typeof value === "number" && Number.isFinite(value) ? value : undefined),
73
+ z.number().optional(),
74
+ ),
75
+ maxOutputTokens: z.preprocess(
76
+ value => (typeof value === "number" && Number.isFinite(value) ? value : undefined),
77
+ z.number().optional(),
78
+ ),
79
+ model: z.preprocess(value => (typeof value === "string" ? value : undefined), z.string().optional()),
80
+ apiProvider: z.preprocess(value => (typeof value === "string" ? value : undefined), z.string().optional()),
81
+ modelProvider: z.preprocess(value => (typeof value === "string" ? value : undefined), z.string().optional()),
82
+ isInternal: z.preprocess(value => (typeof value === "boolean" ? value : undefined), z.boolean().optional()),
83
+ supportsVideo: z.preprocess(value => (typeof value === "boolean" ? value : undefined), z.boolean().optional()),
84
+ })
85
+ .loose();
86
+ const AntigravityDiscoveryAgentModelGroupSchema: z.ZodType<AntigravityDiscoveryAgentModelGroup> = z
87
+ .object({
88
+ modelIds: z.preprocess(
89
+ value =>
90
+ Array.isArray(value)
91
+ ? value.filter((modelId): modelId is string => typeof modelId === "string")
92
+ : undefined,
93
+ z.array(z.string()).optional(),
94
+ ),
95
+ })
96
+ .loose();
97
+ const AntigravityDiscoveryAgentModelSortSchema: z.ZodType<AntigravityDiscoveryAgentModelSort> = z
98
+ .object({
99
+ groups: z.preprocess(
100
+ value => (Array.isArray(value) ? value : undefined),
101
+ z
102
+ .array(z.unknown())
103
+ .transform(groups =>
104
+ groups.flatMap(group => {
105
+ const parsedGroup = AntigravityDiscoveryAgentModelGroupSchema.safeParse(group);
106
+ return parsedGroup.success ? [parsedGroup.data] : [];
107
+ }),
108
+ )
109
+ .optional(),
110
+ ),
111
+ })
112
+ .loose();
113
+ const AntigravityDiscoveryApiResponseSchema: z.ZodType<AntigravityDiscoveryApiResponse> = z
114
+ .object({
115
+ models: z.preprocess(
116
+ value => (typeof value === "object" && value !== null ? value : undefined),
117
+ z
118
+ .record(z.string(), z.unknown())
119
+ .transform(models => {
120
+ const normalized: Record<string, AntigravityDiscoveryApiModel> = {};
121
+ for (const [modelId, modelValue] of Object.entries(models)) {
122
+ if (typeof modelValue !== "object" || modelValue === null) {
123
+ continue;
124
+ }
125
+ const parsedModel = AntigravityDiscoveryApiModelSchema.safeParse(modelValue);
126
+ if (parsedModel.success) {
127
+ normalized[modelId] = parsedModel.data;
128
+ }
129
+ }
130
+ return normalized;
131
+ })
132
+ .optional(),
133
+ ),
134
+ agentModelSorts: z.preprocess(
135
+ value => (Array.isArray(value) ? value : undefined),
136
+ z
137
+ .array(z.unknown())
138
+ .transform(sorts =>
139
+ sorts.flatMap(sort => {
140
+ const parsedSort = AntigravityDiscoveryAgentModelSortSchema.safeParse(sort);
141
+ return parsedSort.success ? [parsedSort.data] : [];
142
+ }),
143
+ )
144
+ .optional(),
145
+ ),
146
+ })
147
+ .loose();
148
+
149
+ /**
150
+ * Options for fetching Antigravity discovery models.
151
+ */
152
+ export interface FetchAntigravityDiscoveryModelsOptions {
153
+ /** OAuth access token used as `Authorization: Bearer <token>`. */
154
+ token: string;
155
+ /** Optional endpoint override. Defaults to Antigravity fallback endpoints. */
156
+ endpoint?: string;
157
+ /** Deprecated and ignored for antigravity discovery parity. */
158
+ project?: string;
159
+ /** Optional user agent override. */
160
+ userAgent?: string;
161
+ /** Optional abort signal for request cancellation. */
162
+ signal?: AbortSignal;
163
+ /** Optional fetch implementation override for tests. */
164
+ fetcher?: typeof fetch;
165
+ }
166
+
167
+ /**
168
+ * Fetches discoverable Antigravity models and normalizes them into canonical model entries.
169
+ *
170
+ * Returns `null` on network/payload/auth failures.
171
+ * Returns `[]` only when the endpoint responds successfully with no usable models.
172
+ */
173
+ export async function fetchAntigravityDiscoveryModels(
174
+ options: FetchAntigravityDiscoveryModelsOptions,
175
+ ): Promise<Model<"google-gemini-cli">[] | null> {
176
+ const fetcher = options.fetcher ?? fetch;
177
+ const endpoints = options.endpoint
178
+ ? [trimTrailingSlashes(options.endpoint)]
179
+ : DEFAULT_ANTIGRAVITY_DISCOVERY_ENDPOINTS.map(trimTrailingSlashes);
180
+
181
+ for (const endpoint of endpoints) {
182
+ let response: Response;
183
+ try {
184
+ response = await fetcher(`${endpoint}${FETCH_AVAILABLE_MODELS_PATH}`, {
185
+ method: "POST",
186
+ headers: {
187
+ Authorization: `Bearer ${options.token}`,
188
+ "Content-Type": "application/json",
189
+ "User-Agent": options.userAgent ?? getAntigravityUserAgent(),
190
+ },
191
+ body: JSON.stringify({}),
192
+ signal: options.signal,
193
+ });
194
+ } catch {
195
+ continue;
196
+ }
197
+
198
+ if (!response.ok) {
199
+ continue;
200
+ }
201
+
202
+ let payload: unknown;
203
+ try {
204
+ payload = await response.json();
205
+ } catch {
206
+ continue;
207
+ }
208
+
209
+ const parsed = parseAntigravityDiscoveryResponse(payload);
210
+ if (!parsed) {
211
+ continue;
212
+ }
213
+
214
+ const models: Model<"google-gemini-cli">[] = [];
215
+
216
+ for (const [modelId, model] of Object.entries(parsed.models ?? {})) {
217
+ if (ANTIGRAVITY_DISCOVERY_DENYLIST.has(modelId)) {
218
+ continue;
219
+ }
220
+ if (model.isInternal === true) {
221
+ continue;
222
+ }
223
+
224
+ const supportsImages = model.supportsImages === true;
225
+ models.push({
226
+ id: modelId,
227
+ name: model.displayName ? `${model.displayName} (Antigravity)` : modelId,
228
+ api: "google-gemini-cli",
229
+ provider: "google-antigravity",
230
+ baseUrl: endpoint,
231
+ reasoning: model.supportsThinking === true,
232
+ input: supportsImages ? ["text", "image"] : ["text"],
233
+ cost: {
234
+ input: 0,
235
+ output: 0,
236
+ cacheRead: 0,
237
+ cacheWrite: 0,
238
+ },
239
+ contextWindow: toPositiveNumber(model.maxTokens, DEFAULT_CONTEXT_WINDOW),
240
+ maxTokens: toPositiveNumber(model.maxOutputTokens, DEFAULT_MAX_TOKENS),
241
+ });
242
+ }
243
+
244
+ models.sort((a, b) => a.name.localeCompare(b.name) || a.id.localeCompare(b.id));
245
+ return models;
246
+ }
247
+
248
+ return null;
249
+ }
250
+
251
+ function parseAntigravityDiscoveryResponse(value: unknown): AntigravityDiscoveryApiResponse | null {
252
+ const parsed = AntigravityDiscoveryApiResponseSchema.safeParse(value);
253
+ if (!parsed.success) {
254
+ return null;
255
+ }
256
+ return parsed.data;
257
+ }
258
+
259
+ function trimTrailingSlashes(value: string): string {
260
+ return value.replace(/\/+$/, "");
261
+ }
@@ -0,0 +1,371 @@
1
+ import * as z from "zod/v4";
2
+ import { CODEX_BASE_URL, OPENAI_HEADER_VALUES, OPENAI_HEADERS } from "../../providers/openai-codex/constants";
3
+ import type { Model } from "../../types";
4
+ import { isRecord } from "../../utils";
5
+
6
+ const DEFAULT_MODEL_LIST_PATHS = ["/codex/models", "/models"] as const;
7
+ const DEFAULT_CONTEXT_WINDOW = 272_000;
8
+ const DEFAULT_MAX_TOKENS = 128_000;
9
+ const DEFAULT_CODEX_CLIENT_VERSION = "0.99.0";
10
+ const NPM_CODEX_LATEST_URL = "https://registry.npmjs.org/@openai%2Fcodex/latest";
11
+
12
+ const codexReasoningPresetSchema = z
13
+ .object({
14
+ effort: z.unknown().optional(),
15
+ })
16
+ .loose();
17
+
18
+ const codexModelEntrySchema = z
19
+ .object({
20
+ slug: z.unknown().optional(),
21
+ id: z.unknown().optional(),
22
+ display_name: z.unknown().optional(),
23
+ context_window: z.unknown().optional(),
24
+ default_reasoning_level: z.unknown().optional(),
25
+ supported_reasoning_levels: z.unknown().optional(),
26
+ input_modalities: z.unknown().optional(),
27
+ supported_in_api: z.unknown().optional(),
28
+ priority: z.unknown().optional(),
29
+ prefer_websockets: z.unknown().optional(),
30
+ })
31
+ .loose();
32
+
33
+ const codexModelsResponseSchema = z
34
+ .object({
35
+ models: z.array(z.unknown()).optional(),
36
+ data: z.array(z.unknown()).optional(),
37
+ })
38
+ .loose();
39
+
40
+ type CodexModelEntry = z.infer<typeof codexModelEntrySchema>;
41
+
42
+ interface NormalizedCodexModel {
43
+ model: Model<"openai-codex-responses">;
44
+ priority: number;
45
+ }
46
+
47
+ /**
48
+ * Fetch options for OpenAI Codex model discovery.
49
+ */
50
+ export interface CodexModelDiscoveryOptions {
51
+ /** OAuth access token used for `Authorization: Bearer ...`. */
52
+ accessToken: string;
53
+ /** ChatGPT account id value used for `chatgpt-account-id` header. */
54
+ accountId?: string;
55
+ /** Base URL for Codex backend. Defaults to `https://chatgpt.com/backend-api`. */
56
+ baseUrl?: string;
57
+ /** Optional client version attached as `client_version` query parameter. */
58
+ clientVersion?: string;
59
+ /** Optional endpoint path candidates. Defaults to `/codex/models`, then `/models`. */
60
+ paths?: readonly string[];
61
+ /** Additional headers merged on top of required Codex headers. */
62
+ headers?: Record<string, string>;
63
+ /** Abort signal for network request cancellation. */
64
+ signal?: AbortSignal;
65
+ /** Optional fetch implementation override for tests. */
66
+ fetchFn?: typeof fetch;
67
+ /** Optional registry fetch implementation override for client version lookup. */
68
+ registryFetchFn?: typeof fetch;
69
+ }
70
+
71
+ /**
72
+ * Normalized Codex discovery response.
73
+ */
74
+ export interface CodexModelDiscoveryResult {
75
+ models: Model<"openai-codex-responses">[];
76
+ etag?: string;
77
+ }
78
+
79
+ /**
80
+ * Fetches model metadata from Codex backend and normalizes it for aery model management.
81
+ *
82
+ * Returns `null` when no supported model-list route can be fetched/parsed.
83
+ * Returns `{ models: [] }` when a route succeeds but yields no usable models.
84
+ */
85
+ export async function fetchCodexModels(options: CodexModelDiscoveryOptions): Promise<CodexModelDiscoveryResult | null> {
86
+ const fetchFn = options.fetchFn ?? fetch;
87
+ const baseUrl = normalizeBaseUrl(options.baseUrl);
88
+ const paths = normalizePaths(options.paths);
89
+ const headers = buildCodexHeaders(options);
90
+ const clientVersion = await resolveCodexClientVersion(
91
+ options.clientVersion,
92
+ options.registryFetchFn ?? fetchFn,
93
+ options.signal,
94
+ );
95
+
96
+ let sawSuccessfulResponse = false;
97
+ for (const path of paths) {
98
+ const requestUrl = buildModelsUrl(baseUrl, path, clientVersion);
99
+ let response: Response;
100
+ try {
101
+ response = await fetchFn(requestUrl, {
102
+ method: "GET",
103
+ headers,
104
+ signal: options.signal,
105
+ });
106
+ } catch {
107
+ continue;
108
+ }
109
+
110
+ if (!response.ok) {
111
+ continue;
112
+ }
113
+
114
+ let payload: unknown;
115
+ try {
116
+ payload = await response.json();
117
+ } catch {
118
+ continue;
119
+ }
120
+
121
+ const models = normalizeCodexModels(payload, baseUrl);
122
+ if (models === null) {
123
+ continue;
124
+ }
125
+ sawSuccessfulResponse = true;
126
+ const etag = getResponseEtag(response.headers);
127
+ return etag ? { models, etag } : { models };
128
+ }
129
+ return sawSuccessfulResponse ? { models: [] } : null;
130
+ }
131
+
132
+ function normalizeBaseUrl(baseUrl: string | undefined): string {
133
+ const raw = (baseUrl ?? CODEX_BASE_URL).trim();
134
+ if (!raw) {
135
+ return CODEX_BASE_URL;
136
+ }
137
+ return raw.replace(/\/+$/, "");
138
+ }
139
+
140
+ function normalizePaths(paths: readonly string[] | undefined): string[] {
141
+ if (!paths || paths.length === 0) {
142
+ return [...DEFAULT_MODEL_LIST_PATHS];
143
+ }
144
+ const normalized = paths
145
+ .map(path => path.trim())
146
+ .filter(path => path.length > 0)
147
+ .map(path => (path.startsWith("/") ? path : `/${path}`));
148
+ return normalized.length > 0 ? normalized : [...DEFAULT_MODEL_LIST_PATHS];
149
+ }
150
+
151
+ function buildModelsUrl(baseUrl: string, path: string, clientVersion: string | undefined): string {
152
+ const url = new URL(`${baseUrl}${path}`);
153
+ if (clientVersion && clientVersion.trim().length > 0) {
154
+ url.searchParams.set("client_version", clientVersion.trim());
155
+ }
156
+ return url.toString();
157
+ }
158
+
159
+ function buildCodexHeaders(options: CodexModelDiscoveryOptions): Headers {
160
+ const headers = new Headers(options.headers);
161
+ headers.set("Authorization", `Bearer ${options.accessToken}`);
162
+ if (options.accountId && options.accountId.trim().length > 0) {
163
+ headers.set(OPENAI_HEADERS.ACCOUNT_ID, options.accountId);
164
+ }
165
+ headers.set(OPENAI_HEADERS.BETA, OPENAI_HEADER_VALUES.BETA_RESPONSES);
166
+ headers.set(OPENAI_HEADERS.ORIGINATOR, OPENAI_HEADER_VALUES.ORIGINATOR_CODEX);
167
+ headers.set("accept", "application/json");
168
+ return headers;
169
+ }
170
+
171
+ async function resolveCodexClientVersion(
172
+ clientVersion: string | undefined,
173
+ fetchFn: typeof fetch,
174
+ signal: AbortSignal | undefined,
175
+ ): Promise<string> {
176
+ const normalizedClientVersion = normalizeClientVersion(clientVersion);
177
+ if (normalizedClientVersion) {
178
+ return normalizedClientVersion;
179
+ }
180
+ try {
181
+ const response = await fetchFn(NPM_CODEX_LATEST_URL, {
182
+ method: "GET",
183
+ headers: { Accept: "application/json" },
184
+ signal,
185
+ });
186
+ if (!response.ok) {
187
+ return DEFAULT_CODEX_CLIENT_VERSION;
188
+ }
189
+ const payload: unknown = await response.json();
190
+ if (!isRecord(payload)) {
191
+ return DEFAULT_CODEX_CLIENT_VERSION;
192
+ }
193
+ const npmVersion = normalizeClientVersion(payload.version);
194
+ return npmVersion ?? DEFAULT_CODEX_CLIENT_VERSION;
195
+ } catch (error) {
196
+ if (isAbortError(error)) {
197
+ throw error;
198
+ }
199
+ return DEFAULT_CODEX_CLIENT_VERSION;
200
+ }
201
+ }
202
+
203
+ function normalizeClientVersion(value: unknown): string | undefined {
204
+ if (typeof value !== "string") {
205
+ return undefined;
206
+ }
207
+ const trimmed = value.trim();
208
+ if (!/^\d+\.\d+\.\d+$/.test(trimmed)) {
209
+ return undefined;
210
+ }
211
+ return trimmed;
212
+ }
213
+
214
+ function isAbortError(error: unknown): error is Error {
215
+ return error instanceof Error && error.name === "AbortError";
216
+ }
217
+
218
+ function normalizeCodexModels(payload: unknown, baseUrl: string): Model<"openai-codex-responses">[] | null {
219
+ const parsedResponse = codexModelsResponseSchema.safeParse(payload);
220
+ if (!parsedResponse.success) {
221
+ return null;
222
+ }
223
+
224
+ const entries = parsedResponse.data.models ?? parsedResponse.data.data ?? [];
225
+ const normalized: NormalizedCodexModel[] = [];
226
+ for (const entry of entries) {
227
+ const model = normalizeCodexModelEntry(entry, baseUrl);
228
+ if (model) {
229
+ normalized.push(model);
230
+ }
231
+ }
232
+
233
+ normalized.sort((left, right) => {
234
+ if (left.priority !== right.priority) {
235
+ return left.priority - right.priority;
236
+ }
237
+ return left.model.id.localeCompare(right.model.id);
238
+ });
239
+
240
+ return normalized.map(item => item.model);
241
+ }
242
+
243
+ function normalizeCodexModelEntry(entry: unknown, baseUrl: string): NormalizedCodexModel | null {
244
+ const parsedEntry = codexModelEntrySchema.safeParse(entry);
245
+ if (!parsedEntry.success) {
246
+ return null;
247
+ }
248
+
249
+ const payload: CodexModelEntry = parsedEntry.data;
250
+ const slug = toNonEmptyString(payload.slug) ?? toNonEmptyString(payload.id);
251
+ if (!slug) {
252
+ return null;
253
+ }
254
+
255
+ const supportedInApi = toBoolean(payload.supported_in_api);
256
+ if (supportedInApi === false) {
257
+ return null;
258
+ }
259
+
260
+ const name = toNonEmptyString(payload.display_name) ?? slug;
261
+ const contextWindow = toPositiveInt(payload.context_window) ?? DEFAULT_CONTEXT_WINDOW;
262
+ const maxTokens = Math.min(DEFAULT_MAX_TOKENS, contextWindow);
263
+ const reasoning = supportsReasoning(payload.default_reasoning_level, payload.supported_reasoning_levels);
264
+ const input = normalizeInputModalities(payload.input_modalities);
265
+ const preferWebsockets = toBoolean(payload.prefer_websockets) === true;
266
+ const priority = toFiniteNumber(payload.priority) ?? Number.MAX_SAFE_INTEGER;
267
+
268
+ return {
269
+ priority,
270
+ model: {
271
+ id: slug,
272
+ name,
273
+ api: "openai-codex-responses",
274
+ provider: "openai-codex",
275
+ baseUrl,
276
+ reasoning,
277
+ input,
278
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
279
+ contextWindow,
280
+ maxTokens,
281
+ ...(preferWebsockets ? { preferWebsockets: true } : {}),
282
+ ...(priority !== Number.MAX_SAFE_INTEGER ? { priority } : {}),
283
+ },
284
+ };
285
+ }
286
+
287
+ function supportsReasoning(defaultReasoningLevel: unknown, supportedReasoningLevels: unknown): boolean {
288
+ const defaultLevel = toNonEmptyString(defaultReasoningLevel)?.toLowerCase();
289
+ if (defaultLevel && defaultLevel !== "none") {
290
+ return true;
291
+ }
292
+
293
+ if (!Array.isArray(supportedReasoningLevels)) {
294
+ return false;
295
+ }
296
+
297
+ for (const level of supportedReasoningLevels) {
298
+ const parsedLevel = codexReasoningPresetSchema.safeParse(level);
299
+ if (!parsedLevel.success) {
300
+ continue;
301
+ }
302
+ const effort = toNonEmptyString(parsedLevel.data.effort)?.toLowerCase();
303
+ if (effort && effort !== "none") {
304
+ return true;
305
+ }
306
+ }
307
+
308
+ return false;
309
+ }
310
+
311
+ function normalizeInputModalities(inputModalities: unknown): ("text" | "image")[] {
312
+ if (!Array.isArray(inputModalities)) {
313
+ return ["text", "image"];
314
+ }
315
+
316
+ const set = new Set<"text" | "image">();
317
+ for (const modality of inputModalities) {
318
+ const normalized = toNonEmptyString(modality)?.toLowerCase();
319
+ if (normalized === "text" || normalized === "image") {
320
+ set.add(normalized);
321
+ }
322
+ }
323
+
324
+ if (set.size === 0) {
325
+ return ["text", "image"];
326
+ }
327
+
328
+ const canonical: ("text" | "image")[] = ["text", "image"];
329
+ return canonical.filter(modality => set.has(modality));
330
+ }
331
+
332
+ function getResponseEtag(headers: Headers): string | undefined {
333
+ const etag = headers.get("etag");
334
+ if (!etag) {
335
+ return undefined;
336
+ }
337
+ const trimmed = etag.trim();
338
+ return trimmed.length > 0 ? trimmed : undefined;
339
+ }
340
+
341
+ function toNonEmptyString(value: unknown): string | null {
342
+ if (typeof value !== "string") {
343
+ return null;
344
+ }
345
+ const trimmed = value.trim();
346
+ return trimmed.length > 0 ? trimmed : null;
347
+ }
348
+
349
+ function toPositiveInt(value: unknown): number | null {
350
+ if (typeof value !== "number" || !Number.isFinite(value)) {
351
+ return null;
352
+ }
353
+ if (value <= 0) {
354
+ return null;
355
+ }
356
+ return Math.trunc(value);
357
+ }
358
+
359
+ function toFiniteNumber(value: unknown): number | null {
360
+ if (typeof value !== "number" || !Number.isFinite(value)) {
361
+ return null;
362
+ }
363
+ return value;
364
+ }
365
+
366
+ function toBoolean(value: unknown): boolean | null {
367
+ if (typeof value !== "boolean") {
368
+ return null;
369
+ }
370
+ return value;
371
+ }