@cortexkit/opencode-antigravity-auth 1.1.0 → 2.0.0

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 (371) hide show
  1. package/README.md +225 -569
  2. package/dist/cli.js +3790 -0
  3. package/dist/cli.js.map +7 -0
  4. package/dist/index.d.ts +1 -3
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +18767 -13829
  7. package/dist/index.js.map +4 -4
  8. package/dist/src/antigravity/oauth.d.ts +1 -1
  9. package/dist/src/antigravity/oauth.js +1 -1
  10. package/dist/src/cli.d.ts +21 -0
  11. package/dist/src/cli.d.ts.map +1 -0
  12. package/dist/src/cli.js +237 -0
  13. package/dist/src/cli.js.map +1 -0
  14. package/dist/src/constants.d.ts +1 -1
  15. package/dist/src/constants.js +1 -1
  16. package/dist/src/hooks/auto-update-checker/cache.d.ts.map +1 -1
  17. package/dist/src/hooks/auto-update-checker/cache.js +13 -13
  18. package/dist/src/hooks/auto-update-checker/cache.js.map +1 -1
  19. package/dist/src/hooks/auto-update-checker/checker.d.ts +1 -1
  20. package/dist/src/hooks/auto-update-checker/checker.d.ts.map +1 -1
  21. package/dist/src/hooks/auto-update-checker/checker.js +75 -51
  22. package/dist/src/hooks/auto-update-checker/checker.js.map +1 -1
  23. package/dist/src/hooks/auto-update-checker/constants.d.ts.map +1 -1
  24. package/dist/src/hooks/auto-update-checker/constants.js +12 -12
  25. package/dist/src/hooks/auto-update-checker/constants.js.map +1 -1
  26. package/dist/src/hooks/auto-update-checker/index.d.ts +6 -6
  27. package/dist/src/hooks/auto-update-checker/index.d.ts.map +1 -1
  28. package/dist/src/hooks/auto-update-checker/index.js +17 -17
  29. package/dist/src/hooks/auto-update-checker/index.js.map +1 -1
  30. package/dist/src/hooks/auto-update-checker/logging.js +2 -2
  31. package/dist/src/hooks/auto-update-checker/logging.js.map +1 -1
  32. package/dist/src/hooks/auto-update-checker/types.d.ts.map +1 -1
  33. package/dist/src/plugin/account-access.d.ts +99 -0
  34. package/dist/src/plugin/account-access.d.ts.map +1 -0
  35. package/dist/src/plugin/account-access.js +480 -0
  36. package/dist/src/plugin/account-access.js.map +1 -0
  37. package/dist/src/plugin/accounts.d.ts +7 -256
  38. package/dist/src/plugin/accounts.d.ts.map +1 -1
  39. package/dist/src/plugin/accounts.js +31 -1367
  40. package/dist/src/plugin/accounts.js.map +1 -1
  41. package/dist/src/plugin/agy-request-metadata.d.ts +1 -1
  42. package/dist/src/plugin/agy-request-metadata.js +1 -1
  43. package/dist/src/plugin/agy-transport.d.ts +1 -1
  44. package/dist/src/plugin/agy-transport.js +1 -1
  45. package/dist/src/plugin/auth-doctor.d.ts +6 -6
  46. package/dist/src/plugin/auth-doctor.d.ts.map +1 -1
  47. package/dist/src/plugin/auth-doctor.js +74 -66
  48. package/dist/src/plugin/auth-doctor.js.map +1 -1
  49. package/dist/src/plugin/auth-drift.d.ts +4 -4
  50. package/dist/src/plugin/auth-drift.d.ts.map +1 -1
  51. package/dist/src/plugin/auth-drift.js +15 -15
  52. package/dist/src/plugin/auth-drift.js.map +1 -1
  53. package/dist/src/plugin/auth-loader.d.ts +35 -0
  54. package/dist/src/plugin/auth-loader.d.ts.map +1 -0
  55. package/dist/src/plugin/auth-loader.js +144 -0
  56. package/dist/src/plugin/auth-loader.js.map +1 -0
  57. package/dist/src/plugin/auth.d.ts +1 -1
  58. package/dist/src/plugin/auth.js +1 -1
  59. package/dist/src/plugin/cache/index.d.ts +1 -1
  60. package/dist/src/plugin/cache/index.d.ts.map +1 -1
  61. package/dist/src/plugin/cache/index.js +1 -1
  62. package/dist/src/plugin/cache/index.js.map +1 -1
  63. package/dist/src/plugin/cache/signature-cache.d.ts +1 -1
  64. package/dist/src/plugin/cache/signature-cache.d.ts.map +1 -1
  65. package/dist/src/plugin/cache/signature-cache.js +23 -24
  66. package/dist/src/plugin/cache/signature-cache.js.map +1 -1
  67. package/dist/src/plugin/cache.d.ts +6 -5
  68. package/dist/src/plugin/cache.d.ts.map +1 -1
  69. package/dist/src/plugin/cache.js +21 -7
  70. package/dist/src/plugin/cache.js.map +1 -1
  71. package/dist/src/plugin/catalog.d.ts +23 -0
  72. package/dist/src/plugin/catalog.d.ts.map +1 -0
  73. package/dist/src/plugin/catalog.js +60 -0
  74. package/dist/src/plugin/catalog.js.map +1 -0
  75. package/dist/src/plugin/cli.d.ts +7 -7
  76. package/dist/src/plugin/cli.d.ts.map +1 -1
  77. package/dist/src/plugin/cli.js +62 -55
  78. package/dist/src/plugin/cli.js.map +1 -1
  79. package/dist/src/plugin/command-data.d.ts +276 -0
  80. package/dist/src/plugin/command-data.d.ts.map +1 -0
  81. package/dist/src/plugin/command-data.js +325 -0
  82. package/dist/src/plugin/command-data.js.map +1 -0
  83. package/dist/src/plugin/commands.d.ts +151 -0
  84. package/dist/src/plugin/commands.d.ts.map +1 -0
  85. package/dist/src/plugin/commands.js +639 -0
  86. package/dist/src/plugin/commands.js.map +1 -0
  87. package/dist/src/plugin/config/index.d.ts +2 -2
  88. package/dist/src/plugin/config/index.d.ts.map +1 -1
  89. package/dist/src/plugin/config/index.js +2 -2
  90. package/dist/src/plugin/config/index.js.map +1 -1
  91. package/dist/src/plugin/config/loader.d.ts +1 -1
  92. package/dist/src/plugin/config/loader.d.ts.map +1 -1
  93. package/dist/src/plugin/config/loader.js +18 -16
  94. package/dist/src/plugin/config/loader.js.map +1 -1
  95. package/dist/src/plugin/config/models.d.ts +2 -2
  96. package/dist/src/plugin/config/models.d.ts.map +1 -1
  97. package/dist/src/plugin/config/models.js +1 -1
  98. package/dist/src/plugin/config/models.js.map +1 -1
  99. package/dist/src/plugin/config/operator-settings-schema.d.ts +29 -0
  100. package/dist/src/plugin/config/operator-settings-schema.d.ts.map +1 -0
  101. package/dist/src/plugin/config/operator-settings-schema.js +28 -0
  102. package/dist/src/plugin/config/operator-settings-schema.js.map +1 -0
  103. package/dist/src/plugin/config/schema.d.ts +21 -2
  104. package/dist/src/plugin/config/schema.d.ts.map +1 -1
  105. package/dist/src/plugin/config/schema.js +85 -25
  106. package/dist/src/plugin/config/schema.js.map +1 -1
  107. package/dist/src/plugin/config/updater.d.ts.map +1 -1
  108. package/dist/src/plugin/config/updater.js +15 -15
  109. package/dist/src/plugin/config/updater.js.map +1 -1
  110. package/dist/src/plugin/config/writer.d.ts +34 -0
  111. package/dist/src/plugin/config/writer.d.ts.map +1 -0
  112. package/dist/src/plugin/config/writer.js +81 -0
  113. package/dist/src/plugin/config/writer.js.map +1 -0
  114. package/dist/src/plugin/core/streaming/index.d.ts +1 -1
  115. package/dist/src/plugin/core/streaming/index.d.ts.map +1 -1
  116. package/dist/src/plugin/core/streaming/index.js +1 -1
  117. package/dist/src/plugin/core/streaming/index.js.map +1 -1
  118. package/dist/src/plugin/core/streaming/transformer.d.ts.map +1 -1
  119. package/dist/src/plugin/core/streaming/transformer.js +85 -44
  120. package/dist/src/plugin/core/streaming/transformer.js.map +1 -1
  121. package/dist/src/plugin/core/streaming/types.d.ts.map +1 -1
  122. package/dist/src/plugin/debug.d.ts +3 -3
  123. package/dist/src/plugin/debug.d.ts.map +1 -1
  124. package/dist/src/plugin/debug.js +85 -47
  125. package/dist/src/plugin/debug.js.map +1 -1
  126. package/dist/src/plugin/dependencies.d.ts +129 -0
  127. package/dist/src/plugin/dependencies.d.ts.map +1 -0
  128. package/dist/src/plugin/dependencies.js +107 -0
  129. package/dist/src/plugin/dependencies.js.map +1 -0
  130. package/dist/src/plugin/errors.d.ts +27 -0
  131. package/dist/src/plugin/errors.d.ts.map +1 -1
  132. package/dist/src/plugin/errors.js +29 -3
  133. package/dist/src/plugin/errors.js.map +1 -1
  134. package/dist/src/plugin/event-handler.d.ts +53 -0
  135. package/dist/src/plugin/event-handler.d.ts.map +1 -0
  136. package/dist/src/plugin/event-handler.js +101 -0
  137. package/dist/src/plugin/event-handler.js.map +1 -0
  138. package/dist/src/plugin/fetch/retry-state.d.ts +61 -0
  139. package/dist/src/plugin/fetch/retry-state.d.ts.map +1 -0
  140. package/dist/src/plugin/fetch/retry-state.js +248 -0
  141. package/dist/src/plugin/fetch/retry-state.js.map +1 -0
  142. package/dist/src/plugin/fetch/warmup.d.ts +30 -0
  143. package/dist/src/plugin/fetch/warmup.d.ts.map +1 -0
  144. package/dist/src/plugin/fetch/warmup.js +76 -0
  145. package/dist/src/plugin/fetch/warmup.js.map +1 -0
  146. package/dist/src/plugin/fetch-interceptor.d.ts +59 -0
  147. package/dist/src/plugin/fetch-interceptor.d.ts.map +1 -0
  148. package/dist/src/plugin/fetch-interceptor.js +1387 -0
  149. package/dist/src/plugin/fetch-interceptor.js.map +1 -0
  150. package/dist/src/plugin/fetch-routing.d.ts +26 -0
  151. package/dist/src/plugin/fetch-routing.d.ts.map +1 -0
  152. package/dist/src/plugin/fetch-routing.js +99 -0
  153. package/dist/src/plugin/fetch-routing.js.map +1 -0
  154. package/dist/src/plugin/fingerprint.d.ts +1 -1
  155. package/dist/src/plugin/fingerprint.js +1 -1
  156. package/dist/src/plugin/gemini-dump.d.ts +5 -5
  157. package/dist/src/plugin/gemini-dump.d.ts.map +1 -1
  158. package/dist/src/plugin/gemini-dump.js +109 -55
  159. package/dist/src/plugin/gemini-dump.js.map +1 -1
  160. package/dist/src/plugin/google-search-tool.d.ts +9 -0
  161. package/dist/src/plugin/google-search-tool.d.ts.map +1 -0
  162. package/dist/src/plugin/google-search-tool.js +56 -0
  163. package/dist/src/plugin/google-search-tool.js.map +1 -0
  164. package/dist/src/plugin/image-saver.d.ts.map +1 -1
  165. package/dist/src/plugin/image-saver.js +16 -16
  166. package/dist/src/plugin/image-saver.js.map +1 -1
  167. package/dist/src/plugin/index.d.ts +23 -0
  168. package/dist/src/plugin/index.d.ts.map +1 -0
  169. package/dist/src/plugin/index.js +308 -0
  170. package/dist/src/plugin/index.js.map +1 -0
  171. package/dist/src/plugin/killswitch.d.ts +94 -0
  172. package/dist/src/plugin/killswitch.d.ts.map +1 -0
  173. package/dist/src/plugin/killswitch.js +194 -0
  174. package/dist/src/plugin/killswitch.js.map +1 -0
  175. package/dist/src/plugin/lifecycle.d.ts +40 -0
  176. package/dist/src/plugin/lifecycle.d.ts.map +1 -0
  177. package/dist/src/plugin/lifecycle.js +73 -0
  178. package/dist/src/plugin/lifecycle.js.map +1 -0
  179. package/dist/src/plugin/logger.d.ts +10 -1
  180. package/dist/src/plugin/logger.d.ts.map +1 -1
  181. package/dist/src/plugin/logger.js +38 -12
  182. package/dist/src/plugin/logger.js.map +1 -1
  183. package/dist/src/plugin/logging-utils.d.ts +35 -1
  184. package/dist/src/plugin/logging-utils.d.ts.map +1 -1
  185. package/dist/src/plugin/logging-utils.js +98 -15
  186. package/dist/src/plugin/logging-utils.js.map +1 -1
  187. package/dist/src/plugin/model-registry.d.ts +1 -1
  188. package/dist/src/plugin/model-registry.js +1 -1
  189. package/dist/src/plugin/oauth-login.d.ts +22 -0
  190. package/dist/src/plugin/oauth-login.d.ts.map +1 -0
  191. package/dist/src/plugin/oauth-login.js +37 -0
  192. package/dist/src/plugin/oauth-login.js.map +1 -0
  193. package/dist/src/plugin/oauth-methods.d.ts +42 -0
  194. package/dist/src/plugin/oauth-methods.d.ts.map +1 -0
  195. package/dist/src/plugin/oauth-methods.js +1284 -0
  196. package/dist/src/plugin/oauth-methods.js.map +1 -0
  197. package/dist/src/plugin/operator-settings.d.ts +40 -0
  198. package/dist/src/plugin/operator-settings.d.ts.map +1 -0
  199. package/dist/src/plugin/operator-settings.js +148 -0
  200. package/dist/src/plugin/operator-settings.js.map +1 -0
  201. package/dist/src/plugin/persist-account-pool.d.ts +37 -0
  202. package/dist/src/plugin/persist-account-pool.d.ts.map +1 -0
  203. package/dist/src/plugin/persist-account-pool.js +142 -0
  204. package/dist/src/plugin/persist-account-pool.js.map +1 -0
  205. package/dist/src/plugin/project.d.ts +1 -1
  206. package/dist/src/plugin/project.js +1 -1
  207. package/dist/src/plugin/prompt-context.d.ts.map +1 -1
  208. package/dist/src/plugin/prompt-context.js +11 -11
  209. package/dist/src/plugin/prompt-context.js.map +1 -1
  210. package/dist/src/plugin/quota.d.ts +97 -41
  211. package/dist/src/plugin/quota.d.ts.map +1 -1
  212. package/dist/src/plugin/quota.js +273 -285
  213. package/dist/src/plugin/quota.js.map +1 -1
  214. package/dist/src/plugin/recovery/constants.d.ts.map +1 -1
  215. package/dist/src/plugin/recovery/constants.js +24 -15
  216. package/dist/src/plugin/recovery/constants.js.map +1 -1
  217. package/dist/src/plugin/recovery/index.d.ts +3 -3
  218. package/dist/src/plugin/recovery/index.d.ts.map +1 -1
  219. package/dist/src/plugin/recovery/index.js +3 -3
  220. package/dist/src/plugin/recovery/index.js.map +1 -1
  221. package/dist/src/plugin/recovery/storage.d.ts +1 -1
  222. package/dist/src/plugin/recovery/storage.d.ts.map +1 -1
  223. package/dist/src/plugin/recovery/storage.js +31 -39
  224. package/dist/src/plugin/recovery/storage.js.map +1 -1
  225. package/dist/src/plugin/recovery/types.d.ts +12 -12
  226. package/dist/src/plugin/recovery/types.d.ts.map +1 -1
  227. package/dist/src/plugin/recovery.d.ts +3 -3
  228. package/dist/src/plugin/recovery.d.ts.map +1 -1
  229. package/dist/src/plugin/recovery.js +62 -58
  230. package/dist/src/plugin/recovery.js.map +1 -1
  231. package/dist/src/plugin/refresh-queue.d.ts +5 -2
  232. package/dist/src/plugin/refresh-queue.d.ts.map +1 -1
  233. package/dist/src/plugin/refresh-queue.js +37 -15
  234. package/dist/src/plugin/refresh-queue.js.map +1 -1
  235. package/dist/src/plugin/request-helpers.d.ts +1 -1
  236. package/dist/src/plugin/request-helpers.d.ts.map +1 -1
  237. package/dist/src/plugin/request-helpers.js +451 -352
  238. package/dist/src/plugin/request-helpers.js.map +1 -1
  239. package/dist/src/plugin/request.d.ts +7 -7
  240. package/dist/src/plugin/request.d.ts.map +1 -1
  241. package/dist/src/plugin/request.js +622 -384
  242. package/dist/src/plugin/request.js.map +1 -1
  243. package/dist/src/plugin/rotation.d.ts +1 -168
  244. package/dist/src/plugin/rotation.d.ts.map +1 -1
  245. package/dist/src/plugin/rotation.js +1 -327
  246. package/dist/src/plugin/rotation.js.map +1 -1
  247. package/dist/src/plugin/search.d.ts.map +1 -1
  248. package/dist/src/plugin/search.js +39 -35
  249. package/dist/src/plugin/search.js.map +1 -1
  250. package/dist/src/plugin/server.d.ts +1 -1
  251. package/dist/src/plugin/server.d.ts.map +1 -1
  252. package/dist/src/plugin/server.js +42 -37
  253. package/dist/src/plugin/server.js.map +1 -1
  254. package/dist/src/plugin/session-context.d.ts +2 -1
  255. package/dist/src/plugin/session-context.d.ts.map +1 -1
  256. package/dist/src/plugin/session-context.js +11 -7
  257. package/dist/src/plugin/session-context.js.map +1 -1
  258. package/dist/src/plugin/storage.d.ts +59 -120
  259. package/dist/src/plugin/storage.d.ts.map +1 -1
  260. package/dist/src/plugin/storage.js +140 -485
  261. package/dist/src/plugin/storage.js.map +1 -1
  262. package/dist/src/plugin/stores/signature-store.d.ts.map +1 -1
  263. package/dist/src/plugin/stores/signature-store.js.map +1 -1
  264. package/dist/src/plugin/thinking-recovery.d.ts.map +1 -1
  265. package/dist/src/plugin/thinking-recovery.js +35 -33
  266. package/dist/src/plugin/thinking-recovery.js.map +1 -1
  267. package/dist/src/plugin/token.d.ts +2 -2
  268. package/dist/src/plugin/token.d.ts.map +1 -1
  269. package/dist/src/plugin/token.js +30 -21
  270. package/dist/src/plugin/token.js.map +1 -1
  271. package/dist/src/plugin/transform/cross-model-sanitizer.d.ts +1 -1
  272. package/dist/src/plugin/transform/cross-model-sanitizer.js +1 -1
  273. package/dist/src/plugin/transform/index.d.ts +1 -1
  274. package/dist/src/plugin/transform/index.js +1 -1
  275. package/dist/src/plugin/transform/model-resolver.d.ts +1 -1
  276. package/dist/src/plugin/transform/model-resolver.js +1 -1
  277. package/dist/src/plugin/transform/types.d.ts +1 -1
  278. package/dist/src/plugin/transform/types.js +1 -1
  279. package/dist/src/plugin/types.d.ts +25 -69
  280. package/dist/src/plugin/types.d.ts.map +1 -1
  281. package/dist/src/plugin/ui/ansi.d.ts.map +1 -1
  282. package/dist/src/plugin/ui/ansi.js.map +1 -1
  283. package/dist/src/plugin/ui/auth-menu.d.ts +1 -1
  284. package/dist/src/plugin/ui/auth-menu.d.ts.map +1 -1
  285. package/dist/src/plugin/ui/auth-menu.js +82 -31
  286. package/dist/src/plugin/ui/auth-menu.js.map +1 -1
  287. package/dist/src/plugin/ui/confirm.d.ts.map +1 -1
  288. package/dist/src/plugin/ui/confirm.js.map +1 -1
  289. package/dist/src/plugin/ui/model-status.d.ts +3 -3
  290. package/dist/src/plugin/ui/model-status.d.ts.map +1 -1
  291. package/dist/src/plugin/ui/model-status.js +3 -3
  292. package/dist/src/plugin/ui/model-status.js.map +1 -1
  293. package/dist/src/plugin/ui/quota-status.d.ts +4 -4
  294. package/dist/src/plugin/ui/quota-status.d.ts.map +1 -1
  295. package/dist/src/plugin/ui/quota-status.js +51 -49
  296. package/dist/src/plugin/ui/quota-status.js.map +1 -1
  297. package/dist/src/plugin/ui/select.d.ts.map +1 -1
  298. package/dist/src/plugin/ui/select.js +22 -12
  299. package/dist/src/plugin/ui/select.js.map +1 -1
  300. package/dist/src/plugin/version.d.ts +1 -1
  301. package/dist/src/plugin/version.js +1 -1
  302. package/dist/src/rpc/notifications.d.ts +6 -0
  303. package/dist/src/rpc/notifications.d.ts.map +1 -0
  304. package/dist/src/rpc/notifications.js +46 -0
  305. package/dist/src/rpc/notifications.js.map +1 -0
  306. package/dist/src/rpc/port-file.d.ts +13 -0
  307. package/dist/src/rpc/port-file.d.ts.map +1 -0
  308. package/dist/src/rpc/port-file.js +109 -0
  309. package/dist/src/rpc/port-file.js.map +1 -0
  310. package/dist/src/rpc/protocol.d.ts +22 -0
  311. package/dist/src/rpc/protocol.d.ts.map +1 -0
  312. package/dist/src/rpc/protocol.js +1 -0
  313. package/dist/src/rpc/protocol.js.map +1 -0
  314. package/dist/src/rpc/rpc-client.d.ts +10 -0
  315. package/dist/src/rpc/rpc-client.d.ts.map +1 -0
  316. package/dist/src/rpc/rpc-client.js +58 -0
  317. package/dist/src/rpc/rpc-client.js.map +1 -0
  318. package/dist/src/rpc/rpc-dir.d.ts +4 -0
  319. package/dist/src/rpc/rpc-dir.d.ts.map +1 -0
  320. package/dist/src/rpc/rpc-dir.js +19 -0
  321. package/dist/src/rpc/rpc-dir.js.map +1 -0
  322. package/dist/src/rpc/rpc-server.d.ts +13 -0
  323. package/dist/src/rpc/rpc-server.d.ts.map +1 -0
  324. package/dist/src/rpc/rpc-server.js +231 -0
  325. package/dist/src/rpc/rpc-server.js.map +1 -0
  326. package/dist/src/sidebar-state.d.ts +240 -0
  327. package/dist/src/sidebar-state.d.ts.map +1 -0
  328. package/dist/src/sidebar-state.js +520 -0
  329. package/dist/src/sidebar-state.js.map +1 -0
  330. package/dist/src/tui/command-dialogs.d.ts +61 -0
  331. package/dist/src/tui/command-dialogs.d.ts.map +1 -0
  332. package/dist/src/tui/command-dialogs.js +497 -0
  333. package/dist/src/tui/command-dialogs.js.map +1 -0
  334. package/dist/src/tui/file-logger.d.ts +41 -0
  335. package/dist/src/tui/file-logger.d.ts.map +1 -0
  336. package/dist/src/tui/file-logger.js +114 -0
  337. package/dist/src/tui/file-logger.js.map +1 -0
  338. package/dist/src/tui-preferences.d.ts +40 -0
  339. package/dist/src/tui-preferences.d.ts.map +1 -0
  340. package/dist/src/tui-preferences.js +328 -0
  341. package/dist/src/tui-preferences.js.map +1 -0
  342. package/dist/src/tui.d.ts +68 -0
  343. package/dist/src/tui.d.ts.map +1 -0
  344. package/dist/src/tui.js +662 -0
  345. package/dist/src/tui.js.map +1 -0
  346. package/package.json +46 -22
  347. package/src/plugin/command-data.ts +651 -0
  348. package/src/rpc/port-file.ts +143 -0
  349. package/src/rpc/protocol.ts +31 -0
  350. package/src/rpc/rpc-client.ts +102 -0
  351. package/src/rpc/rpc-dir.ts +24 -0
  352. package/src/sidebar-state.ts +717 -0
  353. package/src/tui/command-dialogs.tsx +699 -0
  354. package/src/tui/entry.mjs +74 -0
  355. package/src/tui/file-logger.ts +145 -0
  356. package/src/tui-compiled/plugin/command-data.ts +651 -0
  357. package/src/tui-compiled/rpc/port-file.ts +143 -0
  358. package/src/tui-compiled/rpc/protocol.ts +31 -0
  359. package/src/tui-compiled/rpc/rpc-client.ts +102 -0
  360. package/src/tui-compiled/rpc/rpc-dir.ts +24 -0
  361. package/src/tui-compiled/sidebar-state.ts +717 -0
  362. package/src/tui-compiled/tui/command-dialogs.tsx +659 -0
  363. package/src/tui-compiled/tui/file-logger.ts +145 -0
  364. package/src/tui-compiled/tui-preferences.ts +416 -0
  365. package/src/tui-compiled/tui.tsx +1150 -0
  366. package/src/tui-preferences.ts +416 -0
  367. package/src/tui.tsx +1117 -0
  368. package/dist/src/plugin.d.ts +0 -48
  369. package/dist/src/plugin.d.ts.map +0 -1
  370. package/dist/src/plugin.js +0 -3311
  371. package/dist/src/plugin.js.map +0 -1
