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