@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,809 @@
1
+ /**
2
+ * Google Gemini CLI / Antigravity provider.
3
+ * Shared implementation for both google-gemini-cli and google-antigravity providers.
4
+ * Uses the Cloud Code Assist API endpoint to access Gemini and Claude models.
5
+ */
6
+ import { createHash, randomBytes, randomUUID } from "node:crypto";
7
+ import { scheduler } from "node:timers/promises";
8
+ import { extractHttpStatusFromError, fetchWithRetry, readSseJson } from "@aryee337/aery-utils";
9
+ import { calculateCost } from "../models";
10
+ import type {
11
+ Api,
12
+ AssistantMessage,
13
+ Context,
14
+ Model,
15
+ StreamFunction,
16
+ StreamOptions,
17
+ TextContent,
18
+ ThinkingContent,
19
+ ToolCall,
20
+ } from "../types";
21
+ import { normalizeSystemPrompts } from "../utils";
22
+ import { AssistantMessageEventStream } from "../utils/event-stream";
23
+ import { appendRawHttpRequestDumpFor400, type RawHttpRequestDump, withHttpStatus } from "../utils/http-inspector";
24
+ // Refresh is the sole responsibility of AuthStorage (broker-aware, single-flighted);
25
+ // the stream provider trusts the access token threaded through `options.apiKey`.
26
+ import { normalizeSchemaForCCA } from "../utils/schema";
27
+ import { ANTIGRAVITY_SYSTEM_INSTRUCTION, getAntigravityUserAgent, getGeminiCliHeaders } from "./google-gemini-headers";
28
+ import type { Content, FunctionCallingConfigMode, ThinkingConfig } from "./google-shared";
29
+ import {
30
+ convertMessages,
31
+ convertTools,
32
+ type GoogleThinkingLevel,
33
+ isThinkingPart,
34
+ mapStopReasonString,
35
+ mapToolChoice,
36
+ nextToolCallId,
37
+ pushBlockEndEvent,
38
+ pushToolCallEvents,
39
+ retainThoughtSignature,
40
+ startTextOrThinkingBlock,
41
+ } from "./google-shared";
42
+
43
+ /**
44
+ * Thinking level for Gemini 3 models. Re-exported from `google-shared` so existing
45
+ * `import { GoogleThinkingLevel } from "./google-gemini-cli"` callers keep working.
46
+ */
47
+ export type { GoogleThinkingLevel };
48
+
49
+ export interface GoogleGeminiCliOptions extends StreamOptions {
50
+ /**
51
+ * Tool selection mode. String forms map directly to Gemini
52
+ * `FunctionCallingConfigMode`. The object form forces a single named tool —
53
+ * `mode: "ANY"` is wire-required when `allowedFunctionNames` is set.
54
+ */
55
+ toolChoice?: "auto" | "none" | "any" | { mode: "ANY"; allowedFunctionNames: [string, ...string[]] };
56
+ /**
57
+ * Thinking/reasoning configuration.
58
+ * - Gemini 2.x models: use `budgetTokens` to set the thinking budget
59
+ * - Gemini 3 models (gemini-3-pro-*, gemini-3-flash-*): use `level` instead
60
+ *
61
+ * When using `streamSimple`, this is handled automatically based on the model.
62
+ */
63
+ thinking?: {
64
+ enabled: boolean;
65
+ /** Thinking budget in tokens. Use for Gemini 2.x models. */
66
+ budgetTokens?: number;
67
+ /** Thinking level. Use for Gemini 3 models (LOW/HIGH for Pro, MINIMAL/LOW/MEDIUM/HIGH for Flash). */
68
+ level?: GoogleThinkingLevel;
69
+ };
70
+ projectId?: string;
71
+ }
72
+
73
+ const DEFAULT_ENDPOINT = "https://cloudcode-pa.googleapis.com";
74
+ const ANTIGRAVITY_DAILY_ENDPOINT = "https://daily-cloudcode-pa.googleapis.com";
75
+ const ANTIGRAVITY_SANDBOX_ENDPOINT = "https://daily-cloudcode-pa.sandbox.googleapis.com";
76
+ const ANTIGRAVITY_ENDPOINT_FALLBACKS = [ANTIGRAVITY_DAILY_ENDPOINT, ANTIGRAVITY_SANDBOX_ENDPOINT] as const;
77
+
78
+ export {
79
+ ANTIGRAVITY_SYSTEM_INSTRUCTION,
80
+ getAntigravityUserAgent,
81
+ getGeminiCliHeaders,
82
+ getGeminiCliUserAgent,
83
+ } from "./google-gemini-headers";
84
+
85
+ // Retry configuration
86
+ const MAX_RETRIES = 3;
87
+ const BASE_DELAY_MS = 1000;
88
+ const MAX_EMPTY_STREAM_RETRIES = 2;
89
+ const EMPTY_STREAM_BASE_DELAY_MS = 500;
90
+ const RATE_LIMIT_BUDGET_MS = 5 * 60 * 1000;
91
+ const CLAUDE_THINKING_BETA_HEADER = "interleaved-thinking-2025-05-14";
92
+ const GOOGLE_GEMINI_REFRESH_SKEW_MS = 60_000;
93
+ const ANTIGRAVITY_REFRESH_SKEW_MS = 60_000;
94
+
95
+ function isClaudeModel(modelId: string): boolean {
96
+ return modelId.toLowerCase().includes("claude");
97
+ }
98
+
99
+ function needsClaudeThinkingBetaHeader(model: Model<"google-gemini-cli">): boolean {
100
+ return model.provider === "google-antigravity" && model.id.startsWith("claude-") && model.reasoning;
101
+ }
102
+
103
+ function shouldInjectAntigravitySystemInstruction(modelId: string): boolean {
104
+ const normalized = modelId.toLowerCase();
105
+ return normalized.includes("claude") || normalized.includes("gemini-3");
106
+ }
107
+
108
+ /**
109
+ * Extract a clean, user-friendly error message from Google API error response.
110
+ * Parses JSON error responses and returns just the message field.
111
+ */
112
+ function extractErrorMessage(errorText: string): string {
113
+ try {
114
+ const parsed = JSON.parse(errorText) as { error?: { message?: string } };
115
+ if (parsed.error?.message) {
116
+ return parsed.error.message;
117
+ }
118
+ } catch {
119
+ // Not JSON, return as-is
120
+ }
121
+ return errorText;
122
+ }
123
+
124
+ interface GeminiCliApiKeyPayload {
125
+ token?: unknown;
126
+ projectId?: unknown;
127
+ project_id?: unknown;
128
+ refreshToken?: unknown;
129
+ expiresAt?: unknown;
130
+ refresh?: unknown;
131
+ expires?: unknown;
132
+ }
133
+ interface ParsedGeminiCliCredentials {
134
+ accessToken: string;
135
+ projectId: string;
136
+ refreshToken?: string;
137
+ expiresAt?: number;
138
+ }
139
+
140
+ function normalizeExpiryMs(value: unknown): number | undefined {
141
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
142
+ return undefined;
143
+ }
144
+ return value < 10_000_000_000 ? value * 1000 : value;
145
+ }
146
+
147
+ export function parseGeminiCliCredentials(apiKeyRaw: string): ParsedGeminiCliCredentials {
148
+ const invalidCredentialsMessage = "Invalid Google Cloud Code Assist credentials. Use /login to re-authenticate.";
149
+ const missingCredentialsMessage =
150
+ "Missing token or projectId in Google Cloud credentials. Use /login to re-authenticate.";
151
+
152
+ let parsed: GeminiCliApiKeyPayload;
153
+ try {
154
+ parsed = JSON.parse(apiKeyRaw) as GeminiCliApiKeyPayload;
155
+ } catch {
156
+ throw new Error(invalidCredentialsMessage);
157
+ }
158
+
159
+ const projectId =
160
+ typeof parsed.projectId === "string"
161
+ ? parsed.projectId
162
+ : typeof parsed.project_id === "string"
163
+ ? parsed.project_id
164
+ : undefined;
165
+
166
+ if (typeof parsed.token !== "string" || typeof projectId !== "string") {
167
+ throw new Error(missingCredentialsMessage);
168
+ }
169
+
170
+ const refreshToken =
171
+ typeof parsed.refreshToken === "string"
172
+ ? parsed.refreshToken
173
+ : typeof parsed.refresh === "string"
174
+ ? parsed.refresh
175
+ : undefined;
176
+ const expiresAt = normalizeExpiryMs(parsed.expiresAt ?? parsed.expires);
177
+
178
+ return {
179
+ accessToken: parsed.token,
180
+ projectId,
181
+ refreshToken,
182
+ expiresAt,
183
+ };
184
+ }
185
+
186
+ export function shouldRefreshGeminiCliCredentials(
187
+ expiresAt: number | undefined,
188
+ isAntigravity: boolean,
189
+ nowMs = Date.now(),
190
+ ): boolean {
191
+ if (expiresAt === undefined) {
192
+ return false;
193
+ }
194
+
195
+ const skewMs = isAntigravity ? ANTIGRAVITY_REFRESH_SKEW_MS : GOOGLE_GEMINI_REFRESH_SKEW_MS;
196
+ return nowMs + skewMs >= expiresAt;
197
+ }
198
+
199
+ interface CloudCodeAssistRequest {
200
+ project: string;
201
+ model: string;
202
+ request: {
203
+ contents: Content[];
204
+ sessionId?: string;
205
+ systemInstruction?: { role?: string; parts: { text: string }[] };
206
+ generationConfig?: {
207
+ maxOutputTokens?: number;
208
+ temperature?: number;
209
+ topP?: number;
210
+ topK?: number;
211
+ minP?: number;
212
+ presencePenalty?: number;
213
+ repetitionPenalty?: number;
214
+ thinkingConfig?: ThinkingConfig;
215
+ };
216
+ tools?: { functionDeclarations: Record<string, unknown>[] }[] | undefined;
217
+ toolConfig?: {
218
+ functionCallingConfig: {
219
+ mode: FunctionCallingConfigMode;
220
+ allowedFunctionNames?: string[];
221
+ };
222
+ };
223
+ };
224
+ requestType?: string;
225
+ userAgent?: string;
226
+ requestId?: string;
227
+ }
228
+
229
+ interface CloudCodeAssistResponseChunk {
230
+ response?: {
231
+ candidates?: Array<{
232
+ content?: {
233
+ role: string;
234
+ parts?: Array<{
235
+ text?: string;
236
+ thought?: boolean;
237
+ thoughtSignature?: string;
238
+ functionCall?: {
239
+ name: string;
240
+ args: Record<string, unknown>;
241
+ id?: string;
242
+ };
243
+ }>;
244
+ };
245
+ finishReason?: string;
246
+ }>;
247
+ usageMetadata?: {
248
+ promptTokenCount?: number;
249
+ candidatesTokenCount?: number;
250
+ thoughtsTokenCount?: number;
251
+ totalTokenCount?: number;
252
+ cachedContentTokenCount?: number;
253
+ };
254
+ modelVersion?: string;
255
+ responseId?: string;
256
+ };
257
+ traceId?: string;
258
+ }
259
+
260
+ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
261
+ model: Model<"google-gemini-cli">,
262
+ context: Context,
263
+ options?: GoogleGeminiCliOptions,
264
+ ): AssistantMessageEventStream => {
265
+ const stream = new AssistantMessageEventStream();
266
+
267
+ (async () => {
268
+ const startTime = Date.now();
269
+ let firstTokenTime: number | undefined;
270
+
271
+ const output: AssistantMessage = {
272
+ role: "assistant",
273
+ content: [],
274
+ api: "google-gemini-cli" as Api,
275
+ provider: model.provider,
276
+ model: model.id,
277
+ usage: {
278
+ input: 0,
279
+ output: 0,
280
+ cacheRead: 0,
281
+ cacheWrite: 0,
282
+ totalTokens: 0,
283
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
284
+ },
285
+ stopReason: "stop",
286
+ timestamp: Date.now(),
287
+ };
288
+ let rawRequestDump: RawHttpRequestDump | undefined;
289
+
290
+ try {
291
+ const apiKeyRaw = options?.apiKey;
292
+ if (!apiKeyRaw) {
293
+ throw new Error("Google Cloud Code Assist requires OAuth authentication. Use /login to authenticate.");
294
+ }
295
+
296
+ const isAntigravity = model.provider === "google-antigravity";
297
+ const parsedCredentials = parseGeminiCliCredentials(apiKeyRaw);
298
+ // AuthStorage already refreshed credentials before threading them
299
+ // here (see {@link OAUTH_REFRESH_SKEW_MS}). If the credential lands
300
+ // expired we bail rather than POSTing a stale token; the next call
301
+ // — driven by AuthStorage's invalidate+retry path — will carry a
302
+ // fresh credential.
303
+ if (
304
+ shouldRefreshGeminiCliCredentials(parsedCredentials.expiresAt, isAntigravity) &&
305
+ parsedCredentials.expiresAt !== undefined &&
306
+ Date.now() >= parsedCredentials.expiresAt
307
+ ) {
308
+ throw new Error(
309
+ "OAuth token expired before request — please retry; AuthStorage will refresh on the next attempt.",
310
+ );
311
+ }
312
+ const { accessToken, projectId } = parsedCredentials;
313
+
314
+ const baseUrl = model.baseUrl?.trim();
315
+ const endpoints = baseUrl ? [baseUrl] : isAntigravity ? ANTIGRAVITY_ENDPOINT_FALLBACKS : [DEFAULT_ENDPOINT];
316
+
317
+ let requestBody = buildRequest(model, context, projectId, options, isAntigravity);
318
+ const replacementPayload = await options?.onPayload?.(requestBody, model);
319
+ if (replacementPayload !== undefined) {
320
+ requestBody = replacementPayload as typeof requestBody;
321
+ }
322
+ const headers = isAntigravity ? { "User-Agent": getAntigravityUserAgent() } : getGeminiCliHeaders(model.id);
323
+
324
+ const requestHeaders = {
325
+ Authorization: `Bearer ${accessToken}`,
326
+ "Content-Type": "application/json",
327
+ Accept: "text/event-stream",
328
+ ...headers,
329
+ ...(needsClaudeThinkingBetaHeader(model) ? { "anthropic-beta": CLAUDE_THINKING_BETA_HEADER } : {}),
330
+ ...(options?.headers ?? {}),
331
+ };
332
+ const requestBodyJson = JSON.stringify(requestBody);
333
+ rawRequestDump = {
334
+ provider: model.provider,
335
+ api: output.api,
336
+ model: model.id,
337
+ method: "POST",
338
+ body: requestBody,
339
+ headers: requestHeaders,
340
+ };
341
+
342
+ const response = await fetchWithRetry(
343
+ attempt => `${endpoints[Math.min(attempt, endpoints.length - 1)]}/v1internal:streamGenerateContent?alt=sse`,
344
+ {
345
+ method: "POST",
346
+ headers: requestHeaders,
347
+ body: requestBodyJson,
348
+ signal: options?.signal,
349
+ maxAttempts: MAX_RETRIES + 1,
350
+ defaultDelayMs: attempt => BASE_DELAY_MS * 2 ** attempt,
351
+ maxDelayMs: options?.maxRetryDelayMs ?? RATE_LIMIT_BUDGET_MS,
352
+ fetch: options?.fetch,
353
+ },
354
+ );
355
+ if (!response.ok) {
356
+ const errorText = await response.text();
357
+ throw withHttpStatus(
358
+ new Error(`Cloud Code Assist API error (${response.status}): ${extractErrorMessage(errorText)}`),
359
+ response.status,
360
+ );
361
+ }
362
+ const requestUrl = response.url;
363
+
364
+ let started = false;
365
+ const ensureStarted = () => {
366
+ if (!started) {
367
+ if (!firstTokenTime) firstTokenTime = Date.now();
368
+ stream.push({ type: "start", partial: output });
369
+ started = true;
370
+ }
371
+ };
372
+
373
+ const resetOutput = () => {
374
+ output.content = [];
375
+ output.usage = {
376
+ input: 0,
377
+ output: 0,
378
+ cacheRead: 0,
379
+ cacheWrite: 0,
380
+ totalTokens: 0,
381
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
382
+ };
383
+ output.stopReason = "stop";
384
+ output.errorMessage = undefined;
385
+ output.timestamp = Date.now();
386
+ started = false;
387
+ };
388
+
389
+ const streamResponse = async (activeResponse: Response): Promise<boolean> => {
390
+ if (!activeResponse.body) {
391
+ throw new Error("No response body");
392
+ }
393
+
394
+ let hasContent = false;
395
+ let currentBlock: TextContent | ThinkingContent | null = null;
396
+ const blocks = output.content;
397
+ const blockIndex = () => blocks.length - 1;
398
+
399
+ for await (const chunk of readSseJson<CloudCodeAssistResponseChunk>(
400
+ activeResponse.body!,
401
+ options?.signal,
402
+ event => options?.onSseEvent?.({ event: event.event, data: event.data, raw: [...event.raw] }, model),
403
+ )) {
404
+ const responseData = chunk.response;
405
+ if (!responseData) continue;
406
+
407
+ const candidate = responseData.candidates?.[0];
408
+ if (candidate?.content?.parts) {
409
+ for (const part of candidate.content.parts) {
410
+ if (part.text !== undefined) {
411
+ hasContent = true;
412
+ const isThinking = isThinkingPart(part);
413
+ if (
414
+ !currentBlock ||
415
+ (isThinking && currentBlock.type !== "thinking") ||
416
+ (!isThinking && currentBlock.type !== "text")
417
+ ) {
418
+ if (currentBlock) {
419
+ pushBlockEndEvent(currentBlock, blockIndex(), output, stream);
420
+ }
421
+ currentBlock = startTextOrThinkingBlock(isThinking, output, stream, ensureStarted);
422
+ }
423
+ if (currentBlock.type === "thinking") {
424
+ currentBlock.thinking += part.text;
425
+ currentBlock.thinkingSignature = retainThoughtSignature(
426
+ currentBlock.thinkingSignature,
427
+ part.thoughtSignature,
428
+ );
429
+ stream.push({
430
+ type: "thinking_delta",
431
+ contentIndex: blockIndex(),
432
+ delta: part.text,
433
+ partial: output,
434
+ });
435
+ } else {
436
+ currentBlock.text += part.text;
437
+ currentBlock.textSignature = retainThoughtSignature(
438
+ currentBlock.textSignature,
439
+ part.thoughtSignature,
440
+ );
441
+ stream.push({
442
+ type: "text_delta",
443
+ contentIndex: blockIndex(),
444
+ delta: part.text,
445
+ partial: output,
446
+ });
447
+ }
448
+ }
449
+
450
+ if (part.functionCall) {
451
+ hasContent = true;
452
+ if (currentBlock) {
453
+ pushBlockEndEvent(currentBlock, blockIndex(), output, stream);
454
+ currentBlock = null;
455
+ }
456
+
457
+ const providedId = part.functionCall.id;
458
+ const needsNewId =
459
+ !providedId || output.content.some(b => b.type === "toolCall" && b.id === providedId);
460
+ const toolCallId = needsNewId ? nextToolCallId(part.functionCall.name || "tool") : providedId;
461
+
462
+ const toolCall: ToolCall = {
463
+ type: "toolCall",
464
+ id: toolCallId,
465
+ name: part.functionCall.name || "",
466
+ arguments: part.functionCall.args as Record<string, unknown>,
467
+ ...(part.thoughtSignature && { thoughtSignature: part.thoughtSignature }),
468
+ };
469
+
470
+ output.content.push(toolCall);
471
+ ensureStarted();
472
+ pushToolCallEvents(toolCall, blockIndex(), output, stream);
473
+ }
474
+ }
475
+ }
476
+
477
+ if (candidate?.finishReason) {
478
+ output.stopReason = mapStopReasonString(candidate.finishReason);
479
+ if (output.content.some(b => b.type === "toolCall")) {
480
+ output.stopReason = "toolUse";
481
+ }
482
+ }
483
+
484
+ if (responseData.usageMetadata) {
485
+ // promptTokenCount includes cachedContentTokenCount, so subtract to get fresh input
486
+ const promptTokens = responseData.usageMetadata.promptTokenCount || 0;
487
+ const cacheReadTokens = responseData.usageMetadata.cachedContentTokenCount || 0;
488
+ const thinkingTokens = responseData.usageMetadata.thoughtsTokenCount || 0;
489
+ output.usage = {
490
+ input: promptTokens - cacheReadTokens,
491
+ output: (responseData.usageMetadata.candidatesTokenCount || 0) + thinkingTokens,
492
+ cacheRead: cacheReadTokens,
493
+ cacheWrite: 0,
494
+ totalTokens: responseData.usageMetadata.totalTokenCount || 0,
495
+ ...(thinkingTokens > 0 ? { reasoningTokens: thinkingTokens } : {}),
496
+ cost: {
497
+ input: 0,
498
+ output: 0,
499
+ cacheRead: 0,
500
+ cacheWrite: 0,
501
+ total: 0,
502
+ },
503
+ };
504
+ calculateCost(model, output.usage);
505
+ }
506
+ }
507
+
508
+ if (currentBlock) {
509
+ pushBlockEndEvent(currentBlock, blockIndex(), output, stream);
510
+ }
511
+
512
+ return hasContent;
513
+ };
514
+
515
+ let receivedContent = false;
516
+ let currentResponse = response;
517
+
518
+ for (let emptyAttempt = 0; emptyAttempt <= MAX_EMPTY_STREAM_RETRIES; emptyAttempt++) {
519
+ if (options?.signal?.aborted) {
520
+ throw new Error("Request was aborted");
521
+ }
522
+
523
+ if (emptyAttempt > 0) {
524
+ const backoffMs = EMPTY_STREAM_BASE_DELAY_MS * 2 ** (emptyAttempt - 1);
525
+ try {
526
+ await scheduler.wait(backoffMs, { signal: options?.signal });
527
+ } catch {
528
+ // Normalize AbortError to expected message for consistent error handling
529
+ throw new Error("Request was aborted");
530
+ }
531
+
532
+ if (!requestUrl) {
533
+ throw new Error("Missing request URL");
534
+ }
535
+
536
+ currentResponse = await (options?.fetch ?? fetch)(requestUrl, {
537
+ method: "POST",
538
+ headers: requestHeaders,
539
+ body: requestBodyJson,
540
+ signal: options?.signal,
541
+ });
542
+
543
+ if (!currentResponse.ok) {
544
+ const retryErrorText = await currentResponse.text();
545
+ throw withHttpStatus(
546
+ new Error(`Cloud Code Assist API error (${currentResponse.status}): ${retryErrorText}`),
547
+ currentResponse.status,
548
+ );
549
+ }
550
+ }
551
+
552
+ const streamed = await streamResponse(currentResponse);
553
+ if (streamed) {
554
+ receivedContent = true;
555
+ break;
556
+ }
557
+
558
+ if (emptyAttempt < MAX_EMPTY_STREAM_RETRIES) {
559
+ resetOutput();
560
+ }
561
+ }
562
+
563
+ if (!receivedContent) {
564
+ throw new Error("Cloud Code Assist API returned an empty response");
565
+ }
566
+
567
+ if (options?.signal?.aborted) {
568
+ throw new Error("Request was aborted");
569
+ }
570
+
571
+ if (output.stopReason === "aborted" || output.stopReason === "error") {
572
+ throw new Error(output.errorMessage ?? "An unknown error occurred");
573
+ }
574
+
575
+ output.duration = Date.now() - startTime;
576
+ if (firstTokenTime) output.ttft = firstTokenTime - startTime;
577
+ stream.push({ type: "done", reason: output.stopReason, message: output });
578
+ stream.end();
579
+ } catch (error) {
580
+ for (const block of output.content) {
581
+ if ("index" in block) {
582
+ delete (block as { index?: number }).index;
583
+ }
584
+ }
585
+ output.stopReason = options?.signal?.aborted ? "aborted" : "error";
586
+ output.errorStatus = extractHttpStatusFromError(error);
587
+ output.errorMessage = await appendRawHttpRequestDumpFor400(
588
+ error instanceof Error ? error.message : JSON.stringify(error),
589
+ error,
590
+ rawRequestDump,
591
+ );
592
+ output.duration = Date.now() - startTime;
593
+ if (firstTokenTime) output.ttft = firstTokenTime - startTime;
594
+ stream.push({ type: "error", reason: output.stopReason, error: output });
595
+ stream.end();
596
+ }
597
+ })();
598
+
599
+ return stream;
600
+ };
601
+
602
+ const INT63_MASK = (1n << 63n) - 1n;
603
+ const ANTIGRAVITY_RANDOM_BOUND = 9_000_000_000_000_000_000n;
604
+
605
+ function formatSignedDecimalSessionId(value: bigint): string {
606
+ return `-${value.toString()}`;
607
+ }
608
+
609
+ function deriveSignedDecimalFromHash(text: string): string {
610
+ const digest = createHash("sha256").update(text).digest();
611
+ let value = 0n;
612
+ for (let index = 0; index < 8; index += 1) {
613
+ value = (value << 8n) | BigInt(digest[index] ?? 0);
614
+ }
615
+ return formatSignedDecimalSessionId(value & INT63_MASK);
616
+ }
617
+
618
+ function randomBoundedInt63(maxExclusive: bigint): bigint {
619
+ while (true) {
620
+ const bytes = randomBytes(8);
621
+ let value = 0n;
622
+ for (const byte of bytes) {
623
+ value = (value << 8n) | BigInt(byte);
624
+ }
625
+ value &= INT63_MASK;
626
+ if (value < maxExclusive) {
627
+ return value;
628
+ }
629
+ }
630
+ }
631
+
632
+ function randomSignedDecimalSessionId(): string {
633
+ return formatSignedDecimalSessionId(randomBoundedInt63(ANTIGRAVITY_RANDOM_BOUND));
634
+ }
635
+
636
+ function getFirstUserTextForAntigravitySession(context: Context): string | undefined {
637
+ for (const message of context.messages) {
638
+ if (message.role !== "user") {
639
+ continue;
640
+ }
641
+
642
+ if (typeof message.content === "string") {
643
+ return message.content;
644
+ }
645
+
646
+ if (Array.isArray(message.content)) {
647
+ const firstTextPart = message.content.find((item): item is TextContent => item.type === "text");
648
+ return firstTextPart?.text;
649
+ }
650
+
651
+ return undefined;
652
+ }
653
+
654
+ return undefined;
655
+ }
656
+
657
+ function deriveAntigravitySessionId(context: Context): string {
658
+ const text = getFirstUserTextForAntigravitySession(context);
659
+ if (text && text.trim().length > 0) {
660
+ return deriveSignedDecimalFromHash(text);
661
+ }
662
+
663
+ return randomSignedDecimalSessionId();
664
+ }
665
+
666
+ function normalizeAntigravityTools(
667
+ tools: CloudCodeAssistRequest["request"]["tools"],
668
+ ): CloudCodeAssistRequest["request"]["tools"] {
669
+ return tools?.map(tool => ({
670
+ ...tool,
671
+ functionDeclarations: tool.functionDeclarations.map(declaration => {
672
+ if ("parameters" in declaration) {
673
+ return declaration;
674
+ }
675
+
676
+ const { parametersJsonSchema, ...rest } = declaration;
677
+ return {
678
+ ...rest,
679
+ parameters: normalizeSchemaForCCA(parametersJsonSchema),
680
+ };
681
+ }),
682
+ }));
683
+ }
684
+
685
+ export function buildRequest(
686
+ model: Model<"google-gemini-cli">,
687
+ context: Context,
688
+ projectId: string,
689
+ options: GoogleGeminiCliOptions = {},
690
+ isAntigravity = false,
691
+ ): CloudCodeAssistRequest {
692
+ const systemPrompts = normalizeSystemPrompts(context.systemPrompt);
693
+ const contents = convertMessages(model, context);
694
+ const generationConfig: CloudCodeAssistRequest["request"]["generationConfig"] = {};
695
+ if (options.temperature !== undefined) {
696
+ generationConfig.temperature = options.temperature;
697
+ }
698
+ if (options.maxTokens !== undefined) {
699
+ generationConfig.maxOutputTokens = options.maxTokens;
700
+ }
701
+ if (options.topP !== undefined) {
702
+ generationConfig.topP = options.topP;
703
+ }
704
+ if (options.topK !== undefined) {
705
+ generationConfig.topK = options.topK;
706
+ }
707
+ if (options.minP !== undefined) {
708
+ generationConfig.minP = options.minP;
709
+ }
710
+ if (options.presencePenalty !== undefined) {
711
+ generationConfig.presencePenalty = options.presencePenalty;
712
+ }
713
+ if (options.repetitionPenalty !== undefined) {
714
+ generationConfig.repetitionPenalty = options.repetitionPenalty;
715
+ }
716
+
717
+ // Thinking config
718
+ if (options.thinking?.enabled && model.reasoning) {
719
+ generationConfig.thinkingConfig = {
720
+ includeThoughts: true,
721
+ };
722
+ // Gemini 3 models use thinkingLevel, older models use thinkingBudget
723
+ if (options.thinking.level !== undefined) {
724
+ // Cast to any since our GoogleThinkingLevel mirrors Google's ThinkingLevel enum values
725
+ generationConfig.thinkingConfig.thinkingLevel = options.thinking.level as any;
726
+ } else if (options.thinking.budgetTokens !== undefined) {
727
+ generationConfig.thinkingConfig.thinkingBudget = options.thinking.budgetTokens;
728
+ }
729
+ }
730
+
731
+ const request: CloudCodeAssistRequest["request"] = {
732
+ contents,
733
+ };
734
+
735
+ if (isAntigravity) {
736
+ request.sessionId = deriveAntigravitySessionId(context);
737
+ }
738
+
739
+ // System instruction must be object with parts, not plain string
740
+ if (systemPrompts.length > 0) {
741
+ request.systemInstruction = {
742
+ parts: systemPrompts.map(text => ({ text })),
743
+ };
744
+ }
745
+
746
+ if (Object.keys(generationConfig).length > 0) {
747
+ request.generationConfig = generationConfig;
748
+ }
749
+
750
+ if (context.tools && context.tools.length > 0) {
751
+ const convertedTools = convertTools(context.tools, model);
752
+ request.tools = isAntigravity ? normalizeAntigravityTools(convertedTools) : convertedTools;
753
+ if (options.toolChoice) {
754
+ const choice = options.toolChoice;
755
+ if (typeof choice === "string") {
756
+ request.toolConfig = {
757
+ functionCallingConfig: { mode: mapToolChoice(choice) },
758
+ };
759
+ } else {
760
+ request.toolConfig = {
761
+ functionCallingConfig: {
762
+ mode: "ANY",
763
+ allowedFunctionNames: [...choice.allowedFunctionNames],
764
+ },
765
+ };
766
+ }
767
+ }
768
+ }
769
+
770
+ if (isAntigravity && !isClaudeModel(model.id) && request.generationConfig?.maxOutputTokens !== undefined) {
771
+ delete request.generationConfig.maxOutputTokens;
772
+ if (Object.keys(request.generationConfig).length === 0) {
773
+ delete request.generationConfig;
774
+ }
775
+ }
776
+
777
+ if (isAntigravity && isClaudeModel(model.id)) {
778
+ request.toolConfig = {
779
+ functionCallingConfig: {
780
+ mode: "VALIDATED" as FunctionCallingConfigMode,
781
+ },
782
+ };
783
+ }
784
+
785
+ if (isAntigravity && shouldInjectAntigravitySystemInstruction(model.id)) {
786
+ const existingParts = request.systemInstruction?.parts ?? [];
787
+ request.systemInstruction = {
788
+ role: "user",
789
+ parts: [
790
+ { text: ANTIGRAVITY_SYSTEM_INSTRUCTION },
791
+ { text: `Please ignore following [ignore]${ANTIGRAVITY_SYSTEM_INSTRUCTION}[/ignore]` },
792
+ ...existingParts,
793
+ ],
794
+ };
795
+ }
796
+
797
+ return {
798
+ project: projectId,
799
+ model: model.id,
800
+ request,
801
+ ...(isAntigravity
802
+ ? {
803
+ requestType: "agent",
804
+ userAgent: "antigravity",
805
+ requestId: `agent-${randomUUID()}`,
806
+ }
807
+ : {}),
808
+ };
809
+ }