@@ -1,54 +1,56 @@
1
- import crypto from "node:crypto";
2
- import { ANTIGRAVITY_ENDPOINT, ANTIGRAVITY_DEFAULT_PROJECT_ID, GEMINI_CLI_ENDPOINT, EMPTY_SCHEMA_PLACEHOLDER_NAME, EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION, SKIP_THOUGHT_SIGNATURE, getRandomizedHeaders, } from "../constants";
3
- import { cacheSignature, getCachedSignature } from "./cache";
4
- import { getKeepThinking } from "./config";
5
- import { createStreamingTransformer, transformSseLine, transformStreamingPayload, } from "./core/streaming";
6
- import { defaultSignatureStore } from "./stores/signature-store";
7
- import { DEBUG_MESSAGE_PREFIX, isDebugEnabled, isDebugTuiEnabled, logAntigravityDebugResponse, logCacheStats, } from "./debug";
8
- import { createLogger } from "./logger";
9
- import { cleanJSONSchemaForAntigravity, deepFilterThinkingBlocks, extractThinkingConfig, extractVariantThinkingConfig, extractUsageFromSsePayload, extractUsageMetadata, fixToolResponseGrouping, validateAndFixClaudeToolPairing, applyToolPairingFixes, injectParameterSignatures, injectToolHardeningInstruction, isThinkingCapableModel, normalizeThinkingConfig, parseAntigravityApiBody, resolveThinkingConfig, rewriteAntigravityPreviewAccessError, transformThinkingParts, } from "./request-helpers";
10
- import { CLAUDE_TOOL_SYSTEM_INSTRUCTION, CLAUDE_DESCRIPTION_PROMPT, } from "../constants";
11
- import { analyzeConversationState, closeToolLoopForThinking, needsThinkingRecovery, } from "./thinking-recovery";
12
- import { sanitizeCrossModelPayloadInPlace } from "./transform/cross-model-sanitizer";
13
- import { isGemini3Model, isImageGenerationModel, buildImageGenerationConfig, applyGeminiTransforms } from "./transform";
14
- import { resolveModelWithTier, resolveModelWithVariant, resolveModelForHeaderStyle, isClaudeModel, isClaudeThinkingModel, CLAUDE_THINKING_MAX_OUTPUT_TOKENS, computeClaudeMaxOutputTokens, appendClaudeThinkingHint, } from "./transform";
15
- import { detectErrorType } from "./recovery";
16
- import { getSessionFingerprint, buildFingerprintHeaders } from "./fingerprint";
17
- import { buildAgyAgentRequestMetadata, createAgyRequestSessionContext, orderAgyRequestPayloadInPlace, } from "./agy-request-metadata";
18
- import { appendGeminiDumpResponseText, createGeminiDumpResponseTransform, noteGeminiDumpResponse, } from "./gemini-dump";
19
- const log = createLogger("request");
1
+ import crypto from 'node:crypto';
2
+ import { ANTIGRAVITY_DEFAULT_PROJECT_ID, ANTIGRAVITY_ENDPOINT, CLAUDE_DESCRIPTION_PROMPT, CLAUDE_TOOL_SYSTEM_INSTRUCTION, EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION, EMPTY_SCHEMA_PLACEHOLDER_NAME, GEMINI_CLI_ENDPOINT, getRandomizedHeaders, SKIP_THOUGHT_SIGNATURE, } from '../constants';
3
+ import { buildAgyAgentRequestMetadata, createAgyRequestSessionContext, orderAgyRequestPayloadInPlace, } from './agy-request-metadata';
4
+ import { cacheSignature, getCachedSignature } from './cache';
5
+ import { getKeepThinking } from './config';
6
+ import { createStreamingTransformer, transformSseLine, transformStreamingPayload, } from './core/streaming';
7
+ import { DEBUG_MESSAGE_PREFIX, isDebugTuiEnabled, logAntigravityDebugResponse, logCacheStats, } from './debug';
8
+ import { buildFingerprintHeaders, getSessionFingerprint, } from './fingerprint';
9
+ import { appendGeminiDumpResponseText, createGeminiDumpResponseTransform, noteGeminiDumpResponse, } from './gemini-dump';
10
+ import { createLogger } from './logger';
11
+ import { detectErrorType } from './recovery';
12
+ import { applyToolPairingFixes, cleanJSONSchemaForAntigravity, deepFilterThinkingBlocks, extractThinkingConfig, extractUsageFromSsePayload, extractUsageMetadata, extractVariantThinkingConfig, fixToolResponseGrouping, injectParameterSignatures, injectToolHardeningInstruction, isThinkingCapableModel, normalizeThinkingConfig, parseAntigravityApiBody, resolveThinkingConfig, rewriteAntigravityPreviewAccessError, transformThinkingParts, validateAndFixClaudeToolPairing, } from './request-helpers';
13
+ import { defaultSignatureStore } from './stores/signature-store';
14
+ import { analyzeConversationState, closeToolLoopForThinking, needsThinkingRecovery, } from './thinking-recovery';
15
+ import { appendClaudeThinkingHint, applyGeminiTransforms, buildImageGenerationConfig, computeClaudeMaxOutputTokens, isClaudeModel, isClaudeThinkingModel, isGemini3Model, isImageGenerationModel, resolveModelForHeaderStyle, } from './transform';
16
+ import { sanitizeCrossModelPayloadInPlace } from './transform/cross-model-sanitizer';
17
+ const log = createLogger('request');
20
18
  const PLUGIN_SESSION_ID = `-${crypto.randomUUID()}`;
21
- const DEFAULT_AGY_REQUEST_SESSION = createAgyRequestSessionContext("");
19
+ const DEFAULT_AGY_REQUEST_SESSION = createAgyRequestSessionContext('');
22
20
  const sessionDisplayedThinkingHashes = new Set();
23
21
  const MIN_SIGNATURE_LENGTH = 50;
24
22
  const AGY_CLAUDE_THINKING_BUDGET = 1024;
25
23
  const ANTIGRAVITY_ENVELOPE_FIELD_ORDER = [
26
- "project",
27
- "requestId",
28
- "request",
29
- "model",
30
- "userAgent",
31
- "requestType",
24
+ 'project',
25
+ 'requestId',
26
+ 'request',
27
+ 'model',
28
+ 'userAgent',
29
+ 'requestType',
32
30
  ];
