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