33
- const OPENCODE_TITLE_PROMPT_PREFIX = "Generate a title for this conversation:";
31
+ const OPENCODE_TITLE_PROMPT_PREFIX = 'Generate a title for this conversation:';
34
32
  function getOpenCodeTitleSourceText(payload) {
35
33
  if (!Array.isArray(payload.contents)) {
36
34
  return undefined;
37
35
  }
38
36
  const texts = payload.contents.flatMap((content) => {
39
- if (!content || typeof content !== "object") {
37
+ if (!content || typeof content !== 'object') {
40
38
  return [];
41
39
  }
42
40
  const parts = content.parts;
43
41
  if (!Array.isArray(parts)) {
44
42
  return [];
45
43
  }
46
- return parts.flatMap((part) => !!part && typeof part === "object" && typeof part.text === "string"
44
+ return parts.flatMap((part) => part &&
45
+ typeof part === 'object' &&
46
+ typeof part.text === 'string'
47
47
  ? [part.text]
48
48
  : []);
49
49
  });
50
50
  const promptIndex = texts.findIndex((text) => text.startsWith(OPENCODE_TITLE_PROMPT_PREFIX));
51
- return promptIndex >= 0 ? texts.slice(promptIndex + 1).find((text) => text.trim().length > 0) : undefined;
51
+ return promptIndex >= 0
52
+ ? texts.slice(promptIndex + 1).find((text) => text.trim().length > 0)
53
+ : undefined;
52
54
  }
53
55
  function isOpenCodeTitleGenerationRequest(payload) {
54
56
  return getOpenCodeTitleSourceText(payload) !== undefined;
@@ -56,13 +58,13 @@ function isOpenCodeTitleGenerationRequest(payload) {
56
58
  function formatLocalImageTitle(sourceText) {
57
59
  const normalized = sourceText
58
60
  .trim()
59
- .replace(/^(["“])(.*)(["”])$/s, "$2")
60
- .replace(/\s+/g, " ");
61
+ .replace(/^(["“])(.*)(["”])$/s, '$2')
62
+ .replace(/\s+/g, ' ');
61
63
  const characters = Array.from(normalized);
62
64
  if (characters.length <= 50) {
63
- return normalized || "Image generation";
65
+ return normalized || 'Image generation';
64
66
  }
65
- return `${characters.slice(0, 47).join("").trimEnd()}...`;
67
+ return `${characters.slice(0, 47).join('').trimEnd()}...`;
66
68
  }
67
69
  export function getImageModelLocalTitle(input, init) {
68
70
  const url = fetchInputToUrl(input);
@@ -70,17 +72,19 @@ export function getImageModelLocalTitle(input, init) {
70
72
  return undefined;
71
73
  }
72
74
  const body = init?.body;
73
- const bodyText = typeof body === "string"
75
+ const bodyText = typeof body === 'string'
74
76
  ? body
75
77
  : body instanceof Uint8Array
76
78
  ? new TextDecoder().decode(body)
77
- : "";
79
+ : '';
78
80
  if (!bodyText) {
79
81
  return undefined;
80
82
  }
81
83
  try {
82
84
  const sourceText = getOpenCodeTitleSourceText(JSON.parse(bodyText));
83
- return sourceText === undefined ? undefined : formatLocalImageTitle(sourceText);
85
+ return sourceText === undefined
86
+ ? undefined
87
+ : formatLocalImageTitle(sourceText);
84
88
  }
85
89
  catch {
86
90
  return undefined;
@@ -88,27 +92,27 @@ export function getImageModelLocalTitle(input, init) {
88
92
  }
89
93
  function getAgyMaxOutputTokens(model) {
90
94
  const lower = model.toLowerCase();
91
- if (lower === "gemini-3.5-flash-low"
92
- || lower === "gemini-3.5-flash-extra-low"
93
- || lower === "gemini-3-flash-agent"
94
- || lower === "gemini-3.6-flash-low"
95
- || lower === "gemini-3.6-flash-medium"
96
- || lower === "gemini-3.6-flash-high") {
95
+ if (lower === 'gemini-3.5-flash-low' ||
96
+ lower === 'gemini-3.5-flash-extra-low' ||
97
+ lower === 'gemini-3-flash-agent' ||
98
+ lower === 'gemini-3.6-flash-low' ||
99
+ lower === 'gemini-3.6-flash-medium' ||
100
+ lower === 'gemini-3.6-flash-high') {
97
101
  return 65536;
98
102
  }
99
- if (lower === "gemini-3.1-pro-low" || lower === "gemini-pro-agent") {
103
+ if (lower === 'gemini-3.1-pro-low' || lower === 'gemini-pro-agent') {
100
104
  return 65535;
101
105
  }
102
- if (lower === "claude-sonnet-4-6" || lower === "claude-opus-4-6-thinking") {
106
+ if (lower === 'claude-sonnet-4-6' || lower === 'claude-opus-4-6-thinking') {
103
107
  return 64000;
104
108
  }
105
- if (lower === "gpt-oss-120b-medium") {
109
+ if (lower === 'gpt-oss-120b-medium') {
106
110
  return 32768;
107
111
  }
108
112
  return undefined;
109
113
  }
110
114
  function applyAgyGenerationDefaults(model, generationConfig, headerStyle) {
111
- if (headerStyle !== "antigravity") {
115
+ if (headerStyle !== 'antigravity') {
112
116
  return;
113
117
  }
114
118
  const maxOutputTokens = getAgyMaxOutputTokens(model);
@@ -132,13 +136,13 @@ function orderAntigravityEnvelope(body) {
132
136
  return ordered;
133
137
  }
134
138
  function buildSignatureSessionKey(sessionId, model, conversationKey, projectKey) {
135
- const modelKey = typeof model === "string" && model.trim() ? model.toLowerCase() : "unknown";
136
- const projectPart = typeof projectKey === "string" && projectKey.trim()
139
+ const modelKey = typeof model === 'string' && model.trim() ? model.toLowerCase() : 'unknown';
140
+ const projectPart = typeof projectKey === 'string' && projectKey.trim()
137
141
  ? projectKey.trim()
138
- : "default";
139
- const conversationPart = typeof conversationKey === "string" && conversationKey.trim()
142
+ : 'default';
143
+ const conversationPart = typeof conversationKey === 'string' && conversationKey.trim()
140
144
  ? conversationKey.trim()
141
- : "default";
145
+ : 'default';
142
146
  return `${sessionId}:${modelKey}:${projectPart}:${conversationPart}`;
143
147
  }
144
148
  /**
@@ -150,22 +154,30 @@ function buildSignatureSessionKey(sessionId, model, conversationKey, projectKey)
150
154
  * by checking for JSON Schema primitive types. Everything else that's
151
155
  * a non-string `thinking` value gets flattened to "".
152
156
  */
153
- const JSON_SCHEMA_TYPES = new Set(["boolean", "string", "number", "integer", "array", "object"]);
157
+ const JSON_SCHEMA_TYPES = new Set([
158
+ 'boolean',
159
+ 'string',
160
+ 'number',
161
+ 'integer',
162
+ 'array',
163
+ 'object',
164
+ ]);
154
165
  function thinkingSafeReplacer(key, value) {
155
- if (key === "thinking" && typeof value === "object" && value !== null) {
166
+ if (key === 'thinking' && typeof value === 'object' && value !== null) {
156
167
  // Preserve tool schemas before and after Gemini uppercases their type.
157
168
  const rec = value;
158
- if (typeof rec.type === "string" && JSON_SCHEMA_TYPES.has(rec.type.toLowerCase())) {
169
+ if (typeof rec.type === 'string' &&
170
+ JSON_SCHEMA_TYPES.has(rec.type.toLowerCase())) {
159
171
  return value;
160
172
  }
161
173
  // Flatten any non-string, non-Schema thinking to empty string
162
- return "";
174
+ return '';
163
175
  }
164
176
  return value;
165
177
  }
166
178
  /** Stringify with built-in thinking sanitization. Impossible to bypass. */
167
179
  function ensureThinkingFields(obj) {
168
- if (!obj || typeof obj !== "object")
180
+ if (!obj || typeof obj !== 'object')
169
181
  return;
170
182
  if (Array.isArray(obj)) {
171
183
  for (const item of obj)
@@ -176,11 +188,11 @@ function ensureThinkingFields(obj) {
176
188
  // Fix: check for missing OR undefined OR non-string thinking field.
177
189
  // JSON.stringify silently drops undefined values, so key-exists-but-undefined
178
190
  // produces { type: "thinking", signature: "..." } with NO thinking field.
179
- if (rec.type === "thinking" && typeof rec.thinking !== "string") {
180
- rec.thinking = "";
191
+ if (rec.type === 'thinking' && typeof rec.thinking !== 'string') {
192
+ rec.thinking = '';
181
193
  }
182
- if (rec.thought === true && typeof rec.text !== "string") {
183
- rec.text = "";
194
+ if (rec.thought === true && typeof rec.text !== 'string') {
195
+ rec.text = '';
184
196
  }
185
197
  for (const val of Object.values(rec)) {
186
198
  ensureThinkingFields(val);
@@ -191,59 +203,67 @@ function safeStringify(obj) {
191
203
  return JSON.stringify(obj, thinkingSafeReplacer);
192
204
  }
193
205
  function shouldCacheThinkingSignatures(model) {
194
- if (typeof model !== "string")
206
+ if (typeof model !== 'string')
195
207
  return false;
196
208
  const lower = model.toLowerCase();
197
209
  // Both Claude and Gemini 3 models require thought signature caching
198
210
  // for multi-turn conversations with function calling
199
- return lower.includes("claude") || lower.includes("gemini-3");
211
+ return lower.includes('claude') || lower.includes('gemini-3');
200
212
  }
201
213
  function hashConversationSeed(seed) {
202
- return crypto.createHash("sha256").update(seed, "utf8").digest("hex").slice(0, 16);
214
+ return crypto
215
+ .createHash('sha256')
216
+ .update(seed, 'utf8')
217
+ .digest('hex')
218
+ .slice(0, 16);
203
219
  }
204
220
  function extractTextFromContent(content) {
205
- if (typeof content === "string") {
221
+ if (typeof content === 'string') {
206
222
  return content;
207
223
  }
208
224
  if (!Array.isArray(content)) {
209
- return "";
225
+ return '';
210
226
  }
211
227
  for (const block of content) {
212
- if (!block || typeof block !== "object") {
228
+ if (!block || typeof block !== 'object') {
213
229
  continue;
214
230
  }
215
231
  const anyBlock = block;
216
- if (typeof anyBlock.text === "string") {
232
+ if (typeof anyBlock.text === 'string') {
217
233
  return anyBlock.text;
218
234
  }
219
- if (anyBlock.text && typeof anyBlock.text === "object" && typeof anyBlock.text.text === "string") {
235
+ if (anyBlock.text &&
236
+ typeof anyBlock.text === 'object' &&
237
+ typeof anyBlock.text.text === 'string') {
220
238
  return anyBlock.text.text;
221
239
  }
222
240
  }
223
- return "";
241
+ return '';
224
242
  }
225
243
  function extractConversationSeedFromMessages(messages) {
226
- const system = messages.find((message) => message?.role === "system");
227
- const users = messages.filter((message) => message?.role === "user");
244
+ const system = messages.find((message) => message?.role === 'system');
245
+ const users = messages.filter((message) => message?.role === 'user');
228
246
  const firstUser = users[0];
229
247
  const lastUser = users.length > 0 ? users[users.length - 1] : undefined;
230
- const systemText = system ? extractTextFromContent(system.content) : "";
231
- const userText = firstUser ? extractTextFromContent(firstUser.content) : "";
232
- const fallbackUserText = !userText && lastUser ? extractTextFromContent(lastUser.content) : "";
233
- return [systemText, userText || fallbackUserText].filter(Boolean).join("|");
248
+ const systemText = system ? extractTextFromContent(system.content) : '';
249
+ const userText = firstUser ? extractTextFromContent(firstUser.content) : '';
250
+ const fallbackUserText = !userText && lastUser ? extractTextFromContent(lastUser.content) : '';
251
+ return [systemText, userText || fallbackUserText].filter(Boolean).join('|');
234
252
  }
235
253
  function extractConversationSeedFromContents(contents) {
236
- const users = contents.filter((content) => content?.role === "user");
254
+ const users = contents.filter((content) => content?.role === 'user');
237
255
  const firstUser = users[0];
238
256
  const lastUser = users.length > 0 ? users[users.length - 1] : undefined;
239
- const primaryUser = firstUser && Array.isArray(firstUser.parts) ? extractTextFromContent(firstUser.parts) : "";
257
+ const primaryUser = firstUser && Array.isArray(firstUser.parts)
258
+ ? extractTextFromContent(firstUser.parts)
259
+ : '';
240
260
  if (primaryUser) {
241
261
  return primaryUser;
242
262
  }
243
263
  if (lastUser && Array.isArray(lastUser.parts)) {
244
264
  return extractTextFromContent(lastUser.parts);
245
265
  }
246
- return "";
266
+ return '';
247
267
  }
248
268
  function resolveConversationKey(requestPayload) {
249
269
  const anyPayload = requestPayload;
@@ -262,20 +282,20 @@ function resolveConversationKey(requestPayload) {
262
282
  anyPayload.metadata?.threadId,
263
283
  ];
264
284
  for (const candidate of candidates) {
265
- if (typeof candidate === "string" && candidate.trim()) {
285
+ if (typeof candidate === 'string' && candidate.trim()) {
266
286
  return candidate.trim();
267
287
  }
268
288
  }
269
- const systemSeed = extractTextFromContent(anyPayload.systemInstruction?.parts
270
- ?? anyPayload.systemInstruction
271
- ?? anyPayload.system
272
- ?? anyPayload.system_instruction);
289
+ const systemSeed = extractTextFromContent(anyPayload.systemInstruction?.parts ??
290
+ anyPayload.systemInstruction ??
291
+ anyPayload.system ??
292
+ anyPayload.system_instruction);
273
293
  const messageSeed = Array.isArray(anyPayload.messages)
274
294
  ? extractConversationSeedFromMessages(anyPayload.messages)
275
295
  : Array.isArray(anyPayload.contents)
276
296
  ? extractConversationSeedFromContents(anyPayload.contents)
277
- : "";
278
- const seed = [systemSeed, messageSeed].filter(Boolean).join("|");
297
+ : '';
298
+ const seed = [systemSeed, messageSeed].filter(Boolean).join('|');
279
299
  if (!seed) {
280
300
  return undefined;
281
301
  }
@@ -291,10 +311,10 @@ function resolveConversationKeyFromRequests(requestObjects) {
291
311
  return undefined;
292
312
  }
293
313
  function resolveProjectKey(candidate, fallback) {
294
- if (typeof candidate === "string" && candidate.trim()) {
314
+ if (typeof candidate === 'string' && candidate.trim()) {
295
315
  return candidate.trim();
296
316
  }
297
- if (typeof fallback === "string" && fallback.trim()) {
317
+ if (typeof fallback === 'string' && fallback.trim()) {
298
318
  return fallback.trim();
299
319
  }
300
320
  return undefined;
@@ -305,10 +325,10 @@ function formatDebugLinesForThinking(lines) {
305
325
  .filter((line) => line.length > 0)
306
326
  .slice(-50);
307
327
  const prelude = `[ThinkingResolution] source=debug_tui lines=${cleaned.length}`;
308
- return `${DEBUG_MESSAGE_PREFIX}\n- ${prelude}\n${cleaned.map((line) => `- ${line}`).join("\n")}`;
328
+ return `${DEBUG_MESSAGE_PREFIX}\n- ${prelude}\n${cleaned.map((line) => `- ${line}`).join('\n')}`;
309
329
  }
310
330
  function injectDebugThinking(response, debugText) {
311
- if (!response || typeof response !== "object") {
331
+ if (!response || typeof response !== 'object') {
312
332
  return response;
313
333
  }
314
334
  const resp = response;
@@ -316,9 +336,9 @@ function injectDebugThinking(response, debugText) {
316
336
  const candidates = resp.candidates.slice();
317
337
  const first = candidates[0];
318
338
  if (first &&
319
- typeof first === "object" &&
339
+ typeof first === 'object' &&
320
340
  first.content &&
321
- typeof first.content === "object" &&
341
+ typeof first.content === 'object' &&
322
342
  Array.isArray(first.content.parts)) {
323
343
  const parts = [{ thought: true, text: debugText }, ...first.content.parts];
324
344
  candidates[0] = { ...first, content: { ...first.content, parts } };
@@ -327,7 +347,7 @@ function injectDebugThinking(response, debugText) {
327
347
  return resp;
328
348
  }
329
349
  if (Array.isArray(resp.content)) {
330
- const content = [{ type: "thinking", thinking: debugText }, ...resp.content];
350
+ const content = [{ type: 'thinking', thinking: debugText }, ...resp.content];
331
351
  return { ...resp, content };
332
352
  }
333
353
  if (!resp.reasoning_content) {
@@ -340,7 +360,7 @@ function injectDebugThinking(response, debugText) {
340
360
  * Injected via the same path as debug text (injectDebugThinking) to ensure consistent
341
361
  * signature caching and multi-turn handling.
342
362
  */
343
- const SYNTHETIC_THINKING_PLACEHOLDER = "[Thinking preserved]\n";
363
+ const SYNTHETIC_THINKING_PLACEHOLDER = '[Thinking preserved]\n';
344
364
  function stripInjectedDebugFromParts(parts) {
345
365
  if (!Array.isArray(parts)) {
346
366
  return parts;
@@ -348,18 +368,20 @@ function stripInjectedDebugFromParts(parts) {
348
368
  // Use .map() with empty text sentinels instead of .filter() to preserve
349
369
  // array indices and prevent prompt cache invalidation.
350
370
  return parts.map((part) => {
351
- if (!part || typeof part !== "object") {
371
+ if (!part || typeof part !== 'object') {
352
372
  return part;
353
373
  }
354
374
  const record = part;
355
- const text = typeof record.text === "string"
375
+ const text = typeof record.text === 'string'
356
376
  ? record.text
357
- : typeof record.thinking === "string"
377
+ : typeof record.thinking === 'string'
358
378
  ? record.thinking
359
379
  : undefined;
360
380
  // Replace debug blocks and synthetic thinking placeholders with empty text sentinel
361
- if (text && (text.startsWith(DEBUG_MESSAGE_PREFIX) || text.startsWith(SYNTHETIC_THINKING_PLACEHOLDER.trim()))) {
362
- const sentinel = { text: "." };
381
+ if (text &&
382
+ (text.startsWith(DEBUG_MESSAGE_PREFIX) ||
383
+ text.startsWith(SYNTHETIC_THINKING_PLACEHOLDER.trim()))) {
384
+ const sentinel = { text: '.' };
363
385
  if (record.cache_control !== undefined)
364
386
  sentinel.cache_control = record.cache_control;
365
387
  return sentinel;
@@ -371,50 +393,56 @@ function stripInjectedDebugFromRequestPayload(payload) {
371
393
  const anyPayload = payload;
372
394
  if (Array.isArray(anyPayload.contents)) {
373
395
  anyPayload.contents = anyPayload.contents.map((content) => {
374
- if (!content || typeof content !== "object") {
396
+ if (!content || typeof content !== 'object') {
375
397
  return content;
376
398
  }
377
399
  if (Array.isArray(content.parts)) {
378
400
  return { ...content, parts: stripInjectedDebugFromParts(content.parts) };
379
401
  }
380
402
  if (Array.isArray(content.content)) {
381
- return { ...content, content: stripInjectedDebugFromParts(content.content) };
403
+ return {
404
+ ...content,
405
+ content: stripInjectedDebugFromParts(content.content),
406
+ };
382
407
  }
383
408
  return content;
384
409
  });
385
410
  }
386
411
  if (Array.isArray(anyPayload.messages)) {
387
412
  anyPayload.messages = anyPayload.messages.map((message) => {
388
- if (!message || typeof message !== "object") {
413
+ if (!message || typeof message !== 'object') {
389
414
  return message;
390
415
  }
391
416
  if (Array.isArray(message.content)) {
392
- return { ...message, content: stripInjectedDebugFromParts(message.content) };
417
+ return {
418
+ ...message,
419
+ content: stripInjectedDebugFromParts(message.content),
420
+ };
393
421
  }
394
422
  return message;
395
423
  });
396
424
  }
397
425
  }
398
426
  function isValidRequestPart(part) {
399
- if (!part || typeof part !== "object") {
427
+ if (!part || typeof part !== 'object') {
400
428
  return false;
401
429
  }
402
430
  const record = part;
403
- return (Object.prototype.hasOwnProperty.call(record, "text") ||
404
- Object.prototype.hasOwnProperty.call(record, "functionCall") ||
405
- Object.prototype.hasOwnProperty.call(record, "functionResponse") ||
406
- Object.prototype.hasOwnProperty.call(record, "inlineData") ||
407
- Object.prototype.hasOwnProperty.call(record, "fileData") ||
408
- Object.prototype.hasOwnProperty.call(record, "executableCode") ||
409
- Object.prototype.hasOwnProperty.call(record, "codeExecutionResult") ||
410
- Object.prototype.hasOwnProperty.call(record, "thought"));
431
+ return (Object.hasOwn(record, 'text') ||
432
+ Object.hasOwn(record, 'functionCall') ||
433
+ Object.hasOwn(record, 'functionResponse') ||
434
+ Object.hasOwn(record, 'inlineData') ||
435
+ Object.hasOwn(record, 'fileData') ||
436
+ Object.hasOwn(record, 'executableCode') ||
437
+ Object.hasOwn(record, 'codeExecutionResult') ||
438
+ Object.hasOwn(record, 'thought'));
411
439
  }
412
440
  function stripCacheControlFromParts(parts) {
413
441
  if (!Array.isArray(parts)) {
414
442
  return;
415
443
  }
416
444
  for (const part of parts) {
417
- if (!part || typeof part !== "object" || Array.isArray(part)) {
445
+ if (!part || typeof part !== 'object' || Array.isArray(part)) {
418
446
  continue;
419
447
  }
420
448
  const record = part;
@@ -429,7 +457,7 @@ function stripUnsupportedAntigravityFields(payload) {
429
457
  delete payload.cache_control;
430
458
  delete payload.cacheControl;
431
459
  const extraBody = payload.extra_body;
432
- if (extraBody && typeof extraBody === "object" && !Array.isArray(extraBody)) {
460
+ if (extraBody && typeof extraBody === 'object' && !Array.isArray(extraBody)) {
433
461
  const extraBodyRecord = extraBody;
434
462
  delete extraBodyRecord.cached_content;
435
463
  delete extraBodyRecord.cachedContent;
@@ -444,7 +472,7 @@ function stripUnsupportedAntigravityFields(payload) {
444
472
  return;
445
473
  }
446
474
  for (const item of items) {
447
- if (!item || typeof item !== "object" || Array.isArray(item)) {
475
+ if (!item || typeof item !== 'object' || Array.isArray(item)) {
448
476
  continue;
449
477
  }
450
478
  const record = item;
@@ -454,9 +482,14 @@ function stripUnsupportedAntigravityFields(payload) {
454
482
  };
455
483
  stripContentParts(payload.contents);
456
484
  stripContentParts(payload.messages);
457
- for (const instructionKey of ["systemInstruction", "system_instruction"]) {
485
+ for (const instructionKey of [
486
+ 'systemInstruction',
487
+ 'system_instruction',
488
+ ]) {
458
489
  const instruction = payload[instructionKey];
459
- if (instruction && typeof instruction === "object" && !Array.isArray(instruction)) {
490
+ if (instruction &&
491
+ typeof instruction === 'object' &&
492
+ !Array.isArray(instruction)) {
460
493
  stripCacheControlFromParts(instruction.parts);
461
494
  }
462
495
  }
@@ -466,15 +499,17 @@ function configureAntigravityToolCalling(payload) {
466
499
  delete payload.toolConfig;
467
500
  return;
468
501
  }
469
- const toolConfig = payload.toolConfig && typeof payload.toolConfig === "object" && !Array.isArray(payload.toolConfig)
502
+ const toolConfig = payload.toolConfig &&
503
+ typeof payload.toolConfig === 'object' &&
504
+ !Array.isArray(payload.toolConfig)
470
505
  ? payload.toolConfig
471
506
  : {};
472
507
  const functionCallingConfig = toolConfig.functionCallingConfig &&
473
- typeof toolConfig.functionCallingConfig === "object" &&
508
+ typeof toolConfig.functionCallingConfig === 'object' &&
474
509
  !Array.isArray(toolConfig.functionCallingConfig)
475
510
  ? toolConfig.functionCallingConfig
476
511
  : {};
477
- functionCallingConfig.mode = "VALIDATED";
512
+ functionCallingConfig.mode = 'VALIDATED';
478
513
  toolConfig.functionCallingConfig = functionCallingConfig;
479
514
  payload.toolConfig = toolConfig;
480
515
  }
@@ -482,23 +517,26 @@ function sanitizeRequestPayloadForAntigravity(payload) {
482
517
  const anyPayload = payload;
483
518
  if (Array.isArray(anyPayload.contents)) {
484
519
  // Use .map() instead of .map().filter() to preserve array indices for prompt cache stability
485
- anyPayload.contents = anyPayload.contents
486
- .map((content) => {
487
- if (!content || typeof content !== "object") {
520
+ anyPayload.contents = anyPayload.contents.map((content) => {
521
+ if (!content || typeof content !== 'object') {
488
522
  // Preserve non-object entries as empty sentinel instead of filtering
489
- return { role: "user", parts: [{ text: "." }] };
523
+ return { role: 'user', parts: [{ text: '.' }] };
490
524
  }
491
525
  const contentRecord = content;
492
- const rawParts = Array.isArray(contentRecord.parts) ? contentRecord.parts : [];
526
+ const rawParts = Array.isArray(contentRecord.parts)
527
+ ? contentRecord.parts
528
+ : [];
493
529
  let foundFirstFunctionCall = false;
494
- const sanitizedParts = rawParts.map((part) => {
530
+ const sanitizedParts = rawParts
531
+ .map((part) => {
495
532
  // Replace invalid parts with sentinel to preserve array indices for cache stability
496
533
  if (!isValidRequestPart(part)) {
497
- return { text: "." };
534
+ return { text: '.' };
498
535
  }
499
536
  return part;
500
- }).map((part) => {
501
- if (part && typeof part === "object" && part.functionCall) {
537
+ })
538
+ .map((part) => {
539
+ if (part && typeof part === 'object' && part.functionCall) {
502
540
  let sig = part.thoughtSignature || part.thought_signature;
503
541
  // Only the first functionCall part in a block should have the signature.
504
542
  // If it's the first one and missing a valid signature, inject the sentinel
@@ -526,7 +564,7 @@ function sanitizeRequestPayloadForAntigravity(payload) {
526
564
  });
527
565
  if (sanitizedParts.length === 0) {
528
566
  // Preserve as empty text sentinel instead of filtering out
529
- return { ...contentRecord, parts: [{ text: "." }] };
567
+ return { ...contentRecord, parts: [{ text: '.' }] };
530
568
  }
531
569
  return {
532
570
  ...contentRecord,
@@ -536,23 +574,28 @@ function sanitizeRequestPayloadForAntigravity(payload) {
536
574
  }
537
575
  if (Array.isArray(anyPayload.messages)) {
538
576
  anyPayload.messages = anyPayload.messages.map((message) => {
539
- if (!message || typeof message !== "object") {
540
- return { role: "user", content: [{ type: "text", text: "." }] };
577
+ if (!message || typeof message !== 'object') {
578
+ return { role: 'user', content: [{ type: 'text', text: '.' }] };
541
579
  }
542
580
  const messageRecord = message;
543
- const rawContent = Array.isArray(messageRecord.content) ? messageRecord.content : messageRecord.content;
581
+ const rawContent = Array.isArray(messageRecord.content)
582
+ ? messageRecord.content
583
+ : messageRecord.content;
544
584
  if (!Array.isArray(rawContent)) {
545
585
  return messageRecord;
546
586
  }
547
587
  const sanitizedContent = rawContent.map((block) => {
548
- if (!block || typeof block !== "object") {
549
- return { type: "text", text: "." };
588
+ if (!block || typeof block !== 'object') {
589
+ return { type: 'text', text: '.' };
550
590
  }
551
591
  const blockRecord = block;
552
- if (blockRecord.type === "text") {
592
+ if (blockRecord.type === 'text') {
553
593
  const text = blockRecord.text;
554
- if (typeof text !== "string" || text.trim().length === 0) {
555
- const sentinel = { type: "text", text: "." };
594
+ if (typeof text !== 'string' || text.trim().length === 0) {
595
+ const sentinel = {
596
+ type: 'text',
597
+ text: '.',
598
+ };
556
599
  if (blockRecord.cache_control !== undefined)
557
600
  sentinel.cache_control = blockRecord.cache_control;
558
601
  return sentinel;
@@ -561,7 +604,7 @@ function sanitizeRequestPayloadForAntigravity(payload) {
561
604
  return block;
562
605
  });
563
606
  if (sanitizedContent.length === 0) {
564
- return { ...messageRecord, content: [{ type: "text", text: "." }] };
607
+ return { ...messageRecord, content: [{ type: 'text', text: '.' }] };
565
608
  }
566
609
  return {
567
610
  ...messageRecord,
@@ -570,7 +613,9 @@ function sanitizeRequestPayloadForAntigravity(payload) {
570
613
  });
571
614
  }
572
615
  const systemInstruction = anyPayload.systemInstruction;
573
- if (systemInstruction && typeof systemInstruction === "object" && !Array.isArray(systemInstruction)) {
616
+ if (systemInstruction &&
617
+ typeof systemInstruction === 'object' &&
618
+ !Array.isArray(systemInstruction)) {
574
619
  const sys = systemInstruction;
575
620
  if (Array.isArray(sys.parts)) {
576
621
  // Use .map() with sentinels instead of .filter() to preserve array indices
@@ -579,13 +624,16 @@ function sanitizeRequestPayloadForAntigravity(payload) {
579
624
  if (isValidRequestPart(part))
580
625
  return part;
581
626
  const record = part;
582
- const sentinel = { text: "." };
627
+ const sentinel = { text: '.' };
583
628
  if (record?.cache_control !== undefined)
584
629
  sentinel.cache_control = record.cache_control;
585
630
  return sentinel;
586
631
  });
587
632
  // Only delete systemInstruction if ALL parts were invalid (all sentinels, no real content)
588
- const hasRealContent = sanitizedSystemParts.some((p) => p && typeof p === "object" && typeof p.text === "string" && p.text !== ".");
633
+ const hasRealContent = sanitizedSystemParts.some((p) => p &&
634
+ typeof p === 'object' &&
635
+ typeof p.text === 'string' &&
636
+ p.text !== '.');
589
637
  if (hasRealContent) {
590
638
  sys.parts = sanitizedSystemParts;
591
639
  }
@@ -596,31 +644,35 @@ function sanitizeRequestPayloadForAntigravity(payload) {
596
644
  }
597
645
  }
598
646
  function isGeminiToolUsePart(part) {
599
- return !!(part && typeof part === "object" && (part.functionCall || part.tool_use || part.toolUse));
647
+ return !!(part &&
648
+ typeof part === 'object' &&
649
+ (part.functionCall || part.tool_use || part.toolUse));
600
650
  }
601
651
  function isGeminiThinkingPart(part) {
602
652
  return !!(part &&
603
- typeof part === "object" &&
604
- (part.thought === true || part.type === "thinking" || part.type === "reasoning"));
653
+ typeof part === 'object' &&
654
+ (part.thought === true ||
655
+ part.type === 'thinking' ||
656
+ part.type === 'reasoning'));
605
657
  }
606
658
  // Sentinel value used when signature recovery fails - allows Claude to handle gracefully
607
659
  // by redacting the thinking block instead of rejecting the request entirely.
608
660
  // Reference: LLM-API-Key-Proxy uses this pattern for Gemini 3 tool calls.
609
- const SENTINEL_SIGNATURE = "skip_thought_signature_validator";
661
+ const SENTINEL_SIGNATURE = 'skip_thought_signature_validator';
610
662
  function getThinkingPartText(part) {
611
- if (!part || typeof part !== "object") {
612
- return "";
663
+ if (!part || typeof part !== 'object') {
664
+ return '';
613
665
  }
614
- if (typeof part.text === "string") {
666
+ if (typeof part.text === 'string') {
615
667
  return part.text;
616
668
  }
617
- if (typeof part.thinking === "string") {
669
+ if (typeof part.thinking === 'string') {
618
670
  return part.thinking;
619
671
  }
620
- return "";
672
+ return '';
621
673
  }
622
674
  function hasCachedMatchingSignature(part, sessionId) {
623
- if (!part || typeof part !== "object") {
675
+ if (!part || typeof part !== 'object') {
624
676
  return false;
625
677
  }
626
678
  const text = getThinkingPartText(part);
@@ -637,7 +689,7 @@ function hasCachedMatchingSignature(part, sessionId) {
637
689
  return part.signature === expectedSignature;
638
690
  }
639
691
  function ensureThoughtSignature(part, sessionId) {
640
- if (!part || typeof part !== "object") {
692
+ if (!part || typeof part !== 'object') {
641
693
  return part;
642
694
  }
643
695
  if (!sessionId) {
@@ -650,20 +702,24 @@ function ensureThoughtSignature(part, sessionId) {
650
702
  if (part.thought === true) {
651
703
  return { ...part, thoughtSignature: SENTINEL_SIGNATURE };
652
704
  }
653
- if (part.type === "thinking" || part.type === "reasoning" || part.type === "redacted_thinking") {
705
+ if (part.type === 'thinking' ||
706
+ part.type === 'reasoning' ||
707
+ part.type === 'redacted_thinking') {
654
708
  return { ...part, signature: SENTINEL_SIGNATURE };
655
709
  }
656
710
  return part;
657
711
  }
658
712
  function hasSignedThinkingPart(part, sessionId) {
659
- if (!part || typeof part !== "object") {
713
+ if (!part || typeof part !== 'object') {
660
714
  return false;
661
715
  }
662
716
  if (part.thought === true) {
663
- if (part.thoughtSignature === SENTINEL_SIGNATURE || part.thoughtSignature === SKIP_THOUGHT_SIGNATURE) {
717
+ if (part.thoughtSignature === SENTINEL_SIGNATURE ||
718
+ part.thoughtSignature === SKIP_THOUGHT_SIGNATURE) {
664
719
  return true;
665
720
  }
666
- if (typeof part.thoughtSignature !== "string" || part.thoughtSignature.length < MIN_SIGNATURE_LENGTH) {
721
+ if (typeof part.thoughtSignature !== 'string' ||
722
+ part.thoughtSignature.length < MIN_SIGNATURE_LENGTH) {
667
723
  return false;
668
724
  }
669
725
  if (!sessionId) {
@@ -671,11 +727,15 @@ function hasSignedThinkingPart(part, sessionId) {
671
727
  }
672
728
  return hasCachedMatchingSignature(part, sessionId);
673
729
  }
674
- if (part.type === "thinking" || part.type === "reasoning" || part.type === "redacted_thinking") {
675
- if (part.signature === SENTINEL_SIGNATURE || part.signature === SKIP_THOUGHT_SIGNATURE) {
730
+ if (part.type === 'thinking' ||
731
+ part.type === 'reasoning' ||
732
+ part.type === 'redacted_thinking') {
733
+ if (part.signature === SENTINEL_SIGNATURE ||
734
+ part.signature === SKIP_THOUGHT_SIGNATURE) {
676
735
  return true;
677
736
  }
678
- if (typeof part.signature !== "string" || part.signature.length < MIN_SIGNATURE_LENGTH) {
737
+ if (typeof part.signature !== 'string' ||
738
+ part.signature.length < MIN_SIGNATURE_LENGTH) {
679
739
  return false;
680
740
  }
681
741
  if (!sessionId) {
@@ -687,11 +747,13 @@ function hasSignedThinkingPart(part, sessionId) {
687
747
  }
688
748
  function ensureThinkingBeforeToolUseInContents(contents, signatureSessionKey) {
689
749
  return contents.map((content) => {
690
- if (!content || typeof content !== "object" || !Array.isArray(content.parts)) {
750
+ if (!content ||
751
+ typeof content !== 'object' ||
752
+ !Array.isArray(content.parts)) {
691
753
  return content;
692
754
  }
693
755
  const role = content.role;
694
- if (role !== "model" && role !== "assistant") {
756
+ if (role !== 'model' && role !== 'assistant') {
695
757
  return content;
696
758
  }
697
759
  const parts = content.parts;
@@ -700,22 +762,31 @@ function ensureThinkingBeforeToolUseInContents(contents, signatureSessionKey) {
700
762
  return content;
701
763
  }
702
764
  // Check if any thinking part has a valid signed signature
703
- const hasSignedThinking = parts.some(p => isGeminiThinkingPart(p) && hasSignedThinkingPart(ensureThoughtSignature(p, signatureSessionKey), signatureSessionKey));
765
+ const hasSignedThinking = parts.some((p) => isGeminiThinkingPart(p) &&
766
+ hasSignedThinkingPart(ensureThoughtSignature(p, signatureSessionKey), signatureSessionKey));
704
767
  if (hasSignedThinking) {
705
768
  // Ensure signatures on thinking parts in-place — NO reordering to preserve array indices (cache-friendly)
706
- return { ...content, parts: parts.map(p => isGeminiThinkingPart(p) ? ensureThoughtSignature(p, signatureSessionKey) : p) };
769
+ return {
770
+ ...content,
771
+ parts: parts.map((p) => isGeminiThinkingPart(p)
772
+ ? ensureThoughtSignature(p, signatureSessionKey)
773
+ : p),
774
+ };
707
775
  }
708
776
  // Replace thinking parts with sentinels in-place to preserve array indices (cache-friendly).
709
777
  // Deleting parts via .filter() shifts array indices → changes hash → busts prompt cache.
710
778
  const lastThinking = defaultSignatureStore.get(signatureSessionKey);
711
- log.debug("Replacing thinking with sentinels in-place", { signatureSessionKey, hasCachedSig: !!lastThinking });
712
- const newParts = parts.map(p => {
779
+ log.debug('Replacing thinking with sentinels in-place', {
780
+ signatureSessionKey,
781
+ hasCachedSig: !!lastThinking,
782
+ });
783
+ const newParts = parts.map((p) => {
713
784
  if (!isGeminiThinkingPart(p))
714
785
  return p;
715
786
  const cc = p.cache_control;
716
787
  // Use plain empty text part — thinking-format sentinels get converted by the proxy
717
788
  // into Claude thinking blocks missing the required `thinking` field.
718
- const sentinel = { text: "." };
789
+ const sentinel = { text: '.' };
719
790
  if (cc)
720
791
  sentinel.cache_control = cc;
721
792
  return sentinel;
@@ -724,10 +795,10 @@ function ensureThinkingBeforeToolUseInContents(contents, signatureSessionKey) {
724
795
  });
725
796
  }
726
797
  function ensureMessageThinkingSignature(block, sessionId) {
727
- if (!block || typeof block !== "object") {
798
+ if (!block || typeof block !== 'object') {
728
799
  return block;
729
800
  }
730
- if (block.type !== "thinking" && block.type !== "redacted_thinking") {
801
+ if (block.type !== 'thinking' && block.type !== 'redacted_thinking') {
731
802
  return block;
732
803
  }
733
804
  const text = getThinkingPartText(block);
@@ -741,7 +812,9 @@ function ensureMessageThinkingSignature(block, sessionId) {
741
812
  }
742
813
  function hasToolUseInContents(contents) {
743
814
  return contents.some((content) => {
744
- if (!content || typeof content !== "object" || !Array.isArray(content.parts)) {
815
+ if (!content ||
816
+ typeof content !== 'object' ||
817
+ !Array.isArray(content.parts)) {
745
818
  return false;
746
819
  }
747
820
  return content.parts.some(isGeminiToolUsePart);
@@ -749,7 +822,9 @@ function hasToolUseInContents(contents) {
749
822
  }
750
823
  function hasSignedThinkingInContents(contents, sessionId) {
751
824
  return contents.some((content) => {
752
- if (!content || typeof content !== "object" || !Array.isArray(content.parts)) {
825
+ if (!content ||
826
+ typeof content !== 'object' ||
827
+ !Array.isArray(content.parts)) {
753
828
  return false;
754
829
  }
755
830
  return content.parts.some((part) => hasSignedThinkingPart(part, sessionId));
@@ -757,15 +832,21 @@ function hasSignedThinkingInContents(contents, sessionId) {
757
832
  }
758
833
  function hasToolUseInMessages(messages) {
759
834
  return messages.some((message) => {
760
- if (!message || typeof message !== "object" || !Array.isArray(message.content)) {
835
+ if (!message ||
836
+ typeof message !== 'object' ||
837
+ !Array.isArray(message.content)) {
761
838
  return false;
762
839
  }
763
- return message.content.some((block) => block && typeof block === "object" && (block.type === "tool_use" || block.type === "tool_result"));
840
+ return message.content.some((block) => block &&
841
+ typeof block === 'object' &&
842
+ (block.type === 'tool_use' || block.type === 'tool_result'));
764
843
  });
765
844
  }
766
845
  function hasSignedThinkingInMessages(messages, sessionId) {
767
846
  return messages.some((message) => {
768
- if (!message || typeof message !== "object" || !Array.isArray(message.content)) {
847
+ if (!message ||
848
+ typeof message !== 'object' ||
849
+ !Array.isArray(message.content)) {
769
850
  return false;
770
851
  }
771
852
  return message.content.some((block) => hasSignedThinkingPart(block, sessionId));
@@ -773,40 +854,64 @@ function hasSignedThinkingInMessages(messages, sessionId) {
773
854
  }
774
855
  function ensureThinkingBeforeToolUseInMessages(messages, signatureSessionKey) {
775
856
  return messages.map((message) => {
776
- if (!message || typeof message !== "object" || !Array.isArray(message.content)) {
857
+ if (!message ||
858
+ typeof message !== 'object' ||
859
+ !Array.isArray(message.content)) {
777
860
  return message;
778
861
  }
779
- if (message.role !== "assistant") {
862
+ if (message.role !== 'assistant') {
780
863
  return message;
781
864
  }
782
865
  const blocks = message.content;
783
- const hasToolUse = blocks.some((b) => b && typeof b === "object" && (b.type === "tool_use" || b.type === "tool_result"));
866
+ const hasToolUse = blocks.some((b) => b &&
867
+ typeof b === 'object' &&
868
+ (b.type === 'tool_use' || b.type === 'tool_result'));
784
869
  if (!hasToolUse) {
785
870
  return message;
786
871
  }
787
- const isThinkingBlock = (b) => b && typeof b === "object" && (b.type === "thinking" || b.type === "redacted_thinking");
872
+ const isThinkingBlock = (b) => b &&
873
+ typeof b === 'object' &&
874
+ (b.type === 'thinking' || b.type === 'redacted_thinking');
788
875
  // Check if any thinking block has a valid signed signature
789
- const hasSignedThinking = blocks.some((b) => isThinkingBlock(b) && hasSignedThinkingPart(ensureMessageThinkingSignature(b, signatureSessionKey), signatureSessionKey));
876
+ const hasSignedThinking = blocks.some((b) => isThinkingBlock(b) &&
877
+ hasSignedThinkingPart(ensureMessageThinkingSignature(b, signatureSessionKey), signatureSessionKey));
790
878
  if (hasSignedThinking) {
791
879
  // Ensure signatures on thinking blocks in-place — NO reordering to preserve array indices (cache-friendly)
792
- return { ...message, content: blocks.map((b) => isThinkingBlock(b) ? ensureMessageThinkingSignature(b, signatureSessionKey) : b) };
880
+ return {
881
+ ...message,
882
+ content: blocks.map((b) => isThinkingBlock(b)
883
+ ? ensureMessageThinkingSignature(b, signatureSessionKey)
884
+ : b),
885
+ };
793
886
  }
794
887
  // Replace thinking blocks with sentinels in-place to preserve array indices (cache-friendly).
795
888
  // Deleting/reordering via .filter() shifts indices → changes hash → busts prompt cache.
796
889
  const lastThinking = defaultSignatureStore.get(signatureSessionKey);
797
- log.debug("Replacing thinking with sentinels in-place (Messages format)", { signatureSessionKey, hasCachedSig: !!lastThinking });
798
- return { ...message, content: blocks.map((b) => {
890
+ log.debug('Replacing thinking with sentinels in-place (Messages format)', {
891
+ signatureSessionKey,
892
+ hasCachedSig: !!lastThinking,
893
+ });
894
+ return {
895
+ ...message,
896
+ content: blocks.map((b) => {
799
897
  if (!isThinkingBlock(b))
800
898
  return b;
801
- const thinkingText = lastThinking ? lastThinking.text : (typeof b.thinking === "string" ? b.thinking : typeof b.text === "string" ? b.text : "");
899
+ const _thinkingText = lastThinking
900
+ ? lastThinking.text
901
+ : typeof b.thinking === 'string'
902
+ ? b.thinking
903
+ : typeof b.text === 'string'
904
+ ? b.text
905
+ : '';
802
906
  const cc = b.cache_control;
803
907
  // Use plain empty text part — thinking-format sentinels get converted by the proxy
804
908
  // into Claude thinking blocks missing the required `thinking` field.
805
- const sentinel = { text: "." };
909
+ const sentinel = { text: '.' };
806
910
  if (cc)
807
911
  sentinel.cache_control = cc;
808
912
  return sentinel;
809
- }) };
913
+ }),
914
+ };
810
915
  });
811
916
  }
812
917
  /**
@@ -819,18 +924,18 @@ let _lastCacheStats = null;
819
924
  export function getLastCacheStats() {
820
925
  return _lastCacheStats;
821
926
  }
822
- const STREAM_ACTION = "streamGenerateContent";
927
+ const STREAM_ACTION = 'streamGenerateContent';
823
928
  /**
824
929
  * Extract a URL string from any fetch() input shape (string, URL, or Request).
825
930
  */
826
931
  export function fetchInputToUrl(input) {
827
- if (typeof input === "string")
932
+ if (typeof input === 'string')
828
933
  return input;
829
934
  if (input instanceof URL)
830
935
  return input.href;
831
936
  // Request-like object
832
937
  const url = input.url;
833
- return typeof url === "string" ? url : String(input);
938
+ return typeof url === 'string' ? url : String(input);
834
939
  }
835
940
  /**
836
941
  * Detects requests headed to the Google Generative Language API so we can
@@ -839,12 +944,12 @@ export function fetchInputToUrl(input) {
839
944
  * interceptor entirely.
840
945
  */
841
946
  export function isGenerativeLanguageRequest(input) {
842
- return fetchInputToUrl(input).includes("generativelanguage.googleapis.com");
947
+ return fetchInputToUrl(input).includes('generativelanguage.googleapis.com');
843
948
  }
844
- export function prepareAntigravityRequest(input, init, accessToken, projectId, endpointOverride, headerStyle = "antigravity", forceThinkingRecovery = false, options) {
949
+ export function prepareAntigravityRequest(input, init, accessToken, projectId, endpointOverride, headerStyle = 'antigravity', forceThinkingRecovery = false, options) {
845
950
  const baseInit = { ...init };
846
951
  const headers = new Headers(init?.headers ?? {});
847
- let resolvedProjectId = projectId?.trim() || "";
952
+ let resolvedProjectId = projectId?.trim() || '';
848
953
  let toolDebugMissing = 0;
849
954
  const toolDebugSummaries = [];
850
955
  let toolDebugPayload;
@@ -859,16 +964,16 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
859
964
  headerStyle,
860
965
  };
861
966
  }
862
- headers.set("Authorization", `Bearer ${accessToken}`);
863
- headers.delete("x-api-key");
864
- headers.delete("x-goog-api-key");
865
- headers.delete("x-session-affinity");
866
- headers.delete("x-session-id");
867
- headers.delete("x-parent-session-id");
967
+ headers.set('Authorization', `Bearer ${accessToken}`);
968
+ headers.delete('x-api-key');
969
+ headers.delete('x-goog-api-key');
970
+ headers.delete('x-session-affinity');
971
+ headers.delete('x-session-id');
972
+ headers.delete('x-parent-session-id');
868
973
  // Strip x-goog-user-project header to prevent 403 auth/license conflicts.
869
974
  // This header is added by OpenCode/AI SDK and can force project-level checks
870
975
  // that are not required for Antigravity/Gemini CLI OAuth requests.
871
- headers.delete("x-goog-user-project");
976
+ headers.delete('x-goog-user-project');
872
977
  const urlString = fetchInputToUrl(input);
873
978
  const match = urlString.match(/\/models\/([^:]+):(\w+)/);
874
979
  if (!match) {
@@ -879,14 +984,14 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
879
984
  headerStyle,
880
985
  };
881
986
  }
882
- const [, rawModel = "", rawAction = ""] = match;
987
+ const [, rawModel = '', rawAction = ''] = match;
883
988
  const requestedModel = rawModel;
884
989
  const resolved = resolveModelForHeaderStyle(rawModel, headerStyle);
885
990
  let effectiveModel = resolved.actualModel;
886
991
  const streaming = rawAction === STREAM_ACTION;
887
- const defaultEndpoint = headerStyle === "gemini-cli" ? GEMINI_CLI_ENDPOINT : ANTIGRAVITY_ENDPOINT;
992
+ const defaultEndpoint = headerStyle === 'gemini-cli' ? GEMINI_CLI_ENDPOINT : ANTIGRAVITY_ENDPOINT;
888
993
  const baseEndpoint = endpointOverride ?? defaultEndpoint;
889
- const transformedUrl = `${baseEndpoint}/v1internal:${rawAction}${streaming ? "?alt=sse" : ""}`;
994
+ const transformedUrl = `${baseEndpoint}/v1internal:${rawAction}${streaming ? '?alt=sse' : ''}`;
890
995
  const isClaude = isClaudeModel(resolved.actualModel);
891
996
  const isClaudeThinking = isClaudeThinkingModel(resolved.actualModel);
892
997
  const keepThinkingEnabled = getKeepThinking();
@@ -895,21 +1000,23 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
895
1000
  let tierThinkingLevel = resolved.thinkingLevel;
896
1001
  let signatureSessionKey = buildSignatureSessionKey(PLUGIN_SESSION_ID, effectiveModel, undefined, resolveProjectKey(projectId));
897
1002
  let body = baseInit.body;
898
- if (typeof baseInit.body === "string" && baseInit.body) {
1003
+ if (typeof baseInit.body === 'string' && baseInit.body) {
899
1004
  try {
900
1005
  const parsedBody = JSON.parse(baseInit.body);
901
- const isWrapped = typeof parsedBody.project === "string" && "request" in parsedBody;
1006
+ const isWrapped = typeof parsedBody.project === 'string' && 'request' in parsedBody;
902
1007
  if (isWrapped) {
903
1008
  const wrappedBody = {
904
1009
  ...parsedBody,
905
1010
  model: effectiveModel,
906
1011
  };
907
- if (headerStyle === "antigravity") {
908
- if (typeof wrappedBody.userAgent !== "string" || !wrappedBody.userAgent) {
909
- wrappedBody.userAgent = "antigravity";
1012
+ if (headerStyle === 'antigravity') {
1013
+ if (typeof wrappedBody.userAgent !== 'string' ||
1014
+ !wrappedBody.userAgent) {
1015
+ wrappedBody.userAgent = 'antigravity';
910
1016
  }
911
- if (typeof wrappedBody.requestType !== "string" || !wrappedBody.requestType) {
912
- wrappedBody.requestType = "agent";
1017
+ if (typeof wrappedBody.requestType !== 'string' ||
1018
+ !wrappedBody.requestType) {
1019
+ wrappedBody.requestType = 'agent';
913
1020
  }
914
1021
  }
915
1022
  // Some callers may already send an Antigravity-wrapped body.
@@ -917,17 +1024,17 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
917
1024
  // and attach a stable sessionId so multi-turn signature caching works.
918
1025
  const requestRoot = wrappedBody.request;
919
1026
  const requestObjects = [];
920
- if (requestRoot && typeof requestRoot === "object") {
1027
+ if (requestRoot && typeof requestRoot === 'object') {
921
1028
  requestObjects.push(requestRoot);
922
1029
  const nested = requestRoot.request;
923
- if (nested && typeof nested === "object") {
1030
+ if (nested && typeof nested === 'object') {
924
1031
  requestObjects.push(nested);
925
1032
  }
926
1033
  }
927
1034
  const conversationKey = resolveConversationKeyFromRequests(requestObjects);
928
1035
  // Strip tier suffix from model for cache key to prevent cache misses on tier change
929
1036
  // e.g., "claude-opus-4-6-thinking-high" -> "claude-opus-4-6-thinking"
930
- const modelForCacheKey = effectiveModel.replace(/-(minimal|low|medium|high)$/i, "");
1037
+ const modelForCacheKey = effectiveModel.replace(/-(minimal|low|medium|high)$/i, '');
931
1038
  signatureSessionKey = buildSignatureSessionKey(PLUGIN_SESSION_ID, modelForCacheKey, conversationKey, resolveProjectKey(parsedBody.project));
932
1039
  if (requestObjects.length > 0) {
933
1040
  sessionId = signatureSessionKey;
@@ -936,57 +1043,73 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
936
1043
  stripInjectedDebugFromRequestPayload(req);
937
1044
  if (isClaude) {
938
1045
  // Step 0: Sanitize cross-model metadata (strips Gemini signatures when sending to Claude)
939
- sanitizeCrossModelPayloadInPlace(req, { targetModel: effectiveModel });
1046
+ sanitizeCrossModelPayloadInPlace(req, {
1047
+ targetModel: effectiveModel,
1048
+ });
940
1049
  // Step 1: Strip corrupted/unsigned thinking blocks FIRST
941
1050
  deepFilterThinkingBlocks(req, signatureSessionKey, getCachedSignature, true);
942
1051
  // Step 2: THEN inject signed thinking from cache (after stripping)
943
- if (isClaudeThinking && keepThinkingEnabled && Array.isArray(req.contents)) {
1052
+ if (isClaudeThinking &&
1053
+ keepThinkingEnabled &&
1054
+ Array.isArray(req.contents)) {
1055
+ ;
944
1056
  req.contents = ensureThinkingBeforeToolUseInContents(req.contents, signatureSessionKey);
945
1057
  }
946
- if (isClaudeThinking && keepThinkingEnabled && Array.isArray(req.messages)) {
1058
+ if (isClaudeThinking &&
1059
+ keepThinkingEnabled &&
1060
+ Array.isArray(req.messages)) {
1061
+ ;
947
1062
  req.messages = ensureThinkingBeforeToolUseInMessages(req.messages, signatureSessionKey);
948
1063
  }
949
1064
  // Step 3: Apply tool pairing fixes (ID assignment, response matching, orphan recovery)
950
1065
  applyToolPairingFixes(req, true);
951
1066
  }
952
- if (headerStyle === "antigravity") {
1067
+ if (headerStyle === 'antigravity') {
953
1068
  sanitizeRequestPayloadForAntigravity(req);
954
1069
  stripUnsupportedAntigravityFields(req);
955
1070
  configureAntigravityToolCalling(req);
956
1071
  }
957
1072
  }
958
- // Guard against assistant prefill: Claude rejects conversations ending
959
- // with model/assistant messages. After context compaction, the conversation
960
- // can end with a model message — append synthetic user message to fix.
961
- if (isClaude) {
1073
+ // AGY rejects every request that ends with a model turn. Enforce this at
1074
+ // the final wire boundary because host races, recovery, or sanitization can
1075
+ // otherwise leave a model/assistant entry last. Claude fallback transports
1076
+ // have the same assistant-prefill restriction.
1077
+ if (headerStyle === 'antigravity' || isClaude) {
962
1078
  for (const req of requestObjects) {
963
1079
  if (Array.isArray(req.contents)) {
964
1080
  const contents = req.contents;
965
1081
  const lastContent = contents[contents.length - 1];
966
- if (lastContent?.role === "model" || lastContent?.role === "assistant") {
967
- contents.push({ role: "user", parts: [{ text: "[Continue]" }] });
1082
+ if (lastContent?.role === 'model' ||
1083
+ lastContent?.role === 'assistant') {
1084
+ contents.push({ role: 'user', parts: [{ text: '[Continue]' }] });
968
1085
  }
969
1086
  }
970
1087
  if (Array.isArray(req.messages)) {
971
1088
  const messages = req.messages;
972
1089
  const lastMessage = messages[messages.length - 1];
973
- if (lastMessage?.role === "model" || lastMessage?.role === "assistant") {
974
- messages.push({ role: "user", parts: [{ text: "[Continue]" }] });
1090
+ if (lastMessage?.role === 'model' ||
1091
+ lastMessage?.role === 'assistant') {
1092
+ messages.push({ role: 'user', parts: [{ text: '[Continue]' }] });
975
1093
  }
976
1094
  }
977
1095
  }
978
1096
  }
979
1097
  if (isClaudeThinking && keepThinkingEnabled && sessionId) {
980
- const hasToolUse = requestObjects.some((req) => (Array.isArray(req.contents) && hasToolUseInContents(req.contents)) ||
981
- (Array.isArray(req.messages) && hasToolUseInMessages(req.messages)));
982
- const hasSignedThinking = requestObjects.some((req) => (Array.isArray(req.contents) && hasSignedThinkingInContents(req.contents, signatureSessionKey)) ||
983
- (Array.isArray(req.messages) && hasSignedThinkingInMessages(req.messages, signatureSessionKey)));
1098
+ const hasToolUse = requestObjects.some((req) => (Array.isArray(req.contents) &&
1099
+ hasToolUseInContents(req.contents)) ||
1100
+ (Array.isArray(req.messages) &&
1101
+ hasToolUseInMessages(req.messages)));
1102
+ const hasSignedThinking = requestObjects.some((req) => (Array.isArray(req.contents) &&
1103
+ hasSignedThinkingInContents(req.contents, signatureSessionKey)) ||
1104
+ (Array.isArray(req.messages) &&
1105
+ hasSignedThinkingInMessages(req.messages, signatureSessionKey)));
984
1106
  const hasCachedThinking = defaultSignatureStore.has(signatureSessionKey);
985
- needsSignedThinkingWarmup = hasToolUse && !hasSignedThinking && !hasCachedThinking;
1107
+ needsSignedThinkingWarmup =
1108
+ hasToolUse && !hasSignedThinking && !hasCachedThinking;
986
1109
  }
987
1110
  const wireRequest = requestObjects.at(-1);
988
1111
  if (wireRequest) {
989
- if (headerStyle === "antigravity") {
1112
+ if (headerStyle === 'antigravity') {
990
1113
  const metadata = buildAgyAgentRequestMetadata(options?.agySession ?? DEFAULT_AGY_REQUEST_SESSION, wireRequest, effectiveModel, options?.agyRequestTimestamp);
991
1114
  wrappedBody.requestId = metadata.requestId;
992
1115
  wireRequest.sessionId = metadata.sessionId;
@@ -997,45 +1120,55 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
997
1120
  wireRequest.sessionId = signatureSessionKey;
998
1121
  }
999
1122
  }
1000
- body = safeStringify(headerStyle === "antigravity" ? orderAntigravityEnvelope(wrappedBody) : wrappedBody);
1123
+ body = safeStringify(headerStyle === 'antigravity'
1124
+ ? orderAntigravityEnvelope(wrappedBody)
1125
+ : wrappedBody);
1001
1126
  }
1002
1127
  else {
1003
1128
  const requestPayload = { ...parsedBody };
1004
- if (headerStyle === "antigravity" &&
1129
+ if (headerStyle === 'antigravity' &&
1005
1130
  isImageGenerationModel(effectiveModel) &&
1006
1131
  isOpenCodeTitleGenerationRequest(requestPayload)) {
1007
1132
  // OpenCode runs title generation through the active model. Route that
1008
1133
  // text-only helper call away from image generation to avoid consuming
1009
1134
  // image quota and writing unrelated image files.
1010
- effectiveModel = "gemini-3.5-flash-low";
1135
+ effectiveModel = 'gemini-3.5-flash-low';
1011
1136
  tierThinkingBudget = 4000;
1012
1137
  tierThinkingLevel = undefined;
1013
1138
  }
1014
1139
  const rawGenerationConfig = requestPayload.generationConfig;
1015
1140
  const extraBody = requestPayload.extra_body;
1016
1141
  const variantConfig = extractVariantThinkingConfig(requestPayload.providerOptions, rawGenerationConfig);
1017
- const isGemini3 = effectiveModel.toLowerCase().includes("gemini-3");
1018
- log.debug(`[ThinkingResolution] rawModel=${rawModel} resolvedModel=${effectiveModel} resolvedTier=${tierThinkingLevel ?? "none"} variantLevel=${variantConfig?.thinkingLevel ?? "none"} variantBudget=${variantConfig?.thinkingBudget ?? "none"} providerOptions.google=${JSON.stringify(requestPayload.providerOptions?.google ?? null)} generationConfig.thinkingConfig=${JSON.stringify(rawGenerationConfig?.thinkingConfig ?? null)}`);
1142
+ const isGemini3 = effectiveModel.toLowerCase().includes('gemini-3');
1143
+ log.debug(`[ThinkingResolution] rawModel=${rawModel} resolvedModel=${effectiveModel} resolvedTier=${tierThinkingLevel ?? 'none'} variantLevel=${variantConfig?.thinkingLevel ?? 'none'} variantBudget=${variantConfig?.thinkingBudget ?? 'none'} providerOptions.google=${JSON.stringify(requestPayload.providerOptions?.google ?? null)} generationConfig.thinkingConfig=${JSON.stringify(rawGenerationConfig?.thinkingConfig ?? null)}`);
1019
1144
  // providerOptions belongs to the host AI SDK and is only used above to
1020
1145
  // resolve the requested variant. It is never part of the Google wire schema.
1021
1146
  delete requestPayload.providerOptions;
1022
1147
  if (variantConfig?.thinkingLevel && isGemini3) {
1023
1148
  // Gemini 3 native format - use thinkingLevel directly
1024
1149
  const variantModelBase = rawModel
1025
- .replace(/-preview-customtools$/i, "")
1026
- .replace(/-preview$/i, "")
1027
- .replace(/-(minimal|low|medium|high)$/i, "");
1150
+ .replace(/-preview-customtools$/i, '')
1151
+ .replace(/-preview$/i, '')
1152
+ .replace(/-(minimal|low|medium|high)$/i, '');
1028
1153
  const variantResolved = resolveModelForHeaderStyle(`${variantModelBase}-${variantConfig.thinkingLevel}`, headerStyle);
1029
1154
  effectiveModel = variantResolved.actualModel;
1030
1155
  tierThinkingBudget = variantResolved.thinkingBudget;
1031
- tierThinkingLevel = variantResolved.thinkingLevel ?? (variantResolved.thinkingBudget ? undefined : variantConfig.thinkingLevel);
1156
+ tierThinkingLevel =
1157
+ variantResolved.thinkingLevel ??
1158
+ (variantResolved.thinkingBudget
1159
+ ? undefined
1160
+ : variantConfig.thinkingLevel);
1032
1161
  }
1033
1162
  else if (variantConfig?.thinkingBudget) {
1034
1163
  if (isGemini3) {
1035
1164
  // Legacy format for Gemini 3 - convert with deprecation warning
1036
- log.warn("[Deprecated] Using thinkingBudget for Gemini 3 model. Use thinkingLevel instead.");
1037
- tierThinkingLevel = variantConfig.thinkingBudget <= 8192 ? "low"
1038
- : variantConfig.thinkingBudget <= 16384 ? "medium" : "high";
1165
+ log.warn('[Deprecated] Using thinkingBudget for Gemini 3 model. Use thinkingLevel instead.');
1166
+ tierThinkingLevel =
1167
+ variantConfig.thinkingBudget <= 8192
1168
+ ? 'low'
1169
+ : variantConfig.thinkingBudget <= 16384
1170
+ ? 'medium'
1171
+ : 'high';
1039
1172
  tierThinkingBudget = undefined;
1040
1173
  }
1041
1174
  else {
@@ -1047,10 +1180,14 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1047
1180
  // Resolve thinking configuration based on user settings and model capabilities
1048
1181
  // Image generation models don't support thinking - skip thinking config entirely
1049
1182
  const isImageModel = isImageGenerationModel(effectiveModel);
1050
- const userThinkingConfig = isImageModel ? undefined : extractThinkingConfig(requestPayload, rawGenerationConfig, extraBody);
1183
+ const userThinkingConfig = isImageModel
1184
+ ? undefined
1185
+ : extractThinkingConfig(requestPayload, rawGenerationConfig, extraBody);
1051
1186
  const hasAssistantHistory = Array.isArray(requestPayload.contents) &&
1052
- requestPayload.contents.some((c) => c?.role === "model" || c?.role === "assistant");
1053
- const effectiveUserThinkingConfig = isImageModel ? undefined : userThinkingConfig;
1187
+ requestPayload.contents.some((c) => c?.role === 'model' || c?.role === 'assistant');
1188
+ const effectiveUserThinkingConfig = isImageModel
1189
+ ? undefined
1190
+ : userThinkingConfig;
1054
1191
  // For image models, add imageConfig instead of thinkingConfig
1055
1192
  if (isImageModel) {
1056
1193
  const imageConfig = buildImageGenerationConfig();
@@ -1066,11 +1203,26 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1066
1203
  // Add safety settings for image generation (permissive to allow creative content)
1067
1204
  if (!requestPayload.safetySettings) {
1068
1205
  requestPayload.safetySettings = [
1069
- { category: "HARM_CATEGORY_HARASSMENT", threshold: "BLOCK_ONLY_HIGH" },
1070
- { category: "HARM_CATEGORY_HATE_SPEECH", threshold: "BLOCK_ONLY_HIGH" },
1071
- { category: "HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold: "BLOCK_ONLY_HIGH" },
1072
- { category: "HARM_CATEGORY_DANGEROUS_CONTENT", threshold: "BLOCK_ONLY_HIGH" },
1073
- { category: "HARM_CATEGORY_CIVIC_INTEGRITY", threshold: "BLOCK_ONLY_HIGH" },
1206
+ {
1207
+ category: 'HARM_CATEGORY_HARASSMENT',
1208
+ threshold: 'BLOCK_ONLY_HIGH',
1209
+ },
1210
+ {
1211
+ category: 'HARM_CATEGORY_HATE_SPEECH',
1212
+ threshold: 'BLOCK_ONLY_HIGH',
1213
+ },
1214
+ {
1215
+ category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
1216
+ threshold: 'BLOCK_ONLY_HIGH',
1217
+ },
1218
+ {
1219
+ category: 'HARM_CATEGORY_DANGEROUS_CONTENT',
1220
+ threshold: 'BLOCK_ONLY_HIGH',
1221
+ },
1222
+ {
1223
+ category: 'HARM_CATEGORY_CIVIC_INTEGRITY',
1224
+ threshold: 'BLOCK_ONLY_HIGH',
1225
+ },
1074
1226
  ];
1075
1227
  }
1076
1228
  // Image models don't support tools - remove them entirely
@@ -1079,7 +1231,11 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1079
1231
  // Replace system instruction with a simple image generation prompt
1080
1232
  // Image models should not receive agentic coding assistant instructions
1081
1233
  requestPayload.systemInstruction = {
1082
- parts: [{ text: "You are an AI image generator. Generate images based on user descriptions. Focus on creating high-quality, visually appealing images that match the user's request." }]
1234
+ parts: [
1235
+ {
1236
+ text: "You are an AI image generator. Generate images based on user descriptions. Focus on creating high-quality, visually appealing images that match the user's request.",
1237
+ },
1238
+ ],
1083
1239
  };
1084
1240
  }
1085
1241
  else {
@@ -1090,11 +1246,11 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1090
1246
  const thinkingBudget = tierThinkingBudget ?? normalizedThinking.thinkingBudget;
1091
1247
  // Build thinking config based on model type
1092
1248
  let thinkingConfig;
1093
- if (isClaudeThinking && headerStyle !== "antigravity") {
1249
+ if (isClaudeThinking && headerStyle !== 'antigravity') {
1094
1250
  // Claude-on-Gemini fallback uses snake_case keys.
1095
1251
  thinkingConfig = {
1096
1252
  include_thoughts: normalizedThinking.includeThoughts ?? true,
1097
- ...(typeof thinkingBudget === "number" && thinkingBudget > 0
1253
+ ...(typeof thinkingBudget === 'number' && thinkingBudget > 0
1098
1254
  ? { thinking_budget: thinkingBudget }
1099
1255
  : {}),
1100
1256
  };
@@ -1110,19 +1266,25 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1110
1266
  // Gemini 2.5 and others use numeric budget
1111
1267
  thinkingConfig = {
1112
1268
  includeThoughts: normalizedThinking.includeThoughts,
1113
- ...(typeof thinkingBudget === "number" && thinkingBudget > 0 ? { thinkingBudget } : {}),
1269
+ ...(typeof thinkingBudget === 'number' && thinkingBudget > 0
1270
+ ? { thinkingBudget }
1271
+ : {}),
1114
1272
  };
1115
1273
  }
1116
1274
  if (rawGenerationConfig) {
1117
1275
  rawGenerationConfig.thinkingConfig = thinkingConfig;
1118
1276
  applyAgyGenerationDefaults(effectiveModel, rawGenerationConfig, headerStyle);
1119
- if (isClaudeThinking && typeof thinkingBudget === "number" && thinkingBudget > 0) {
1120
- const currentMax = (rawGenerationConfig.maxOutputTokens ?? rawGenerationConfig.max_output_tokens);
1121
- if (headerStyle === "antigravity" && !currentMax) {
1277
+ if (isClaudeThinking &&
1278
+ typeof thinkingBudget === 'number' &&
1279
+ thinkingBudget > 0) {
1280
+ const currentMax = (rawGenerationConfig.maxOutputTokens ??
1281
+ rawGenerationConfig.max_output_tokens);
1282
+ if (headerStyle === 'antigravity' && !currentMax) {
1122
1283
  rawGenerationConfig.maxOutputTokens = 64000;
1123
1284
  }
1124
1285
  else if (!currentMax || currentMax <= thinkingBudget) {
1125
- rawGenerationConfig.maxOutputTokens = computeClaudeMaxOutputTokens(thinkingBudget);
1286
+ rawGenerationConfig.maxOutputTokens =
1287
+ computeClaudeMaxOutputTokens(thinkingBudget);
1126
1288
  }
1127
1289
  if (rawGenerationConfig.max_output_tokens !== undefined) {
1128
1290
  delete rawGenerationConfig.max_output_tokens;
@@ -1131,11 +1293,16 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1131
1293
  requestPayload.generationConfig = rawGenerationConfig;
1132
1294
  }
1133
1295
  else {
1134
- const generationConfig = { thinkingConfig };
1135
- if (isClaudeThinking && typeof thinkingBudget === "number" && thinkingBudget > 0) {
1136
- generationConfig.maxOutputTokens = headerStyle === "antigravity"
1137
- ? 64000
1138
- : computeClaudeMaxOutputTokens(thinkingBudget);
1296
+ const generationConfig = {
1297
+ thinkingConfig,
1298
+ };
1299
+ if (isClaudeThinking &&
1300
+ typeof thinkingBudget === 'number' &&
1301
+ thinkingBudget > 0) {
1302
+ generationConfig.maxOutputTokens =
1303
+ headerStyle === 'antigravity'
1304
+ ? 64000
1305
+ : computeClaudeMaxOutputTokens(thinkingBudget);
1139
1306
  }
1140
1307
  applyAgyGenerationDefaults(effectiveModel, generationConfig, headerStyle);
1141
1308
  requestPayload.generationConfig = generationConfig;
@@ -1158,17 +1325,20 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1158
1325
  }
1159
1326
  delete requestPayload.thinkingConfig;
1160
1327
  delete requestPayload.thinking;
1161
- if ("system_instruction" in requestPayload) {
1328
+ if ('system_instruction' in requestPayload) {
1162
1329
  requestPayload.systemInstruction = requestPayload.system_instruction;
1163
1330
  delete requestPayload.system_instruction;
1164
1331
  }
1165
- if (headerStyle !== "antigravity") {
1332
+ if (headerStyle !== 'antigravity') {
1166
1333
  // Gemini CLI accepts explicit cachedContent references. Normalize its
1167
1334
  // snake_case aliases only on that transport; agy relies on implicit
1168
1335
  // prefix caching and does not send any of these fields.
1169
- const cachedContentFromExtra = typeof requestPayload.extra_body === "object" && requestPayload.extra_body
1170
- ? requestPayload.extra_body.cached_content ??
1171
- requestPayload.extra_body.cachedContent
1336
+ const cachedContentFromExtra = typeof requestPayload.extra_body === 'object' &&
1337
+ requestPayload.extra_body
1338
+ ? (requestPayload.extra_body
1339
+ .cached_content ??
1340
+ requestPayload.extra_body
1341
+ .cachedContent)
1172
1342
  : undefined;
1173
1343
  const cachedContent = requestPayload.cached_content ??
1174
1344
  requestPayload.cachedContent ??
@@ -1177,10 +1347,14 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1177
1347
  requestPayload.cachedContent = cachedContent;
1178
1348
  }
1179
1349
  delete requestPayload.cached_content;
1180
- if (requestPayload.extra_body && typeof requestPayload.extra_body === "object") {
1181
- delete requestPayload.extra_body.cached_content;
1182
- delete requestPayload.extra_body.cachedContent;
1183
- if (Object.keys(requestPayload.extra_body).length === 0) {
1350
+ if (requestPayload.extra_body &&
1351
+ typeof requestPayload.extra_body === 'object') {
1352
+ delete requestPayload.extra_body
1353
+ .cached_content;
1354
+ delete requestPayload.extra_body
1355
+ .cachedContent;
1356
+ if (Object.keys(requestPayload.extra_body)
1357
+ .length === 0) {
1184
1358
  delete requestPayload.extra_body;
1185
1359
  }
1186
1360
  }
@@ -1194,39 +1368,46 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1194
1368
  const normalizeSchema = (schema) => {
1195
1369
  const createPlaceholderSchema = (base = {}) => ({
1196
1370
  ...base,
1197
- type: "object",
1371
+ type: 'object',
1198
1372
  properties: {
1199
1373
  [EMPTY_SCHEMA_PLACEHOLDER_NAME]: {
1200
- type: "boolean",
1374
+ type: 'boolean',
1201
1375
  description: EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION,
1202
1376
  },
1203
1377
  },
1204
1378
  required: [EMPTY_SCHEMA_PLACEHOLDER_NAME],
1205
1379
  });
1206
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
1380
+ if (!schema ||
1381
+ typeof schema !== 'object' ||
1382
+ Array.isArray(schema)) {
1207
1383
  toolDebugMissing += 1;
1208
1384
  return createPlaceholderSchema();
1209
1385
  }
1210
1386
  const cleaned = cleanJSONSchemaForAntigravity(schema);
1211
- if (!cleaned || typeof cleaned !== "object" || Array.isArray(cleaned)) {
1387
+ if (!cleaned ||
1388
+ typeof cleaned !== 'object' ||
1389
+ Array.isArray(cleaned)) {
1212
1390
  toolDebugMissing += 1;
1213
1391
  return createPlaceholderSchema();
1214
1392
  }
1215
1393
  // Claude VALIDATED mode requires tool parameters to be an object schema
1216
1394
  // with at least one property.
1217
1395
  const hasProperties = cleaned.properties &&
1218
- typeof cleaned.properties === "object" &&
1396
+ typeof cleaned.properties === 'object' &&
1219
1397
  Object.keys(cleaned.properties).length > 0;
1220
- cleaned.type = "object";
1398
+ cleaned.type = 'object';
1221
1399
  if (!hasProperties) {
1222
1400
  cleaned.properties = {
1223
1401
  [EMPTY_SCHEMA_PLACEHOLDER_NAME]: {
1224
- type: "boolean",
1402
+ type: 'boolean',
1225
1403
  description: EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION,
1226
1404
  },
1227
1405
  };
1228
1406
  cleaned.required = Array.isArray(cleaned.required)
1229
- ? Array.from(new Set([...cleaned.required, EMPTY_SCHEMA_PLACEHOLDER_NAME]))
1407
+ ? Array.from(new Set([
1408
+ ...cleaned.required,
1409
+ EMPTY_SCHEMA_PLACEHOLDER_NAME,
1410
+ ]))
1230
1411
  : [EMPTY_SCHEMA_PLACEHOLDER_NAME];
1231
1412
  }
1232
1413
  return cleaned;
@@ -1254,21 +1435,26 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1254
1435
  tool.custom?.name ||
1255
1436
  `tool-${functionDeclarations.length}`;
1256
1437
  // Sanitize tool name: must be alphanumeric with underscores, no special chars
1257
- name = String(name).replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
1438
+ name = String(name)
1439
+ .replace(/[^a-zA-Z0-9_-]/g, '_')
1440
+ .slice(0, 64);
1258
1441
  const description = decl?.description ||
1259
1442
  tool.description ||
1260
1443
  tool.function?.description ||
1261
1444
  tool.custom?.description ||
1262
- "";
1445
+ '';
1263
1446
  functionDeclarations.push({
1264
1447
  name,
1265
- description: String(description || ""),
1448
+ description: String(description || ''),
1266
1449
  parameters: normalizeSchema(schema),
1267
1450
  });
1268
- toolDebugSummaries.push(`decl=${name},src=${source},hasSchema=${schema ? "y" : "n"}`);
1451
+ toolDebugSummaries.push(`decl=${name},src=${source},hasSchema=${schema ? 'y' : 'n'}`);
1269
1452
  };
1270
- if (Array.isArray(tool.functionDeclarations) && tool.functionDeclarations.length > 0) {
1271
- tool.functionDeclarations.forEach((decl) => pushDeclaration(decl, "functionDeclarations"));
1453
+ if (Array.isArray(tool.functionDeclarations) &&
1454
+ tool.functionDeclarations.length > 0) {
1455
+ tool.functionDeclarations.forEach((decl) => {
1456
+ pushDeclaration(decl, 'functionDeclarations');
1457
+ });
1272
1458
  return;
1273
1459
  }
1274
1460
  // Fall back to function/custom style definitions.
@@ -1277,7 +1463,7 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1277
1463
  tool.parameters ||
1278
1464
  tool.input_schema ||
1279
1465
  tool.inputSchema) {
1280
- pushDeclaration(tool.function ?? tool.custom ?? tool, "function/custom");
1466
+ pushDeclaration(tool.function ?? tool.custom ?? tool, 'function/custom');
1281
1467
  return;
1282
1468
  }
1283
1469
  // Preserve any non-function tool entries (e.g., codeExecution) untouched.
@@ -1310,7 +1496,10 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1310
1496
  // Injects parameter signatures into descriptions and adds system instruction
1311
1497
  // Can be disabled via config.claude_tool_hardening = false to reduce context size
1312
1498
  const enableToolHardening = options?.claudeToolHardening ?? true;
1313
- if (enableToolHardening && isClaude && Array.isArray(requestPayload.tools) && requestPayload.tools.length > 0) {
1499
+ if (enableToolHardening &&
1500
+ isClaude &&
1501
+ Array.isArray(requestPayload.tools) &&
1502
+ requestPayload.tools.length > 0) {
1314
1503
  // Inject parameter signatures into tool descriptions
1315
1504
  requestPayload.tools = injectParameterSignatures(requestPayload.tools, CLAUDE_DESCRIPTION_PROMPT);
1316
1505
  // Inject tool hardening system instruction
@@ -1319,7 +1508,9 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1319
1508
  // Append interleaved thinking hint for Claude thinking models with tools.
1320
1509
  // Must come AFTER tool hardening so it is the last system instruction part,
1321
1510
  // preserving the stable prefix for prompt cache matching.
1322
- if (isClaudeThinking && Array.isArray(requestPayload.tools) && requestPayload.tools.length > 0) {
1511
+ if (isClaudeThinking &&
1512
+ Array.isArray(requestPayload.tools) &&
1513
+ requestPayload.tools.length > 0) {
1323
1514
  appendClaudeThinkingHint(requestPayload);
1324
1515
  }
1325
1516
  }
@@ -1330,24 +1521,35 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1330
1521
  // Handle both Gemini-style contents[] and Anthropic-style messages[] payloads.
1331
1522
  if (isClaude) {
1332
1523
  // Step 0: Sanitize cross-model metadata (strips Gemini signatures when sending to Claude)
1333
- sanitizeCrossModelPayloadInPlace(requestPayload, { targetModel: effectiveModel });
1524
+ sanitizeCrossModelPayloadInPlace(requestPayload, {
1525
+ targetModel: effectiveModel,
1526
+ });
1334
1527
  // Step 1: Strip corrupted/unsigned thinking blocks FIRST
1335
1528
  deepFilterThinkingBlocks(requestPayload, signatureSessionKey, getCachedSignature, true);
1336
1529
  // Step 2: THEN inject signed thinking from cache (after stripping)
1337
- if (isClaudeThinking && keepThinkingEnabled && Array.isArray(requestPayload.contents)) {
1530
+ if (isClaudeThinking &&
1531
+ keepThinkingEnabled &&
1532
+ Array.isArray(requestPayload.contents)) {
1338
1533
  requestPayload.contents = ensureThinkingBeforeToolUseInContents(requestPayload.contents, signatureSessionKey);
1339
1534
  }
1340
- if (isClaudeThinking && keepThinkingEnabled && Array.isArray(requestPayload.messages)) {
1535
+ if (isClaudeThinking &&
1536
+ keepThinkingEnabled &&
1537
+ Array.isArray(requestPayload.messages)) {
1341
1538
  requestPayload.messages = ensureThinkingBeforeToolUseInMessages(requestPayload.messages, signatureSessionKey);
1342
1539
  }
1343
1540
  // Step 3: Check if warmup needed (AFTER injection attempt)
1344
1541
  if (isClaudeThinking && keepThinkingEnabled) {
1345
- const hasToolUse = (Array.isArray(requestPayload.contents) && hasToolUseInContents(requestPayload.contents)) ||
1346
- (Array.isArray(requestPayload.messages) && hasToolUseInMessages(requestPayload.messages));
1347
- const hasSignedThinking = (Array.isArray(requestPayload.contents) && hasSignedThinkingInContents(requestPayload.contents, signatureSessionKey)) ||
1348
- (Array.isArray(requestPayload.messages) && hasSignedThinkingInMessages(requestPayload.messages, signatureSessionKey));
1542
+ const hasToolUse = (Array.isArray(requestPayload.contents) &&
1543
+ hasToolUseInContents(requestPayload.contents)) ||
1544
+ (Array.isArray(requestPayload.messages) &&
1545
+ hasToolUseInMessages(requestPayload.messages));
1546
+ const hasSignedThinking = (Array.isArray(requestPayload.contents) &&
1547
+ hasSignedThinkingInContents(requestPayload.contents, signatureSessionKey)) ||
1548
+ (Array.isArray(requestPayload.messages) &&
1549
+ hasSignedThinkingInMessages(requestPayload.messages, signatureSessionKey));
1349
1550
  const hasCachedThinking = defaultSignatureStore.has(signatureSessionKey);
1350
- needsSignedThinkingWarmup = hasToolUse && !hasSignedThinking && !hasCachedThinking;
1551
+ needsSignedThinkingWarmup =
1552
+ hasToolUse && !hasSignedThinking && !hasCachedThinking;
1351
1553
  }
1352
1554
  }
1353
1555
  // For Claude models, ensure functionCall/tool use parts carry IDs (required by Anthropic).
@@ -1363,12 +1565,14 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1363
1565
  return content;
1364
1566
  }
1365
1567
  const newParts = content.parts.map((part) => {
1366
- if (part && typeof part === "object" && part.functionCall) {
1568
+ if (part && typeof part === 'object' && part.functionCall) {
1367
1569
  const call = { ...part.functionCall };
1368
1570
  if (!call.id) {
1369
1571
  call.id = `tool-call-${++toolCallCounter}`;
1370
1572
  }
1371
- const nameKey = typeof call.name === "string" ? call.name : `tool-${toolCallCounter}`;
1573
+ const nameKey = typeof call.name === 'string'
1574
+ ? call.name
1575
+ : `tool-${toolCallCounter}`;
1372
1576
  // Push to the queue for this function name
1373
1577
  const queue = pendingCallIdsByName.get(nameKey) || [];
1374
1578
  queue.push(call.id);
@@ -1385,9 +1589,9 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1385
1589
  return content;
1386
1590
  }
1387
1591
  const newParts = content.parts.map((part) => {
1388
- if (part && typeof part === "object" && part.functionResponse) {
1592
+ if (part && typeof part === 'object' && part.functionResponse) {
1389
1593
  const resp = { ...part.functionResponse };
1390
- if (!resp.id && typeof resp.name === "string") {
1594
+ if (!resp.id && typeof resp.name === 'string') {
1391
1595
  const queue = pendingCallIdsByName.get(resp.name);
1392
1596
  if (queue && queue.length > 0) {
1393
1597
  // Consume the first pending ID (FIFO order)
@@ -1431,38 +1635,49 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1431
1635
  const conversationState = analyzeConversationState(requestPayload.contents);
1432
1636
  // Force recovery if API returned thinking_block_order error (retry case)
1433
1637
  // or if proactive check detects we need recovery
1434
- if (forceThinkingRecovery || needsThinkingRecovery(conversationState)) {
1638
+ if (forceThinkingRecovery ||
1639
+ needsThinkingRecovery(conversationState)) {
1435
1640
  // Set message for toast notification (shown in plugin.ts, respects quiet mode)
1436
1641
  thinkingRecoveryMessage = forceThinkingRecovery
1437
- ? "Thinking recovery: retrying with fresh turn (API error)"
1438
- : "Thinking recovery: restarting turn (corrupted context)";
1642
+ ? 'Thinking recovery: retrying with fresh turn (API error)'
1643
+ : 'Thinking recovery: restarting turn (corrupted context)';
1439
1644
  requestPayload.contents = closeToolLoopForThinking(requestPayload.contents);
1440
1645
  defaultSignatureStore.delete(signatureSessionKey);
1441
1646
  }
1442
1647
  }
1443
- // Guard against assistant prefill: Claude rejects conversations ending
1444
- // with model/assistant messages. After context compaction, the conversation
1445
- // can end with a model message — append synthetic user message to fix.
1446
- if (isClaude) {
1648
+ // AGY rejects every request that ends with a model turn. Enforce this at
1649
+ // the final wire boundary because host races, recovery, or sanitization can
1650
+ // otherwise leave a model/assistant entry last. Claude fallback transports
1651
+ // have the same assistant-prefill restriction.
1652
+ if (headerStyle === 'antigravity' || isClaude) {
1447
1653
  if (Array.isArray(requestPayload.contents)) {
1448
1654
  const lastContent = requestPayload.contents[requestPayload.contents.length - 1];
1449
- if (lastContent?.role === "model" || lastContent?.role === "assistant") {
1450
- requestPayload.contents.push({ role: "user", parts: [{ text: "[Continue]" }] });
1655
+ if (lastContent?.role === 'model' ||
1656
+ lastContent?.role === 'assistant') {
1657
+ requestPayload.contents.push({
1658
+ role: 'user',
1659
+ parts: [{ text: '[Continue]' }],
1660
+ });
1451
1661
  }
1452
1662
  }
1453
1663
  if (Array.isArray(requestPayload.messages)) {
1454
1664
  const lastMessage = requestPayload.messages[requestPayload.messages.length - 1];
1455
- if (lastMessage?.role === "model" || lastMessage?.role === "assistant") {
1456
- requestPayload.messages.push({ role: "user", parts: [{ text: "[Continue]" }] });
1665
+ if (lastMessage?.role === 'model' ||
1666
+ lastMessage?.role === 'assistant') {
1667
+ ;
1668
+ requestPayload.messages.push({
1669
+ role: 'user',
1670
+ parts: [{ text: '[Continue]' }],
1671
+ });
1457
1672
  }
1458
1673
  }
1459
1674
  }
1460
- if ("model" in requestPayload) {
1675
+ if ('model' in requestPayload) {
1461
1676
  delete requestPayload.model;
1462
1677
  }
1463
1678
  stripInjectedDebugFromRequestPayload(requestPayload);
1464
1679
  sanitizeRequestPayloadForAntigravity(requestPayload);
1465
- if (headerStyle === "antigravity") {
1680
+ if (headerStyle === 'antigravity') {
1466
1681
  stripUnsupportedAntigravityFields(requestPayload);
1467
1682
  configureAntigravityToolCalling(requestPayload);
1468
1683
  }
@@ -1470,11 +1685,12 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1470
1685
  // a fresh random project each request busts the prompt cache and
1471
1686
  // fragments server-side quota/session state. ensureProjectContext
1472
1687
  // already floors empty cases to this default; this is defense in depth.
1473
- const effectiveProjectId = projectId?.trim() || (headerStyle === "antigravity" ? ANTIGRAVITY_DEFAULT_PROJECT_ID : "");
1688
+ const effectiveProjectId = projectId?.trim() ||
1689
+ (headerStyle === 'antigravity' ? ANTIGRAVITY_DEFAULT_PROJECT_ID : '');
1474
1690
  resolvedProjectId = effectiveProjectId;
1475
1691
  // Keep internal signature-cache identity separate from AGY wire session metadata.
1476
1692
  sessionId = signatureSessionKey;
1477
- const agyMetadata = headerStyle === "antigravity"
1693
+ const agyMetadata = headerStyle === 'antigravity'
1478
1694
  ? buildAgyAgentRequestMetadata(options?.agySession ?? DEFAULT_AGY_REQUEST_SESSION, requestPayload, effectiveModel, options?.agyRequestTimestamp)
1479
1695
  : null;
1480
1696
  requestPayload.sessionId = agyMetadata?.sessionId ?? signatureSessionKey;
@@ -1482,25 +1698,27 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1482
1698
  requestPayload.labels = agyMetadata.labels;
1483
1699
  orderAgyRequestPayloadInPlace(requestPayload);
1484
1700
  }
1485
- const wrappedBody = headerStyle === "antigravity"
1701
+ const wrappedBody = headerStyle === 'antigravity'
1486
1702
  ? {
1487
1703
  project: effectiveProjectId,
1488
- requestId: agyMetadata.requestId,
1704
+ requestId: agyMetadata?.requestId,
1489
1705
  request: requestPayload,
1490
1706
  model: effectiveModel,
1491
- userAgent: "antigravity",
1492
- requestType: "agent",
1707
+ userAgent: 'antigravity',
1708
+ requestType: 'agent',
1493
1709
  }
1494
1710
  : {
1495
1711
  project: effectiveProjectId,
1496
1712
  model: effectiveModel,
1497
1713
  request: requestPayload,
1498
1714
  };
1499
- body = safeStringify(headerStyle === "antigravity" ? orderAntigravityEnvelope(wrappedBody) : wrappedBody);
1715
+ body = safeStringify(headerStyle === 'antigravity'
1716
+ ? orderAntigravityEnvelope(wrappedBody)
1717
+ : wrappedBody);
1500
1718
  }
1501
1719
  }
1502
1720
  catch {
1503
- throw new Error("Failed to build Antigravity request body");
1721
+ throw new Error('Failed to build Antigravity request body');
1504
1722
  }
1505
1723
  }
1506
1724
  // agy CLI does not send an Accept header on streamGenerateContent requests.
@@ -1508,36 +1726,36 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1508
1726
  // Add interleaved thinking header for Claude thinking models
1509
1727
  // This enables real-time streaming of thinking tokens
1510
1728
  if (isClaudeThinking) {
1511
- const existing = headers.get("anthropic-beta");
1512
- const interleavedHeader = "interleaved-thinking-2025-05-14";
1729
+ const existing = headers.get('anthropic-beta');
1730
+ const interleavedHeader = 'interleaved-thinking-2025-05-14';
1513
1731
  if (existing) {
1514
1732
  if (!existing.includes(interleavedHeader)) {
1515
- headers.set("anthropic-beta", `${existing},${interleavedHeader}`);
1733
+ headers.set('anthropic-beta', `${existing},${interleavedHeader}`);
1516
1734
  }
1517
1735
  }
1518
1736
  else {
1519
- headers.set("anthropic-beta", interleavedHeader);
1737
+ headers.set('anthropic-beta', interleavedHeader);
1520
1738
  }
1521
1739
  }
1522
- if (headerStyle === "antigravity") {
1740
+ if (headerStyle === 'antigravity') {
1523
1741
  // Use randomized headers as the fallback pool for Antigravity mode
1524
- const selectedHeaders = getRandomizedHeaders("antigravity", requestedModel);
1742
+ const selectedHeaders = getRandomizedHeaders('antigravity', requestedModel);
1525
1743
  // Antigravity mode: Match Antigravity Manager behavior
1526
1744
  // AM only sends User-Agent on content requests — no X-Goog-Api-Client, no Client-Metadata header
1527
1745
  // (ideType=ANTIGRAVITY goes in request body metadata via project.ts, not as a header)
1528
1746
  const fingerprint = options?.fingerprint ?? getSessionFingerprint();
1529
1747
  const fingerprintHeaders = buildFingerprintHeaders(fingerprint);
1530
- headers.set("User-Agent", fingerprintHeaders["User-Agent"] || selectedHeaders["User-Agent"]);
1531
- headers.set("Accept-Encoding", "gzip");
1748
+ headers.set('User-Agent', fingerprintHeaders['User-Agent'] || selectedHeaders['User-Agent']);
1749
+ headers.set('Accept-Encoding', 'gzip');
1532
1750
  }
1533
1751
  else {
1534
1752
  // Gemini CLI mode: match official google-gemini/gemini-cli User-Agent format
1535
- const geminiCliHeaders = getRandomizedHeaders("gemini-cli", requestedModel);
1536
- headers.set("User-Agent", geminiCliHeaders["User-Agent"]);
1537
- if (geminiCliHeaders["X-Goog-Api-Client"])
1538
- headers.set("X-Goog-Api-Client", geminiCliHeaders["X-Goog-Api-Client"]);
1539
- if (geminiCliHeaders["Client-Metadata"])
1540
- headers.set("Client-Metadata", geminiCliHeaders["Client-Metadata"]);
1753
+ const geminiCliHeaders = getRandomizedHeaders('gemini-cli', requestedModel);
1754
+ headers.set('User-Agent', geminiCliHeaders['User-Agent']);
1755
+ if (geminiCliHeaders['X-Goog-Api-Client'])
1756
+ headers.set('X-Goog-Api-Client', geminiCliHeaders['X-Goog-Api-Client']);
1757
+ if (geminiCliHeaders['Client-Metadata'])
1758
+ headers.set('Client-Metadata', geminiCliHeaders['Client-Metadata']);
1541
1759
  }
1542
1760
  return {
1543
1761
  request: transformedUrl,
@@ -1553,7 +1771,7 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
1553
1771
  endpoint: transformedUrl,
1554
1772
  sessionId,
1555
1773
  toolDebugMissing,
1556
- toolDebugSummary: toolDebugSummaries.slice(0, 20).join(" | "),
1774
+ toolDebugSummary: toolDebugSummaries.slice(0, 20).join(' | '),
1557
1775
  toolDebugPayload,
1558
1776
  needsSignedThinkingWarmup,
1559
1777
  headerStyle,
@@ -1571,11 +1789,11 @@ export function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
1571
1789
  catch {
1572
1790
  return null;
1573
1791
  }
1574
- const warmupPrompt = "Warmup request for thinking signature.";
1575
- const wireModel = typeof parsed.model === "string" ? parsed.model : "claude-sonnet-4-6";
1792
+ const warmupPrompt = 'Warmup request for thinking signature.';
1793
+ const wireModel = typeof parsed.model === 'string' ? parsed.model : 'claude-sonnet-4-6';
1576
1794
  const requestObjects = [];
1577
1795
  const updateRequest = (req) => {
1578
- req.contents = [{ role: "user", parts: [{ text: warmupPrompt }] }];
1796
+ req.contents = [{ role: 'user', parts: [{ text: warmupPrompt }] }];
1579
1797
  delete req.tools;
1580
1798
  delete req.toolConfig;
1581
1799
  const generationConfig = (req.generationConfig ?? {});
@@ -1583,15 +1801,16 @@ export function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
1583
1801
  includeThoughts: true,
1584
1802
  thinkingBudget: AGY_CLAUDE_THINKING_BUDGET,
1585
1803
  };
1586
- generationConfig.maxOutputTokens = getAgyMaxOutputTokens(wireModel) ??
1587
- computeClaudeMaxOutputTokens(AGY_CLAUDE_THINKING_BUDGET);
1804
+ generationConfig.maxOutputTokens =
1805
+ getAgyMaxOutputTokens(wireModel) ??
1806
+ computeClaudeMaxOutputTokens(AGY_CLAUDE_THINKING_BUDGET);
1588
1807
  req.generationConfig = generationConfig;
1589
1808
  requestObjects.push(req);
1590
1809
  };
1591
- if (parsed.request && typeof parsed.request === "object") {
1810
+ if (parsed.request && typeof parsed.request === 'object') {
1592
1811
  updateRequest(parsed.request);
1593
1812
  const nested = parsed.request.request;
1594
- if (nested && typeof nested === "object") {
1813
+ if (nested && typeof nested === 'object') {
1595
1814
  updateRequest(nested);
1596
1815
  }
1597
1816
  }
@@ -1600,7 +1819,7 @@ export function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
1600
1819
  }
1601
1820
  const wireRequest = requestObjects.at(-1);
1602
1821
  if (wireRequest) {
1603
- const numericSessionId = typeof wireRequest.sessionId === "string"
1822
+ const numericSessionId = typeof wireRequest.sessionId === 'string'
1604
1823
  ? wireRequest.sessionId
1605
1824
  : DEFAULT_AGY_REQUEST_SESSION.numericSessionId;
1606
1825
  const warmupSession = {
@@ -1624,9 +1843,9 @@ export function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
1624
1843
  * Thinking/reasoning tokens are transformed and forwarded immediately as they arrive.
1625
1844
  */
1626
1845
  export async function transformAntigravityResponse(response, streaming, debugContext, requestedModel, projectId, endpoint, effectiveModel, sessionId, toolDebugMissing, toolDebugSummary, toolDebugPayload, debugLines, dumpContext) {
1627
- const contentType = response.headers.get("content-type") ?? "";
1628
- const isJsonResponse = contentType.includes("application/json");
1629
- const isEventStreamResponse = contentType.includes("text/event-stream");
1846
+ const contentType = response.headers.get('content-type') ?? '';
1847
+ const isJsonResponse = contentType.includes('application/json');
1848
+ const isEventStreamResponse = contentType.includes('text/event-stream');
1630
1849
  // Generate text for thinking injection:
1631
1850
  // - If debug=true: inject full debug logs
1632
1851
  // - If keep_thinking=true (but no debug): inject placeholder to trigger signature caching
@@ -1639,7 +1858,7 @@ export async function transformAntigravityResponse(response, streaming, debugCon
1639
1858
  const cacheSignatures = shouldCacheThinkingSignatures(effectiveModel);
1640
1859
  if (!isJsonResponse && !isEventStreamResponse) {
1641
1860
  logAntigravityDebugResponse(debugContext, response, {
1642
- note: "Non-JSON response (body omitted)",
1861
+ note: 'Non-JSON response (body omitted)',
1643
1862
  });
1644
1863
  return response;
1645
1864
  }
@@ -1649,11 +1868,13 @@ export async function transformAntigravityResponse(response, streaming, debugCon
1649
1868
  if (streaming && response.ok && isEventStreamResponse && response.body) {
1650
1869
  const headers = new Headers(response.headers);
1651
1870
  logAntigravityDebugResponse(debugContext, response, {
1652
- note: "Streaming SSE response (real-time transform)",
1871
+ note: 'Streaming SSE response (real-time transform)',
1653
1872
  });
1654
1873
  noteGeminiDumpResponse(dumpContext, response);
1655
1874
  const rawDumpTransformer = createGeminiDumpResponseTransform(dumpContext);
1656
- const sourceBody = rawDumpTransformer ? response.body.pipeThrough(rawDumpTransformer) : response.body;
1875
+ const sourceBody = rawDumpTransformer
1876
+ ? response.body.pipeThrough(rawDumpTransformer)
1877
+ : response.body;
1657
1878
  const streamingTransformer = createStreamingTransformer(defaultSignatureStore, {
1658
1879
  onCacheSignature: cacheSignature,
1659
1880
  onInjectDebug: injectDebugThinking,
@@ -1662,10 +1883,15 @@ export async function transformAntigravityResponse(response, streaming, debugCon
1662
1883
  const cacheRead = usage.cachedContentTokenCount;
1663
1884
  const totalInput = usage.promptTokenCount ?? usage.totalTokenCount;
1664
1885
  const hitRate = totalInput > 0 ? Math.round((cacheRead / totalInput) * 100) : 0;
1665
- const status = cacheRead > 0 ? "HIT" : "MISS";
1886
+ const status = cacheRead > 0 ? 'HIT' : 'MISS';
1666
1887
  logCacheStats(effectiveModel, cacheRead, 0, totalInput);
1667
1888
  log.debug(`[Cache] ${status} model=${effectiveModel} read=${cacheRead} total=${totalInput} hitRate=${hitRate}%`);
1668
- _lastCacheStats = { model: effectiveModel, read: cacheRead, total: totalInput, hitRate };
1889
+ _lastCacheStats = {
1890
+ model: effectiveModel,
1891
+ read: cacheRead,
1892
+ total: totalInput,
1893
+ hitRate,
1894
+ };
1669
1895
  }
1670
1896
  },
1671
1897
  transformThinkingParts,
@@ -1673,7 +1899,9 @@ export async function transformAntigravityResponse(response, streaming, debugCon
1673
1899
  signatureSessionKey: sessionId,
1674
1900
  debugText,
1675
1901
  cacheSignatures,
1676
- displayedThinkingHashes: effectiveModel && isGemini3Model(effectiveModel) ? sessionDisplayedThinkingHashes : undefined,
1902
+ displayedThinkingHashes: effectiveModel && isGemini3Model(effectiveModel)
1903
+ ? sessionDisplayedThinkingHashes
1904
+ : undefined,
1677
1905
  // injectSyntheticThinking removed - keep_thinking now unified with debug via debugText
1678
1906
  });
1679
1907
  return new Response(sourceBody.pipeThrough(streamingTransformer), {
@@ -1698,48 +1926,50 @@ export async function transformAntigravityResponse(response, streaming, debugCon
1698
1926
  }
1699
1927
  // Inject Debug Info
1700
1928
  if (errorBody?.error) {
1701
- const rawErrorMessage = typeof errorBody.error.message === "string" && errorBody.error.message.length > 0
1929
+ const rawErrorMessage = typeof errorBody.error.message === 'string' &&
1930
+ errorBody.error.message.length > 0
1702
1931
  ? errorBody.error.message
1703
- : "Unknown error";
1932
+ : 'Unknown error';
1704
1933
  const errorType = detectErrorType(rawErrorMessage);
1705
- const debugInfo = `\n\n[Debug Info]\nRequested Model: ${requestedModel || "Unknown"}\nEffective Model: ${effectiveModel || "Unknown"}\nProject: ${projectId || "Unknown"}\nEndpoint: ${endpoint || "Unknown"}\nStatus: ${response.status}\nRequest ID: ${headers.get("x-request-id") || "N/A"}${toolDebugMissing !== undefined ? `\nTool Debug Missing: ${toolDebugMissing}` : ""}${toolDebugSummary ? `\nTool Debug Summary: ${toolDebugSummary}` : ""}${toolDebugPayload ? `\nTool Debug Payload: ${toolDebugPayload}` : ""}`;
1706
- const injectedDebug = debugText ? `\n\n${debugText}` : "";
1934
+ const debugInfo = `\n\n[Debug Info]\nRequested Model: ${requestedModel || 'Unknown'}\nEffective Model: ${effectiveModel || 'Unknown'}\nProject: ${projectId || 'Unknown'}\nEndpoint: ${endpoint || 'Unknown'}\nStatus: ${response.status}\nRequest ID: ${headers.get('x-request-id') || 'N/A'}${toolDebugMissing !== undefined ? `\nTool Debug Missing: ${toolDebugMissing}` : ''}${toolDebugSummary ? `\nTool Debug Summary: ${toolDebugSummary}` : ''}${toolDebugPayload ? `\nTool Debug Payload: ${toolDebugPayload}` : ''}`;
1935
+ const injectedDebug = debugText ? `\n\n${debugText}` : '';
1707
1936
  errorBody.error.message = rawErrorMessage + debugInfo + injectedDebug;
1708
1937
  // Check if this is a recoverable thinking error - throw to trigger retry
1709
- if (errorType === "thinking_block_order") {
1710
- const recoveryError = new Error("THINKING_RECOVERY_NEEDED");
1938
+ if (errorType === 'thinking_block_order') {
1939
+ const recoveryError = new Error('THINKING_RECOVERY_NEEDED');
1711
1940
  recoveryError.recoveryType = errorType;
1712
1941
  recoveryError.originalError = errorBody;
1713
1942
  recoveryError.debugInfo = debugInfo;
1714
1943
  throw recoveryError;
1715
1944
  }
1716
1945
  // Detect context length / prompt too long errors - signal to caller for toast
1717
- const errorMessage = errorBody.error.message?.toLowerCase() || "";
1718
- if (errorMessage.includes("prompt is too long") ||
1719
- errorMessage.includes("context length exceeded") ||
1720
- errorMessage.includes("context_length_exceeded") ||
1721
- errorMessage.includes("maximum context length")) {
1722
- headers.set("x-antigravity-context-error", "prompt_too_long");
1946
+ const errorMessage = errorBody.error.message?.toLowerCase() || '';
1947
+ if (errorMessage.includes('prompt is too long') ||
1948
+ errorMessage.includes('context length exceeded') ||
1949
+ errorMessage.includes('context_length_exceeded') ||
1950
+ errorMessage.includes('maximum context length')) {
1951
+ headers.set('x-antigravity-context-error', 'prompt_too_long');
1723
1952
  }
1724
1953
  // Detect tool pairing errors - signal to caller for toast
1725
- if (errorMessage.includes("tool_use") &&
1726
- errorMessage.includes("tool_result") &&
1727
- (errorMessage.includes("without") || errorMessage.includes("immediately after"))) {
1728
- headers.set("x-antigravity-context-error", "tool_pairing");
1954
+ if (errorMessage.includes('tool_use') &&
1955
+ errorMessage.includes('tool_result') &&
1956
+ (errorMessage.includes('without') ||
1957
+ errorMessage.includes('immediately after'))) {
1958
+ headers.set('x-antigravity-context-error', 'tool_pairing');
1729
1959
  }
1730
1960
  return new Response(JSON.stringify(errorBody), {
1731
1961
  status: response.status,
1732
1962
  statusText: response.statusText,
1733
- headers
1963
+ headers,
1734
1964
  });
1735
1965
  }
1736
1966
  if (errorBody?.error?.details && Array.isArray(errorBody.error.details)) {
1737
1967
  const retryInfo = errorBody.error.details.find((detail) => detail['@type'] === 'type.googleapis.com/google.rpc.RetryInfo');
1738
1968
  if (retryInfo?.retryDelay) {
1739
1969
  const match = retryInfo.retryDelay.match(/^([\d.]+)s$/);
1740
- if (match && match[1]) {
1970
+ if (match?.[1]) {
1741
1971
  const retrySeconds = parseFloat(match[1]);
1742
- if (!isNaN(retrySeconds) && retrySeconds > 0) {
1972
+ if (!Number.isNaN(retrySeconds) && retrySeconds > 0) {
1743
1973
  const retryAfterSec = Math.ceil(retrySeconds).toString();
1744
1974
  const retryAfterMs = Math.ceil(retrySeconds * 1000).toString();
1745
1975
  headers.set('Retry-After', retryAfterSec);
@@ -1754,35 +1984,42 @@ export async function transformAntigravityResponse(response, streaming, debugCon
1754
1984
  statusText: response.statusText,
1755
1985
  headers,
1756
1986
  };
1757
- const usageFromSse = streaming && isEventStreamResponse ? extractUsageFromSsePayload(text) : null;
1758
- const parsed = !streaming || !isEventStreamResponse ? parseAntigravityApiBody(text) : null;
1759
- const patched = parsed ? rewriteAntigravityPreviewAccessError(parsed, response.status, requestedModel) : null;
1987
+ const usageFromSse = streaming && isEventStreamResponse
1988
+ ? extractUsageFromSsePayload(text)
1989
+ : null;
1990
+ const parsed = !streaming || !isEventStreamResponse
1991
+ ? parseAntigravityApiBody(text)
1992
+ : null;
1993
+ const patched = parsed
1994
+ ? rewriteAntigravityPreviewAccessError(parsed, response.status, requestedModel)
1995
+ : null;
1760
1996
  const effectiveBody = patched ?? parsed ?? undefined;
1761
- const usage = usageFromSse ?? (effectiveBody ? extractUsageMetadata(effectiveBody) : null);
1997
+ const usage = usageFromSse ??
1998
+ (effectiveBody ? extractUsageMetadata(effectiveBody) : null);
1762
1999
  // Log cache stats when available
1763
2000
  if (usage && effectiveModel) {
1764
2001
  const cacheRead = usage.cachedContentTokenCount ?? 0;
1765
2002
  const totalInput = usage.promptTokenCount ?? usage.totalTokenCount ?? 0;
1766
2003
  const hitRate = totalInput > 0 ? Math.round((cacheRead / totalInput) * 100) : 0;
1767
- const status = cacheRead > 0 ? "HIT" : "MISS";
2004
+ const status = cacheRead > 0 ? 'HIT' : 'MISS';
1768
2005
  logCacheStats(effectiveModel, cacheRead, 0, totalInput);
1769
2006
  log.debug(`[Cache] ${status} model=${effectiveModel} read=${cacheRead} total=${totalInput} hitRate=${hitRate}%`);
1770
2007
  }
1771
2008
  if (usage?.cachedContentTokenCount !== undefined) {
1772
- headers.set("x-antigravity-cached-content-token-count", String(usage.cachedContentTokenCount));
2009
+ headers.set('x-antigravity-cached-content-token-count', String(usage.cachedContentTokenCount));
1773
2010
  if (usage.totalTokenCount !== undefined) {
1774
- headers.set("x-antigravity-total-token-count", String(usage.totalTokenCount));
2011
+ headers.set('x-antigravity-total-token-count', String(usage.totalTokenCount));
1775
2012
  }
1776
2013
  if (usage.promptTokenCount !== undefined) {
1777
- headers.set("x-antigravity-prompt-token-count", String(usage.promptTokenCount));
2014
+ headers.set('x-antigravity-prompt-token-count', String(usage.promptTokenCount));
1778
2015
  }
1779
2016
  if (usage.candidatesTokenCount !== undefined) {
1780
- headers.set("x-antigravity-candidates-token-count", String(usage.candidatesTokenCount));
2017
+ headers.set('x-antigravity-candidates-token-count', String(usage.candidatesTokenCount));
1781
2018
  }
1782
2019
  }
1783
2020
  logAntigravityDebugResponse(debugContext, response, {
1784
2021
  body: text,
1785
- note: streaming ? "Streaming SSE payload (buffered fallback)" : undefined,
2022
+ note: streaming ? 'Streaming SSE payload (buffered fallback)' : undefined,
1786
2023
  headersOverride: headers,
1787
2024
  });
1788
2025
  // Note: successful streaming responses are handled above via TransformStream.
@@ -1806,12 +2043,13 @@ export async function transformAntigravityResponse(response, streaming, debugCon
1806
2043
  return new Response(text, init);
1807
2044
  }
1808
2045
  catch (error) {
1809
- if (error instanceof Error && error.message === "THINKING_RECOVERY_NEEDED") {
2046
+ if (error instanceof Error &&
2047
+ error.message === 'THINKING_RECOVERY_NEEDED') {
1810
2048
  throw error;
1811
2049
  }
1812
2050
  logAntigravityDebugResponse(debugContext, response, {
1813
2051
  error,
1814
- note: "Failed to transform Antigravity response",
2052
+ note: 'Failed to transform Antigravity response',
1815
2053
  });
1816
2054
  return responseFallback;
1817
2055
  }