@vib-rato/ai 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3354 -0
- package/README.md +1194 -0
- package/dist/types/adapter-internals/provider-safety-stop.d.ts +45 -0
- package/dist/types/api-registry.d.ts +30 -0
- package/dist/types/auth-broker/client.d.ts +80 -0
- package/dist/types/auth-broker/index.d.ts +5 -0
- package/dist/types/auth-broker/redact.d.ts +7 -0
- package/dist/types/auth-broker/refresher.d.ts +25 -0
- package/dist/types/auth-broker/remote-store.d.ts +153 -0
- package/dist/types/auth-broker/server.d.ts +32 -0
- package/dist/types/auth-broker/types.d.ts +132 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +555 -0
- package/dist/types/auth-gateway/http.d.ts +40 -0
- package/dist/types/auth-gateway/index.d.ts +3 -0
- package/dist/types/auth-gateway/server.d.ts +70 -0
- package/dist/types/auth-gateway/types.d.ts +129 -0
- package/dist/types/auth-storage.d.ts +1074 -0
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/codex-tools.d.ts +4 -0
- package/dist/types/context-cap-policy.d.ts +68 -0
- package/dist/types/core.d.ts +35 -0
- package/dist/types/index.d.ts +55 -0
- package/dist/types/model-cache.d.ts +24 -0
- package/dist/types/model-manager.d.ts +77 -0
- package/dist/types/model-pricing.d.ts +3 -0
- package/dist/types/model-retirements.d.ts +6 -0
- package/dist/types/model-thinking.d.ts +100 -0
- package/dist/types/models.d.ts +21 -0
- package/dist/types/openai-completions-compat.d.ts +34 -0
- package/dist/types/provider-details.d.ts +24 -0
- package/dist/types/provider-models/bundled-references.d.ts +4 -0
- package/dist/types/provider-models/descriptors.d.ts +48 -0
- package/dist/types/provider-models/google.d.ts +20 -0
- package/dist/types/provider-models/index.d.ts +5 -0
- package/dist/types/provider-models/ollama.d.ts +7 -0
- package/dist/types/provider-models/openai-compat.d.ts +293 -0
- package/dist/types/provider-models/special.d.ts +29 -0
- package/dist/types/providers/amazon-bedrock.d.ts +60 -0
- package/dist/types/providers/anthropic-messages-server-schema.d.ts +450 -0
- package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
- package/dist/types/providers/anthropic.d.ts +280 -0
- package/dist/types/providers/aws-credential-config.d.ts +19 -0
- package/dist/types/providers/aws-credentials.d.ts +43 -0
- package/dist/types/providers/aws-eventstream.d.ts +38 -0
- package/dist/types/providers/aws-sigv4.d.ts +55 -0
- package/dist/types/providers/azure-openai-responses.d.ts +22 -0
- package/dist/types/providers/composer-discipline.d.ts +32 -0
- package/dist/types/providers/cursor/client-version.d.ts +10 -0
- package/dist/types/providers/cursor/exec-modern.d.ts +98 -0
- package/dist/types/providers/cursor/gen/agent_pb.d.ts +16769 -0
- package/dist/types/providers/cursor-pi-args.d.ts +119 -0
- package/dist/types/providers/cursor.d.ts +72 -0
- package/dist/types/providers/dashscope-token-plan-headers.d.ts +57 -0
- package/dist/types/providers/error-message.d.ts +27 -0
- package/dist/types/providers/github-copilot-headers.d.ts +40 -0
- package/dist/types/providers/gitlab-duo.d.ts +27 -0
- package/dist/types/providers/google-auth.d.ts +26 -0
- package/dist/types/providers/google-gemini-cli.d.ts +75 -0
- package/dist/types/providers/google-gemini-headers.d.ts +43 -0
- package/dist/types/providers/google-shared.d.ts +183 -0
- package/dist/types/providers/google-types.d.ts +138 -0
- package/dist/types/providers/google-vertex.d.ts +11 -0
- package/dist/types/providers/google.d.ts +4 -0
- package/dist/types/providers/grammar.d.ts +1 -0
- package/dist/types/providers/kimi.d.ts +27 -0
- package/dist/types/providers/kiro-api-key.d.ts +50 -0
- package/dist/types/providers/kiro-codewhisperer.d.ts +11 -0
- package/dist/types/providers/mock.d.ts +189 -0
- package/dist/types/providers/ollama.d.ts +41 -0
- package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
- package/dist/types/providers/openai-bounded-rate-limits.d.ts +3 -0
- package/dist/types/providers/openai-chat-server-schema.d.ts +1733 -0
- package/dist/types/providers/openai-chat-server.d.ts +16 -0
- package/dist/types/providers/openai-codex/constants.d.ts +26 -0
- package/dist/types/providers/openai-codex/request-transformer.d.ts +50 -0
- package/dist/types/providers/openai-codex/response-handler.d.ts +18 -0
- package/dist/types/providers/openai-codex-responses.d.ts +71 -0
- package/dist/types/providers/openai-completions-compat.d.ts +6 -0
- package/dist/types/providers/openai-completions.d.ts +35 -0
- package/dist/types/providers/openai-opencodex-responses.d.ts +10 -0
- package/dist/types/providers/openai-request-transform.d.ts +4 -0
- package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
- package/dist/types/providers/openai-responses-server.d.ts +17 -0
- package/dist/types/providers/openai-responses-shared.d.ts +106 -0
- package/dist/types/providers/openai-responses.d.ts +37 -0
- package/dist/types/providers/pi-native-client.d.ts +29 -0
- package/dist/types/providers/pi-native-server.d.ts +60 -0
- package/dist/types/providers/register-builtins.d.ts +59 -0
- package/dist/types/providers/synthetic.d.ts +26 -0
- package/dist/types/providers/transform-messages.d.ts +33 -0
- package/dist/types/providers/vision-guard.d.ts +8 -0
- package/dist/types/rate-limit-utils.d.ts +19 -0
- package/dist/types/stream.d.ts +45 -0
- package/dist/types/types.d.ts +1073 -0
- package/dist/types/usage/claude.d.ts +3 -0
- package/dist/types/usage/gemini.d.ts +2 -0
- package/dist/types/usage/github-copilot.d.ts +7 -0
- package/dist/types/usage/google-antigravity.d.ts +2 -0
- package/dist/types/usage/grok-cli.d.ts +17 -0
- package/dist/types/usage/kimi.d.ts +4 -0
- package/dist/types/usage/minimax-code.d.ts +2 -0
- package/dist/types/usage/openai-codex.d.ts +3 -0
- package/dist/types/usage/shared.d.ts +1 -0
- package/dist/types/usage/zai.d.ts +2 -0
- package/dist/types/usage.d.ts +264 -0
- package/dist/types/utils/abort.d.ts +19 -0
- package/dist/types/utils/anthropic-auth.d.ts +39 -0
- package/dist/types/utils/block-symbols.d.ts +6 -0
- package/dist/types/utils/discovery/antigravity.d.ts +67 -0
- package/dist/types/utils/discovery/codex.d.ts +38 -0
- package/dist/types/utils/discovery/cursor.d.ts +49 -0
- package/dist/types/utils/discovery/gemini.d.ts +25 -0
- package/dist/types/utils/discovery/index.d.ts +4 -0
- package/dist/types/utils/discovery/openai-compatible.d.ts +81 -0
- package/dist/types/utils/event-stream.d.ts +41 -0
- package/dist/types/utils/fallback-transport.d.ts +110 -0
- package/dist/types/utils/fireworks-model-id.d.ts +10 -0
- package/dist/types/utils/foundry.d.ts +11 -0
- package/dist/types/utils/h2-fetch.d.ts +22 -0
- package/dist/types/utils/http-inspector.d.ts +59 -0
- package/dist/types/utils/idle-iterator.d.ts +122 -0
- package/dist/types/utils/json-parse.d.ts +98 -0
- package/dist/types/utils/oauth/alibaba-token-plan.d.ts +19 -0
- package/dist/types/utils/oauth/anthropic.d.ts +41 -0
- package/dist/types/utils/oauth/api-key-login.d.ts +38 -0
- package/dist/types/utils/oauth/api-key-validation.d.ts +39 -0
- package/dist/types/utils/oauth/bizrouter.d.ts +1 -0
- package/dist/types/utils/oauth/callback-server.d.ts +80 -0
- package/dist/types/utils/oauth/cerebras.d.ts +1 -0
- package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
- package/dist/types/utils/oauth/commandcode.d.ts +1 -0
- package/dist/types/utils/oauth/cursor.d.ts +15 -0
- package/dist/types/utils/oauth/deepinfra.d.ts +1 -0
- package/dist/types/utils/oauth/deepseek.d.ts +10 -0
- package/dist/types/utils/oauth/firepass.d.ts +1 -0
- package/dist/types/utils/oauth/fireworks.d.ts +1 -0
- package/dist/types/utils/oauth/fugu.d.ts +1 -0
- package/dist/types/utils/oauth/github-copilot.d.ts +38 -0
- package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
- package/dist/types/utils/oauth/glm-zcode.d.ts +71 -0
- package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
- package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
- package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
- package/dist/types/utils/oauth/huggingface.d.ts +19 -0
- package/dist/types/utils/oauth/index.d.ts +39 -0
- package/dist/types/utils/oauth/kagi.d.ts +17 -0
- package/dist/types/utils/oauth/kilo.d.ts +5 -0
- package/dist/types/utils/oauth/kimi.d.ts +17 -0
- package/dist/types/utils/oauth/kiro.d.ts +71 -0
- package/dist/types/utils/oauth/litellm.d.ts +18 -0
- package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
- package/dist/types/utils/oauth/mara.d.ts +1 -0
- package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
- package/dist/types/utils/oauth/moonshot.d.ts +1 -0
- package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
- package/dist/types/utils/oauth/nvidia.d.ts +18 -0
- package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
- package/dist/types/utils/oauth/ollama.d.ts +18 -0
- package/dist/types/utils/oauth/openai-codex.d.ts +21 -0
- package/dist/types/utils/oauth/opencode.d.ts +18 -0
- package/dist/types/utils/oauth/opengateway.d.ts +1 -0
- package/dist/types/utils/oauth/openrouter.d.ts +1 -0
- package/dist/types/utils/oauth/parallel.d.ts +17 -0
- package/dist/types/utils/oauth/perplexity.d.ts +4 -0
- package/dist/types/utils/oauth/pkce.d.ts +8 -0
- package/dist/types/utils/oauth/qianfan.d.ts +17 -0
- package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
- package/dist/types/utils/oauth/sglang.d.ts +16 -0
- package/dist/types/utils/oauth/synthetic.d.ts +1 -0
- package/dist/types/utils/oauth/tavily.d.ts +17 -0
- package/dist/types/utils/oauth/together.d.ts +1 -0
- package/dist/types/utils/oauth/types.d.ts +56 -0
- package/dist/types/utils/oauth/venice.d.ts +18 -0
- package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
- package/dist/types/utils/oauth/vllm.d.ts +16 -0
- package/dist/types/utils/oauth/xai.d.ts +30 -0
- package/dist/types/utils/oauth/xiaomi.d.ts +25 -0
- package/dist/types/utils/oauth/zai.d.ts +18 -0
- package/dist/types/utils/oauth/zenmux.d.ts +1 -0
- package/dist/types/utils/overflow.d.ts +14 -0
- package/dist/types/utils/parse-bind.d.ts +26 -0
- package/dist/types/utils/provider-response.d.ts +6 -0
- package/dist/types/utils/provider-safety-stop.d.ts +8 -0
- package/dist/types/utils/proxy.d.ts +7 -0
- package/dist/types/utils/retry-after.d.ts +3 -0
- package/dist/types/utils/retry-budget.d.ts +1 -0
- package/dist/types/utils/retry.d.ts +29 -0
- package/dist/types/utils/schema/adapt.d.ts +24 -0
- package/dist/types/utils/schema/compatibility.d.ts +30 -0
- package/dist/types/utils/schema/dereference.d.ts +11 -0
- package/dist/types/utils/schema/draft.d.ts +10 -0
- package/dist/types/utils/schema/equality.d.ts +4 -0
- package/dist/types/utils/schema/fields.d.ts +49 -0
- package/dist/types/utils/schema/index.d.ts +14 -0
- package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
- package/dist/types/utils/schema/meta-validator.d.ts +2 -0
- package/dist/types/utils/schema/normalize.d.ts +93 -0
- package/dist/types/utils/schema/root-combinator.d.ts +12 -0
- package/dist/types/utils/schema/spill.d.ts +8 -0
- package/dist/types/utils/schema/stamps.d.ts +25 -0
- package/dist/types/utils/schema/types.d.ts +4 -0
- package/dist/types/utils/schema/wire.d.ts +54 -0
- package/dist/types/utils/schema/zod-decontaminate.d.ts +31 -0
- package/dist/types/utils/sse-debug.d.ts +10 -0
- package/dist/types/utils/tool-call-healing.d.ts +80 -0
- package/dist/types/utils/tool-choice-capability.d.ts +57 -0
- package/dist/types/utils/tool-choice.d.ts +50 -0
- package/dist/types/utils/validation.d.ts +17 -0
- package/dist/types/utils.d.ts +117 -0
- package/package.json +152 -0
- package/src/adapter-internals/provider-safety-stop.d.ts +45 -0
- package/src/adapter-internals/provider-safety-stop.ts +156 -0
- package/src/api-registry.d.ts +30 -0
- package/src/api-registry.ts +96 -0
- package/src/auth-broker/client.ts +444 -0
- package/src/auth-broker/index.ts +5 -0
- package/src/auth-broker/redact.ts +39 -0
- package/src/auth-broker/refresher.ts +130 -0
- package/src/auth-broker/remote-store.ts +1576 -0
- package/src/auth-broker/server.ts +764 -0
- package/src/auth-broker/types.ts +164 -0
- package/src/auth-broker/wire-schemas.ts +261 -0
- package/src/auth-gateway/http.ts +198 -0
- package/src/auth-gateway/index.ts +3 -0
- package/src/auth-gateway/server.ts +1315 -0
- package/src/auth-gateway/types.ts +160 -0
- package/src/auth-storage.ts +7312 -0
- package/src/cli.ts +269 -0
- package/src/codex-tools.d.ts +4 -0
- package/src/codex-tools.ts +24 -0
- package/src/context-cap-policy.d.ts +68 -0
- package/src/context-cap-policy.ts +123 -0
- package/src/core.ts +44 -0
- package/src/index.ts +61 -0
- package/src/model-cache.ts +236 -0
- package/src/model-manager.ts +744 -0
- package/src/model-pricing.d.ts +3 -0
- package/src/model-pricing.ts +68 -0
- package/src/model-retirements.d.ts +6 -0
- package/src/model-retirements.ts +19 -0
- package/src/model-thinking.d.ts +100 -0
- package/src/model-thinking.ts +1054 -0
- package/src/models.d.ts +21 -0
- package/src/models.json +94672 -0
- package/src/models.json.d.ts +9 -0
- package/src/models.ts +126 -0
- package/src/openai-completions-compat.d.ts +34 -0
- package/src/openai-completions-compat.ts +383 -0
- package/src/prompts/composer-bash-policy-recovery.md +1 -0
- package/src/prompts/cursor-composer-bash-policy-recovery.md +1 -0
- package/src/prompts/cursor-composer-edit-discipline.md +7 -0
- package/src/prompts/turn-aborted-guidance.md +4 -0
- package/src/provider-details.ts +90 -0
- package/src/provider-models/bundled-references.ts +38 -0
- package/src/provider-models/descriptors.ts +392 -0
- package/src/provider-models/google.ts +92 -0
- package/src/provider-models/index.ts +5 -0
- package/src/provider-models/ollama.ts +159 -0
- package/src/provider-models/openai-compat.ts +2920 -0
- package/src/provider-models/special.ts +185 -0
- package/src/providers/amazon-bedrock.d.ts +60 -0
- package/src/providers/amazon-bedrock.ts +939 -0
- package/src/providers/anthropic-messages-server-schema.ts +229 -0
- package/src/providers/anthropic-messages-server.ts +839 -0
- package/src/providers/anthropic.d.ts +280 -0
- package/src/providers/anthropic.ts +4421 -0
- package/src/providers/aws-credential-config.d.ts +19 -0
- package/src/providers/aws-credential-config.ts +179 -0
- package/src/providers/aws-credentials.d.ts +43 -0
- package/src/providers/aws-credentials.ts +457 -0
- package/src/providers/aws-eventstream.d.ts +38 -0
- package/src/providers/aws-eventstream.ts +185 -0
- package/src/providers/aws-sigv4.d.ts +55 -0
- package/src/providers/aws-sigv4.ts +218 -0
- package/src/providers/azure-openai-responses.d.ts +22 -0
- package/src/providers/azure-openai-responses.ts +447 -0
- package/src/providers/composer-discipline.d.ts +32 -0
- package/src/providers/composer-discipline.ts +95 -0
- package/src/providers/cursor/client-version.d.ts +10 -0
- package/src/providers/cursor/client-version.ts +10 -0
- package/src/providers/cursor/exec-modern.d.ts +98 -0
- package/src/providers/cursor/exec-modern.ts +497 -0
- package/src/providers/cursor/gen/agent_pb.d.ts +16769 -0
- package/src/providers/cursor/gen/agent_pb.ts +19780 -0
- package/src/providers/cursor/proto/agent.proto +4533 -0
- package/src/providers/cursor/proto/buf.gen.yaml +6 -0
- package/src/providers/cursor/proto/buf.yaml +17 -0
- package/src/providers/cursor-pi-args.d.ts +119 -0
- package/src/providers/cursor-pi-args.ts +187 -0
- package/src/providers/cursor.d.ts +72 -0
- package/src/providers/cursor.ts +3396 -0
- package/src/providers/dashscope-token-plan-headers.d.ts +57 -0
- package/src/providers/dashscope-token-plan-headers.ts +84 -0
- package/src/providers/error-message.d.ts +27 -0
- package/src/providers/error-message.ts +21 -0
- package/src/providers/github-copilot-headers.d.ts +40 -0
- package/src/providers/github-copilot-headers.ts +140 -0
- package/src/providers/gitlab-duo.d.ts +27 -0
- package/src/providers/gitlab-duo.ts +393 -0
- package/src/providers/google-auth.d.ts +26 -0
- package/src/providers/google-auth.ts +262 -0
- package/src/providers/google-gemini-cli.d.ts +75 -0
- package/src/providers/google-gemini-cli.ts +969 -0
- package/src/providers/google-gemini-headers.d.ts +43 -0
- package/src/providers/google-gemini-headers.ts +100 -0
- package/src/providers/google-shared.d.ts +183 -0
- package/src/providers/google-shared.ts +1105 -0
- package/src/providers/google-types.d.ts +138 -0
- package/src/providers/google-types.ts +167 -0
- package/src/providers/google-vertex.d.ts +11 -0
- package/src/providers/google-vertex.ts +124 -0
- package/src/providers/google.d.ts +4 -0
- package/src/providers/google.ts +41 -0
- package/src/providers/grammar.d.ts +1 -0
- package/src/providers/grammar.ts +70 -0
- package/src/providers/kimi.d.ts +27 -0
- package/src/providers/kimi.ts +52 -0
- package/src/providers/kiro-api-key.d.ts +50 -0
- package/src/providers/kiro-api-key.ts +786 -0
- package/src/providers/kiro-codewhisperer.d.ts +11 -0
- package/src/providers/kiro-codewhisperer.ts +600 -0
- package/src/providers/mock.ts +526 -0
- package/src/providers/ollama.d.ts +41 -0
- package/src/providers/ollama.ts +645 -0
- package/src/providers/openai-anthropic-shim.d.ts +31 -0
- package/src/providers/openai-anthropic-shim.ts +156 -0
- package/src/providers/openai-bounded-rate-limits.d.ts +3 -0
- package/src/providers/openai-bounded-rate-limits.ts +57 -0
- package/src/providers/openai-chat-server-schema.ts +254 -0
- package/src/providers/openai-chat-server.ts +724 -0
- package/src/providers/openai-codex/constants.d.ts +26 -0
- package/src/providers/openai-codex/constants.ts +43 -0
- package/src/providers/openai-codex/request-transformer.d.ts +50 -0
- package/src/providers/openai-codex/request-transformer.ts +219 -0
- package/src/providers/openai-codex/response-handler.d.ts +18 -0
- package/src/providers/openai-codex/response-handler.ts +111 -0
- package/src/providers/openai-codex-responses.d.ts +71 -0
- package/src/providers/openai-codex-responses.ts +3288 -0
- package/src/providers/openai-completions-compat.d.ts +6 -0
- package/src/providers/openai-completions-compat.ts +6 -0
- package/src/providers/openai-completions.d.ts +35 -0
- package/src/providers/openai-completions.ts +2294 -0
- package/src/providers/openai-opencodex-responses.ts +174 -0
- package/src/providers/openai-request-transform.d.ts +4 -0
- package/src/providers/openai-request-transform.ts +136 -0
- package/src/providers/openai-responses-server-schema.ts +290 -0
- package/src/providers/openai-responses-server.ts +1268 -0
- package/src/providers/openai-responses-shared.d.ts +106 -0
- package/src/providers/openai-responses-shared.ts +1253 -0
- package/src/providers/openai-responses.d.ts +37 -0
- package/src/providers/openai-responses.ts +989 -0
- package/src/providers/pi-native-client.d.ts +29 -0
- package/src/providers/pi-native-client.ts +243 -0
- package/src/providers/pi-native-server.ts +488 -0
- package/src/providers/register-builtins.d.ts +59 -0
- package/src/providers/register-builtins.ts +544 -0
- package/src/providers/synthetic.d.ts +26 -0
- package/src/providers/synthetic.ts +50 -0
- package/src/providers/transform-messages.d.ts +33 -0
- package/src/providers/transform-messages.ts +408 -0
- package/src/providers/vision-guard.d.ts +8 -0
- package/src/providers/vision-guard.ts +31 -0
- package/src/rate-limit-utils.d.ts +19 -0
- package/src/rate-limit-utils.ts +102 -0
- package/src/stream.d.ts +45 -0
- package/src/stream.ts +1306 -0
- package/src/types.d.ts +1073 -0
- package/src/types.ts +1305 -0
- package/src/usage/claude.ts +449 -0
- package/src/usage/gemini.ts +250 -0
- package/src/usage/github-copilot.ts +421 -0
- package/src/usage/google-antigravity.ts +201 -0
- package/src/usage/grok-cli.ts +259 -0
- package/src/usage/kimi.ts +285 -0
- package/src/usage/minimax-code.ts +31 -0
- package/src/usage/openai-codex.ts +503 -0
- package/src/usage/shared.ts +10 -0
- package/src/usage/zai.ts +247 -0
- package/src/usage.ts +190 -0
- package/src/utils/abort.d.ts +19 -0
- package/src/utils/abort.ts +51 -0
- package/src/utils/anthropic-auth.ts +95 -0
- package/src/utils/block-symbols.d.ts +6 -0
- package/src/utils/block-symbols.ts +11 -0
- package/src/utils/discovery/antigravity.ts +275 -0
- package/src/utils/discovery/codex.ts +362 -0
- package/src/utils/discovery/cursor.ts +388 -0
- package/src/utils/discovery/gemini.ts +248 -0
- package/src/utils/discovery/index.ts +4 -0
- package/src/utils/discovery/openai-compatible.ts +379 -0
- package/src/utils/event-stream.d.ts +41 -0
- package/src/utils/event-stream.ts +269 -0
- package/src/utils/fallback-transport.d.ts +110 -0
- package/src/utils/fallback-transport.ts +411 -0
- package/src/utils/fireworks-model-id.d.ts +10 -0
- package/src/utils/fireworks-model-id.ts +30 -0
- package/src/utils/foundry.d.ts +11 -0
- package/src/utils/foundry.ts +18 -0
- package/src/utils/h2-fetch.ts +60 -0
- package/src/utils/http-inspector.d.ts +59 -0
- package/src/utils/http-inspector.ts +380 -0
- package/src/utils/idle-iterator.d.ts +122 -0
- package/src/utils/idle-iterator.ts +410 -0
- package/src/utils/json-parse.d.ts +98 -0
- package/src/utils/json-parse.ts +607 -0
- package/src/utils/oauth/alibaba-token-plan.ts +60 -0
- package/src/utils/oauth/anthropic.ts +233 -0
- package/src/utils/oauth/api-key-login.ts +98 -0
- package/src/utils/oauth/api-key-validation.ts +344 -0
- package/src/utils/oauth/bizrouter.ts +15 -0
- package/src/utils/oauth/callback-server.d.ts +80 -0
- package/src/utils/oauth/callback-server.ts +359 -0
- package/src/utils/oauth/cerebras.ts +16 -0
- package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
- package/src/utils/oauth/commandcode.ts +17 -0
- package/src/utils/oauth/cursor.ts +157 -0
- package/src/utils/oauth/deepinfra.ts +15 -0
- package/src/utils/oauth/deepseek.ts +53 -0
- package/src/utils/oauth/firepass.ts +24 -0
- package/src/utils/oauth/fireworks.ts +15 -0
- package/src/utils/oauth/fugu.ts +15 -0
- package/src/utils/oauth/github-copilot.d.ts +38 -0
- package/src/utils/oauth/github-copilot.ts +362 -0
- package/src/utils/oauth/gitlab-duo.ts +123 -0
- package/src/utils/oauth/glm-zcode.d.ts +71 -0
- package/src/utils/oauth/glm-zcode.ts +433 -0
- package/src/utils/oauth/google-antigravity.ts +200 -0
- package/src/utils/oauth/google-gemini-cli.ts +256 -0
- package/src/utils/oauth/google-oauth-shared.ts +110 -0
- package/src/utils/oauth/huggingface.ts +62 -0
- package/src/utils/oauth/index.ts +558 -0
- package/src/utils/oauth/kagi.ts +47 -0
- package/src/utils/oauth/kilo.ts +87 -0
- package/src/utils/oauth/kimi.d.ts +17 -0
- package/src/utils/oauth/kimi.ts +275 -0
- package/src/utils/oauth/kiro.ts +448 -0
- package/src/utils/oauth/litellm.ts +47 -0
- package/src/utils/oauth/lm-studio.ts +38 -0
- package/src/utils/oauth/mara.ts +16 -0
- package/src/utils/oauth/minimax-code.ts +78 -0
- package/src/utils/oauth/moonshot.ts +16 -0
- package/src/utils/oauth/nanogpt.ts +15 -0
- package/src/utils/oauth/nvidia.ts +70 -0
- package/src/utils/oauth/oauth.html +199 -0
- package/src/utils/oauth/ollama-cloud.ts +28 -0
- package/src/utils/oauth/ollama.ts +47 -0
- package/src/utils/oauth/openai-codex.ts +299 -0
- package/src/utils/oauth/opencode.ts +49 -0
- package/src/utils/oauth/opengateway.ts +15 -0
- package/src/utils/oauth/openrouter.ts +16 -0
- package/src/utils/oauth/parallel.ts +46 -0
- package/src/utils/oauth/perplexity.ts +225 -0
- package/src/utils/oauth/pkce.ts +18 -0
- package/src/utils/oauth/qianfan.ts +58 -0
- package/src/utils/oauth/qwen-portal.ts +60 -0
- package/src/utils/oauth/sglang.ts +42 -0
- package/src/utils/oauth/synthetic.ts +15 -0
- package/src/utils/oauth/tavily.ts +46 -0
- package/src/utils/oauth/together.ts +16 -0
- package/src/utils/oauth/types.d.ts +56 -0
- package/src/utils/oauth/types.ts +122 -0
- package/src/utils/oauth/venice.ts +59 -0
- package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
- package/src/utils/oauth/vllm.ts +42 -0
- package/src/utils/oauth/xai.ts +246 -0
- package/src/utils/oauth/xiaomi.ts +199 -0
- package/src/utils/oauth/zai.ts +60 -0
- package/src/utils/oauth/zenmux.ts +15 -0
- package/src/utils/overflow.ts +275 -0
- package/src/utils/parse-bind.ts +81 -0
- package/src/utils/provider-response.d.ts +6 -0
- package/src/utils/provider-response.ts +30 -0
- package/src/utils/provider-safety-stop.ts +8 -0
- package/src/utils/proxy.d.ts +7 -0
- package/src/utils/proxy.ts +652 -0
- package/src/utils/retry-after.d.ts +3 -0
- package/src/utils/retry-after.ts +110 -0
- package/src/utils/retry-budget.d.ts +1 -0
- package/src/utils/retry-budget.ts +4 -0
- package/src/utils/retry.d.ts +29 -0
- package/src/utils/retry.ts +67 -0
- package/src/utils/schema/CONSTRAINTS.md +164 -0
- package/src/utils/schema/adapt.d.ts +24 -0
- package/src/utils/schema/adapt.ts +36 -0
- package/src/utils/schema/compatibility.d.ts +30 -0
- package/src/utils/schema/compatibility.ts +435 -0
- package/src/utils/schema/dereference.d.ts +11 -0
- package/src/utils/schema/dereference.ts +98 -0
- package/src/utils/schema/draft.d.ts +10 -0
- package/src/utils/schema/draft.ts +341 -0
- package/src/utils/schema/equality.d.ts +4 -0
- package/src/utils/schema/equality.ts +97 -0
- package/src/utils/schema/fields.d.ts +49 -0
- package/src/utils/schema/fields.ts +190 -0
- package/src/utils/schema/index.d.ts +14 -0
- package/src/utils/schema/index.ts +14 -0
- package/src/utils/schema/json-schema-validator.d.ts +12 -0
- package/src/utils/schema/json-schema-validator.ts +577 -0
- package/src/utils/schema/meta-validator.d.ts +2 -0
- package/src/utils/schema/meta-validator.ts +167 -0
- package/src/utils/schema/normalize.d.ts +93 -0
- package/src/utils/schema/normalize.ts +1588 -0
- package/src/utils/schema/root-combinator.d.ts +12 -0
- package/src/utils/schema/root-combinator.ts +143 -0
- package/src/utils/schema/spill.d.ts +8 -0
- package/src/utils/schema/spill.ts +43 -0
- package/src/utils/schema/stamps.d.ts +25 -0
- package/src/utils/schema/stamps.ts +97 -0
- package/src/utils/schema/types.d.ts +4 -0
- package/src/utils/schema/types.ts +11 -0
- package/src/utils/schema/wire.d.ts +54 -0
- package/src/utils/schema/wire.ts +213 -0
- package/src/utils/schema/zod-decontaminate.d.ts +31 -0
- package/src/utils/schema/zod-decontaminate.ts +331 -0
- package/src/utils/sse-debug.d.ts +10 -0
- package/src/utils/sse-debug.ts +289 -0
- package/src/utils/tool-call-healing.d.ts +80 -0
- package/src/utils/tool-call-healing.ts +298 -0
- package/src/utils/tool-choice-capability.d.ts +57 -0
- package/src/utils/tool-choice-capability.ts +633 -0
- package/src/utils/tool-choice.d.ts +50 -0
- package/src/utils/tool-choice.ts +99 -0
- package/src/utils/validation.ts +1080 -0
- package/src/utils.d.ts +117 -0
- package/src/utils.ts +523 -0
|
@@ -0,0 +1,969 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Gemini CLI / Antigravity provider.
|
|
3
|
+
* Shared implementation for both google-gemini-cli and google-antigravity providers.
|
|
4
|
+
* Uses the Cloud Code Assist API endpoint to access Gemini and Anthropic model models.
|
|
5
|
+
*/
|
|
6
|
+
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
7
|
+
import { scheduler } from "node:timers/promises";
|
|
8
|
+
import { extractHttpStatusFromError, fetchWithRetry, readSseJson } from "@vib-rato/utils";
|
|
9
|
+
import {
|
|
10
|
+
isProviderSafetyStopAdapterInvocation,
|
|
11
|
+
mintProviderSafetyStop,
|
|
12
|
+
PROVIDER_SAFETY_STOP_ADAPTER_CAPABILITY,
|
|
13
|
+
} from "../adapter-internals/provider-safety-stop";
|
|
14
|
+
import { calculateCost } from "../models";
|
|
15
|
+
import type {
|
|
16
|
+
Api,
|
|
17
|
+
AssistantMessage,
|
|
18
|
+
Context,
|
|
19
|
+
Model,
|
|
20
|
+
StreamFunction,
|
|
21
|
+
StreamOptions,
|
|
22
|
+
TextContent,
|
|
23
|
+
ThinkingContent,
|
|
24
|
+
ToolCall,
|
|
25
|
+
} from "../types";
|
|
26
|
+
import { normalizeSystemPrompts } from "../utils";
|
|
27
|
+
import { AssistantMessageEventStream } from "../utils/event-stream";
|
|
28
|
+
import { transportFailureFacts } from "../utils/fallback-transport";
|
|
29
|
+
import { appendRawHttpRequestDumpFor400, type RawHttpRequestDump, withHttpStatus } from "../utils/http-inspector";
|
|
30
|
+
import { resolveRetryBudget } from "../utils/retry-budget";
|
|
31
|
+
// Refresh is the sole responsibility of AuthStorage (broker-aware, single-flighted);
|
|
32
|
+
// the stream provider trusts the access token threaded through `options.apiKey`.
|
|
33
|
+
import { normalizeSchemaForCCA } from "../utils/schema";
|
|
34
|
+
import {
|
|
35
|
+
isForcedToolChoiceUnsupportedError,
|
|
36
|
+
markToolChoiceIncapability,
|
|
37
|
+
resolveToolChoice,
|
|
38
|
+
} from "../utils/tool-choice-capability";
|
|
39
|
+
import {
|
|
40
|
+
ANTIGRAVITY_SYSTEM_INSTRUCTION,
|
|
41
|
+
getAntigravityRequestHeaders,
|
|
42
|
+
getGeminiCliHeaders,
|
|
43
|
+
} from "./google-gemini-headers";
|
|
44
|
+
import type { Content, FunctionCallingConfigMode, ThinkingConfig } from "./google-shared";
|
|
45
|
+
import {
|
|
46
|
+
convertMessages,
|
|
47
|
+
convertTools,
|
|
48
|
+
type GoogleThinkingLevel,
|
|
49
|
+
getGooglePromptBlockReason,
|
|
50
|
+
isGoogleCandidateSafetyStopReason,
|
|
51
|
+
isGooglePromptSafetyStopReason,
|
|
52
|
+
isThinkingPart,
|
|
53
|
+
mapStopReasonString,
|
|
54
|
+
mapToolChoice,
|
|
55
|
+
nextToolCallId,
|
|
56
|
+
pushBlockEndEvent,
|
|
57
|
+
pushToolCallEvents,
|
|
58
|
+
retainThoughtSignature,
|
|
59
|
+
startTextOrThinkingBlock,
|
|
60
|
+
} from "./google-shared";
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Thinking level for Gemini 3 models. Re-exported from `google-shared` so existing
|
|
64
|
+
* `import { GoogleThinkingLevel } from "./google-gemini-cli"` callers keep working.
|
|
65
|
+
*/
|
|
66
|
+
export type { GoogleThinkingLevel };
|
|
67
|
+
|
|
68
|
+
export interface GoogleGeminiCliOptions extends StreamOptions {
|
|
69
|
+
toolChoice?: "auto" | "none" | "any" | "required";
|
|
70
|
+
/**
|
|
71
|
+
* Thinking/reasoning configuration.
|
|
72
|
+
* - Gemini 2.x models: use `budgetTokens` to set the thinking budget
|
|
73
|
+
* - Gemini 3 models (gemini-3-pro-*, gemini-3-flash-*): use `level` instead
|
|
74
|
+
*
|
|
75
|
+
* When using `streamSimple`, this is handled automatically based on the model.
|
|
76
|
+
*/
|
|
77
|
+
thinking?: {
|
|
78
|
+
enabled: boolean;
|
|
79
|
+
/** Thinking budget in tokens. Use for Gemini 2.x models. */
|
|
80
|
+
budgetTokens?: number;
|
|
81
|
+
/** Thinking level. Use for Gemini 3 models (LOW/HIGH for Pro, MINIMAL/LOW/MEDIUM/HIGH for Flash). */
|
|
82
|
+
level?: GoogleThinkingLevel;
|
|
83
|
+
};
|
|
84
|
+
projectId?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const DEFAULT_ENDPOINT = "https://cloudcode-pa.googleapis.com";
|
|
88
|
+
const ANTIGRAVITY_DAILY_ENDPOINT = "https://daily-cloudcode-pa.googleapis.com";
|
|
89
|
+
const ANTIGRAVITY_SANDBOX_ENDPOINT = "https://daily-cloudcode-pa.sandbox.googleapis.com";
|
|
90
|
+
const ANTIGRAVITY_ENDPOINT_FALLBACKS = [ANTIGRAVITY_DAILY_ENDPOINT, ANTIGRAVITY_SANDBOX_ENDPOINT] as const;
|
|
91
|
+
|
|
92
|
+
export {
|
|
93
|
+
ANTIGRAVITY_SYSTEM_INSTRUCTION,
|
|
94
|
+
getAntigravityRequestHeaders,
|
|
95
|
+
getGeminiCliHeaders,
|
|
96
|
+
getGeminiCliUserAgent,
|
|
97
|
+
} from "./google-gemini-headers";
|
|
98
|
+
|
|
99
|
+
// Retry configuration
|
|
100
|
+
const MAX_RETRIES = 3;
|
|
101
|
+
const BASE_DELAY_MS = 1000;
|
|
102
|
+
const MAX_EMPTY_STREAM_RETRIES = 2;
|
|
103
|
+
const EMPTY_STREAM_BASE_DELAY_MS = 500;
|
|
104
|
+
const RATE_LIMIT_BUDGET_MS = 5 * 60 * 1000;
|
|
105
|
+
const CLAUDE_THINKING_BETA_HEADER = "interleaved-thinking-2025-05-14";
|
|
106
|
+
const GOOGLE_GEMINI_REFRESH_SKEW_MS = 60_000;
|
|
107
|
+
const ANTIGRAVITY_REFRESH_SKEW_MS = 60_000;
|
|
108
|
+
|
|
109
|
+
function isClaudeModel(modelId: string): boolean {
|
|
110
|
+
return modelId.toLowerCase().includes("claude");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function needsClaudeThinkingBetaHeader(model: Model<"google-gemini-cli">): boolean {
|
|
114
|
+
return model.provider === "google-antigravity" && model.id.startsWith("claude-") && model.reasoning;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function shouldInjectAntigravitySystemInstruction(modelId: string): boolean {
|
|
118
|
+
const normalized = modelId.toLowerCase();
|
|
119
|
+
return normalized.includes("claude") || normalized.includes("gemini-3");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Extract a clean, user-friendly error message from Google API error response.
|
|
124
|
+
* Parses JSON error responses and returns just the message field.
|
|
125
|
+
*/
|
|
126
|
+
function extractErrorMessage(errorText: string): string {
|
|
127
|
+
try {
|
|
128
|
+
const parsed = JSON.parse(errorText) as { error?: { message?: string } };
|
|
129
|
+
if (parsed.error?.message) {
|
|
130
|
+
return parsed.error.message;
|
|
131
|
+
}
|
|
132
|
+
} catch {
|
|
133
|
+
// Not JSON, return as-is
|
|
134
|
+
}
|
|
135
|
+
return errorText;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function createGeminiCliHttpError(response: Response, errorText: string, formatErrorMessage = true): Error {
|
|
139
|
+
const message = formatErrorMessage ? extractErrorMessage(errorText) : errorText;
|
|
140
|
+
const error = withHttpStatus(
|
|
141
|
+
new Error(`Cloud Code Assist API error (${response.status}): ${message}`),
|
|
142
|
+
response.status,
|
|
143
|
+
) as Error & { code?: string; headers?: Headers };
|
|
144
|
+
error.headers = response.headers;
|
|
145
|
+
try {
|
|
146
|
+
const code = (JSON.parse(errorText) as { error?: { code?: unknown } }).error?.code;
|
|
147
|
+
if (typeof code === "string") error.code = code;
|
|
148
|
+
} catch {
|
|
149
|
+
// The response body is not JSON.
|
|
150
|
+
}
|
|
151
|
+
return error;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
interface GeminiCliApiKeyPayload {
|
|
155
|
+
token?: unknown;
|
|
156
|
+
projectId?: unknown;
|
|
157
|
+
project_id?: unknown;
|
|
158
|
+
refreshToken?: unknown;
|
|
159
|
+
expiresAt?: unknown;
|
|
160
|
+
refresh?: unknown;
|
|
161
|
+
expires?: unknown;
|
|
162
|
+
}
|
|
163
|
+
interface ParsedGeminiCliCredentials {
|
|
164
|
+
accessToken: string;
|
|
165
|
+
projectId: string;
|
|
166
|
+
refreshToken?: string;
|
|
167
|
+
expiresAt?: number;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function normalizeExpiryMs(value: unknown): number | undefined {
|
|
171
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
return value < 10_000_000_000 ? value * 1000 : value;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function parseGeminiCliCredentials(apiKeyRaw: string): ParsedGeminiCliCredentials {
|
|
178
|
+
const invalidCredentialsMessage = "Invalid Google Cloud Code Assist credentials. Use /login to re-authenticate.";
|
|
179
|
+
const missingCredentialsMessage =
|
|
180
|
+
"Missing token or projectId in Google Cloud credentials. Use /login to re-authenticate.";
|
|
181
|
+
|
|
182
|
+
let parsed: GeminiCliApiKeyPayload;
|
|
183
|
+
try {
|
|
184
|
+
parsed = JSON.parse(apiKeyRaw) as GeminiCliApiKeyPayload;
|
|
185
|
+
} catch {
|
|
186
|
+
throw new Error(invalidCredentialsMessage);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const projectId =
|
|
190
|
+
typeof parsed.projectId === "string"
|
|
191
|
+
? parsed.projectId
|
|
192
|
+
: typeof parsed.project_id === "string"
|
|
193
|
+
? parsed.project_id
|
|
194
|
+
: undefined;
|
|
195
|
+
|
|
196
|
+
if (typeof parsed.token !== "string" || typeof projectId !== "string") {
|
|
197
|
+
throw new Error(missingCredentialsMessage);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const refreshToken =
|
|
201
|
+
typeof parsed.refreshToken === "string"
|
|
202
|
+
? parsed.refreshToken
|
|
203
|
+
: typeof parsed.refresh === "string"
|
|
204
|
+
? parsed.refresh
|
|
205
|
+
: undefined;
|
|
206
|
+
const expiresAt = normalizeExpiryMs(parsed.expiresAt ?? parsed.expires);
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
accessToken: parsed.token,
|
|
210
|
+
projectId,
|
|
211
|
+
refreshToken,
|
|
212
|
+
expiresAt,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function shouldRefreshGeminiCliCredentials(
|
|
217
|
+
expiresAt: number | undefined,
|
|
218
|
+
isAntigravity: boolean,
|
|
219
|
+
nowMs = Date.now(),
|
|
220
|
+
): boolean {
|
|
221
|
+
if (expiresAt === undefined) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const skewMs = isAntigravity ? ANTIGRAVITY_REFRESH_SKEW_MS : GOOGLE_GEMINI_REFRESH_SKEW_MS;
|
|
226
|
+
return nowMs + skewMs >= expiresAt;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
interface CloudCodeAssistRequest {
|
|
230
|
+
project: string;
|
|
231
|
+
model: string;
|
|
232
|
+
request: {
|
|
233
|
+
contents: Content[];
|
|
234
|
+
sessionId?: string;
|
|
235
|
+
systemInstruction?: { role?: string; parts: { text: string }[] };
|
|
236
|
+
generationConfig?: {
|
|
237
|
+
maxOutputTokens?: number;
|
|
238
|
+
temperature?: number;
|
|
239
|
+
topP?: number;
|
|
240
|
+
topK?: number;
|
|
241
|
+
minP?: number;
|
|
242
|
+
presencePenalty?: number;
|
|
243
|
+
repetitionPenalty?: number;
|
|
244
|
+
thinkingConfig?: ThinkingConfig;
|
|
245
|
+
};
|
|
246
|
+
tools?: { functionDeclarations: Record<string, unknown>[] }[] | undefined;
|
|
247
|
+
toolConfig?: {
|
|
248
|
+
functionCallingConfig: {
|
|
249
|
+
mode: FunctionCallingConfigMode;
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
// Evidence: Real Antigravity IDE sends preambleConfig with
|
|
253
|
+
// SYSTEM_INSTRUCTION_MODE_REPLACE to control how the server
|
|
254
|
+
// interprets the system instruction (replace vs append).
|
|
255
|
+
// Confirmed via network interception of official IDE traffic.
|
|
256
|
+
preambleConfig?: {
|
|
257
|
+
mode: "SYSTEM_INSTRUCTION_MODE_REPLACE";
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
requestType?: string;
|
|
261
|
+
userAgent?: string;
|
|
262
|
+
requestId?: string;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
interface CloudCodeAssistResponseChunk {
|
|
266
|
+
response?: {
|
|
267
|
+
candidates?: Array<{
|
|
268
|
+
content?: {
|
|
269
|
+
role: string;
|
|
270
|
+
parts?: Array<{
|
|
271
|
+
text?: string;
|
|
272
|
+
thought?: boolean;
|
|
273
|
+
thoughtSignature?: string;
|
|
274
|
+
functionCall?: {
|
|
275
|
+
name: string;
|
|
276
|
+
args: Record<string, unknown>;
|
|
277
|
+
id?: string;
|
|
278
|
+
};
|
|
279
|
+
}>;
|
|
280
|
+
};
|
|
281
|
+
finishReason?: string;
|
|
282
|
+
}>;
|
|
283
|
+
promptFeedback?: {
|
|
284
|
+
blockReason?: string;
|
|
285
|
+
};
|
|
286
|
+
usageMetadata?: {
|
|
287
|
+
promptTokenCount?: number;
|
|
288
|
+
candidatesTokenCount?: number;
|
|
289
|
+
thoughtsTokenCount?: number;
|
|
290
|
+
totalTokenCount?: number;
|
|
291
|
+
cachedContentTokenCount?: number;
|
|
292
|
+
};
|
|
293
|
+
modelVersion?: string;
|
|
294
|
+
responseId?: string;
|
|
295
|
+
};
|
|
296
|
+
traceId?: string;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|
300
|
+
model: Model<"google-gemini-cli">,
|
|
301
|
+
context: Context,
|
|
302
|
+
options?: GoogleGeminiCliOptions,
|
|
303
|
+
): AssistantMessageEventStream => {
|
|
304
|
+
const stream = new AssistantMessageEventStream();
|
|
305
|
+
|
|
306
|
+
(async () => {
|
|
307
|
+
const startTime = Date.now();
|
|
308
|
+
let firstTokenTime: number | undefined;
|
|
309
|
+
|
|
310
|
+
const output: AssistantMessage = {
|
|
311
|
+
role: "assistant",
|
|
312
|
+
content: [],
|
|
313
|
+
api: "google-gemini-cli" as Api,
|
|
314
|
+
provider: model.provider,
|
|
315
|
+
model: model.id,
|
|
316
|
+
usage: {
|
|
317
|
+
input: 0,
|
|
318
|
+
output: 0,
|
|
319
|
+
cacheRead: 0,
|
|
320
|
+
cacheWrite: 0,
|
|
321
|
+
totalTokens: 0,
|
|
322
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
323
|
+
},
|
|
324
|
+
stopReason: "stop",
|
|
325
|
+
timestamp: Date.now(),
|
|
326
|
+
};
|
|
327
|
+
let rawRequestDump: RawHttpRequestDump | undefined;
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
const apiKeyRaw = options?.apiKey;
|
|
331
|
+
if (!apiKeyRaw) {
|
|
332
|
+
throw new Error("Google Cloud Code Assist requires OAuth authentication. Use /login to authenticate.");
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const isAntigravity = model.provider === "google-antigravity";
|
|
336
|
+
const parsedCredentials = parseGeminiCliCredentials(apiKeyRaw);
|
|
337
|
+
// AuthStorage already refreshed credentials before threading them
|
|
338
|
+
// here (see {@link OAUTH_REFRESH_SKEW_MS}). If the credential lands
|
|
339
|
+
// expired we bail rather than POSTing a stale token; the next call
|
|
340
|
+
// — driven by AuthStorage's invalidate+retry path — will carry a
|
|
341
|
+
// fresh credential.
|
|
342
|
+
if (
|
|
343
|
+
shouldRefreshGeminiCliCredentials(parsedCredentials.expiresAt, isAntigravity) &&
|
|
344
|
+
parsedCredentials.expiresAt !== undefined &&
|
|
345
|
+
Date.now() >= parsedCredentials.expiresAt
|
|
346
|
+
) {
|
|
347
|
+
throw new Error(
|
|
348
|
+
"OAuth token expired before request — please retry; AuthStorage will refresh on the next attempt.",
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
const { accessToken, projectId } = parsedCredentials;
|
|
352
|
+
|
|
353
|
+
const baseUrl = model.baseUrl?.trim();
|
|
354
|
+
const endpoints = baseUrl ? [baseUrl] : isAntigravity ? ANTIGRAVITY_ENDPOINT_FALLBACKS : [DEFAULT_ENDPOINT];
|
|
355
|
+
|
|
356
|
+
let requestBody = buildRequest(model, context, projectId, options, isAntigravity);
|
|
357
|
+
const replacementPayload = await options?.onPayload?.(requestBody, model, options?.attemptScope);
|
|
358
|
+
if (replacementPayload !== undefined) {
|
|
359
|
+
requestBody = replacementPayload as typeof requestBody;
|
|
360
|
+
}
|
|
361
|
+
const headers = isAntigravity
|
|
362
|
+
? getAntigravityRequestHeaders() // Evidence: UA = "antigravity-ide" (disassembly 0x5ecb1dd)
|
|
363
|
+
: getGeminiCliHeaders(model.id);
|
|
364
|
+
|
|
365
|
+
const requestHeaders = {
|
|
366
|
+
Authorization: `Bearer ${accessToken}`,
|
|
367
|
+
"Content-Type": "application/json",
|
|
368
|
+
Accept: "text/event-stream",
|
|
369
|
+
...headers,
|
|
370
|
+
...(needsClaudeThinkingBetaHeader(model) ? { "anthropic-beta": CLAUDE_THINKING_BETA_HEADER } : {}),
|
|
371
|
+
...(options?.headers ?? {}),
|
|
372
|
+
};
|
|
373
|
+
let requestBodyJson = JSON.stringify(requestBody);
|
|
374
|
+
rawRequestDump = {
|
|
375
|
+
provider: model.provider,
|
|
376
|
+
api: output.api,
|
|
377
|
+
model: model.id,
|
|
378
|
+
method: "POST",
|
|
379
|
+
body: requestBody,
|
|
380
|
+
headers: requestHeaders,
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
const sentForcedToolChoice =
|
|
384
|
+
(requestBody.request.toolConfig?.functionCallingConfig?.mode === "ANY" ||
|
|
385
|
+
requestBody.request.toolConfig?.functionCallingConfig?.mode === "VALIDATED") &&
|
|
386
|
+
options?.toolChoice !== undefined &&
|
|
387
|
+
options.toolChoice !== "auto" &&
|
|
388
|
+
options.toolChoice !== "none";
|
|
389
|
+
options.onStreamCreated?.();
|
|
390
|
+
let response = await fetchWithRetry(
|
|
391
|
+
attempt => `${endpoints[Math.min(attempt, endpoints.length - 1)]}/v1internal:streamGenerateContent?alt=sse`,
|
|
392
|
+
{
|
|
393
|
+
method: "POST",
|
|
394
|
+
headers: requestHeaders,
|
|
395
|
+
body: requestBodyJson,
|
|
396
|
+
signal: options?.signal,
|
|
397
|
+
maxAttempts: resolveRetryBudget(options?.requestMaxRetries, MAX_RETRIES) + 1,
|
|
398
|
+
defaultDelayMs: attempt => BASE_DELAY_MS * 2 ** attempt,
|
|
399
|
+
maxDelayMs: options?.maxRetryDelayMs ?? RATE_LIMIT_BUDGET_MS,
|
|
400
|
+
fetch: options?.fetch,
|
|
401
|
+
},
|
|
402
|
+
);
|
|
403
|
+
if (!response.ok && sentForcedToolChoice) {
|
|
404
|
+
const errorText = await response.text();
|
|
405
|
+
const error = createGeminiCliHttpError(response, errorText);
|
|
406
|
+
if (
|
|
407
|
+
!options?.fallbackManaged &&
|
|
408
|
+
!options?.disableProviderRetries &&
|
|
409
|
+
firstTokenTime === undefined &&
|
|
410
|
+
isForcedToolChoiceUnsupportedError(error, true)
|
|
411
|
+
) {
|
|
412
|
+
const beforeMark = resolveToolChoice(model, options?.toolChoice);
|
|
413
|
+
markToolChoiceIncapability(model, "auto", error.message);
|
|
414
|
+
stream.push({
|
|
415
|
+
type: "toolChoiceIncapability",
|
|
416
|
+
api: model.api,
|
|
417
|
+
provider: model.provider,
|
|
418
|
+
model: model.id,
|
|
419
|
+
requestedLevel: beforeMark.requestedLevel,
|
|
420
|
+
resolvedLevel: "auto",
|
|
421
|
+
reason: error.message,
|
|
422
|
+
registryKey: beforeMark.registryKey,
|
|
423
|
+
});
|
|
424
|
+
requestBody = {
|
|
425
|
+
...requestBody,
|
|
426
|
+
request: { ...requestBody.request, toolConfig: undefined },
|
|
427
|
+
};
|
|
428
|
+
requestBodyJson = JSON.stringify(requestBody);
|
|
429
|
+
rawRequestDump = { ...rawRequestDump, body: requestBody };
|
|
430
|
+
options.onStreamCreated?.();
|
|
431
|
+
response = await fetchWithRetry(
|
|
432
|
+
attempt =>
|
|
433
|
+
`${endpoints[Math.min(attempt, endpoints.length - 1)]}/v1internal:streamGenerateContent?alt=sse`,
|
|
434
|
+
{
|
|
435
|
+
method: "POST",
|
|
436
|
+
headers: requestHeaders,
|
|
437
|
+
body: requestBodyJson,
|
|
438
|
+
signal: options?.signal,
|
|
439
|
+
maxAttempts: 1,
|
|
440
|
+
defaultDelayMs: attempt => BASE_DELAY_MS * 2 ** attempt,
|
|
441
|
+
maxDelayMs: options?.maxRetryDelayMs ?? RATE_LIMIT_BUDGET_MS,
|
|
442
|
+
fetch: options?.fetch,
|
|
443
|
+
},
|
|
444
|
+
);
|
|
445
|
+
} else {
|
|
446
|
+
throw error;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (!response.ok) {
|
|
450
|
+
const errorText = await response.text();
|
|
451
|
+
throw createGeminiCliHttpError(response, errorText);
|
|
452
|
+
}
|
|
453
|
+
const requestUrl = response.url;
|
|
454
|
+
|
|
455
|
+
let started = false;
|
|
456
|
+
const ensureStarted = () => {
|
|
457
|
+
if (!started) {
|
|
458
|
+
if (!firstTokenTime) firstTokenTime = Date.now();
|
|
459
|
+
stream.push({ type: "start", partial: output });
|
|
460
|
+
started = true;
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
const resetOutput = () => {
|
|
465
|
+
output.content = [];
|
|
466
|
+
output.usage = {
|
|
467
|
+
input: 0,
|
|
468
|
+
output: 0,
|
|
469
|
+
cacheRead: 0,
|
|
470
|
+
cacheWrite: 0,
|
|
471
|
+
totalTokens: 0,
|
|
472
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
473
|
+
};
|
|
474
|
+
output.stopReason = "stop";
|
|
475
|
+
output.errorMessage = undefined;
|
|
476
|
+
output.timestamp = Date.now();
|
|
477
|
+
started = false;
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
const streamResponse = async (activeResponse: Response): Promise<boolean> => {
|
|
481
|
+
if (!activeResponse.body) {
|
|
482
|
+
throw new Error("No response body");
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
let hasContent = false;
|
|
486
|
+
let providerSafetyStop = false;
|
|
487
|
+
let currentBlock: TextContent | ThinkingContent | null = null;
|
|
488
|
+
const blocks = output.content;
|
|
489
|
+
const blockIndex = () => blocks.length - 1;
|
|
490
|
+
|
|
491
|
+
for await (const chunk of readSseJson<CloudCodeAssistResponseChunk>(
|
|
492
|
+
activeResponse.body!,
|
|
493
|
+
options?.signal,
|
|
494
|
+
event =>
|
|
495
|
+
options?.onSseEvent?.(
|
|
496
|
+
{ event: event.event, data: event.data, raw: [...event.raw] },
|
|
497
|
+
model,
|
|
498
|
+
options?.attemptScope,
|
|
499
|
+
),
|
|
500
|
+
)) {
|
|
501
|
+
const responseData = chunk.response;
|
|
502
|
+
if (!responseData) continue;
|
|
503
|
+
|
|
504
|
+
const candidate = responseData.candidates?.[0];
|
|
505
|
+
if (candidate?.content?.parts) {
|
|
506
|
+
for (const part of candidate.content.parts) {
|
|
507
|
+
if (part.text !== undefined) {
|
|
508
|
+
hasContent = true;
|
|
509
|
+
const isThinking = isThinkingPart(part);
|
|
510
|
+
if (
|
|
511
|
+
!currentBlock ||
|
|
512
|
+
(isThinking && currentBlock.type !== "thinking") ||
|
|
513
|
+
(!isThinking && currentBlock.type !== "text")
|
|
514
|
+
) {
|
|
515
|
+
if (currentBlock) {
|
|
516
|
+
pushBlockEndEvent(currentBlock, blockIndex(), output, stream);
|
|
517
|
+
}
|
|
518
|
+
currentBlock = startTextOrThinkingBlock(isThinking, output, stream, ensureStarted);
|
|
519
|
+
}
|
|
520
|
+
if (currentBlock.type === "thinking") {
|
|
521
|
+
currentBlock.thinking += part.text;
|
|
522
|
+
currentBlock.thinkingSignature = retainThoughtSignature(
|
|
523
|
+
currentBlock.thinkingSignature,
|
|
524
|
+
part.thoughtSignature,
|
|
525
|
+
);
|
|
526
|
+
stream.push({
|
|
527
|
+
type: "thinking_delta",
|
|
528
|
+
contentIndex: blockIndex(),
|
|
529
|
+
delta: part.text,
|
|
530
|
+
partial: output,
|
|
531
|
+
});
|
|
532
|
+
} else {
|
|
533
|
+
currentBlock.text += part.text;
|
|
534
|
+
currentBlock.textSignature = retainThoughtSignature(
|
|
535
|
+
currentBlock.textSignature,
|
|
536
|
+
part.thoughtSignature,
|
|
537
|
+
);
|
|
538
|
+
stream.push({
|
|
539
|
+
type: "text_delta",
|
|
540
|
+
contentIndex: blockIndex(),
|
|
541
|
+
delta: part.text,
|
|
542
|
+
partial: output,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if (part.functionCall) {
|
|
548
|
+
hasContent = true;
|
|
549
|
+
if (currentBlock) {
|
|
550
|
+
pushBlockEndEvent(currentBlock, blockIndex(), output, stream);
|
|
551
|
+
currentBlock = null;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const providedId = part.functionCall.id;
|
|
555
|
+
const needsNewId =
|
|
556
|
+
!providedId || output.content.some(b => b.type === "toolCall" && b.id === providedId);
|
|
557
|
+
const toolCallId = needsNewId ? nextToolCallId(part.functionCall.name || "tool") : providedId;
|
|
558
|
+
|
|
559
|
+
const toolCall: ToolCall = {
|
|
560
|
+
type: "toolCall",
|
|
561
|
+
id: toolCallId,
|
|
562
|
+
name: part.functionCall.name || "",
|
|
563
|
+
arguments: part.functionCall.args as Record<string, unknown>,
|
|
564
|
+
...(part.thoughtSignature && { thoughtSignature: part.thoughtSignature }),
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
output.content.push(toolCall);
|
|
568
|
+
ensureStarted();
|
|
569
|
+
pushToolCallEvents(toolCall, blockIndex(), output, stream);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (candidate?.finishReason) {
|
|
575
|
+
if (isGoogleCandidateSafetyStopReason(candidate.finishReason)) {
|
|
576
|
+
providerSafetyStop = true;
|
|
577
|
+
hasContent = true;
|
|
578
|
+
// Adapter-minted terminal authority from the parsed
|
|
579
|
+
// structured finish reason (#4777).
|
|
580
|
+
mintProviderSafetyStop(
|
|
581
|
+
output,
|
|
582
|
+
candidate.finishReason,
|
|
583
|
+
PROVIDER_SAFETY_STOP_ADAPTER_CAPABILITY,
|
|
584
|
+
options?.fetch,
|
|
585
|
+
isProviderSafetyStopAdapterInvocation(options),
|
|
586
|
+
);
|
|
587
|
+
output.stopReason = "error";
|
|
588
|
+
} else if (!providerSafetyStop) {
|
|
589
|
+
output.stopReason = mapStopReasonString(candidate.finishReason);
|
|
590
|
+
if (output.stopReason === "stop" && output.content.some(b => b.type === "toolCall")) {
|
|
591
|
+
output.stopReason = "toolUse";
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const blockReason = getGooglePromptBlockReason(responseData.promptFeedback);
|
|
597
|
+
if (blockReason) {
|
|
598
|
+
hasContent = true;
|
|
599
|
+
if (isGooglePromptSafetyStopReason(blockReason)) {
|
|
600
|
+
providerSafetyStop = true;
|
|
601
|
+
// Prompt-level block reason: adapter-minted authority (#4777).
|
|
602
|
+
mintProviderSafetyStop(
|
|
603
|
+
output,
|
|
604
|
+
blockReason,
|
|
605
|
+
PROVIDER_SAFETY_STOP_ADAPTER_CAPABILITY,
|
|
606
|
+
options?.fetch,
|
|
607
|
+
isProviderSafetyStopAdapterInvocation(options),
|
|
608
|
+
);
|
|
609
|
+
output.stopReason = "error";
|
|
610
|
+
} else if (!providerSafetyStop) {
|
|
611
|
+
output.stopReason = "error";
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (responseData.usageMetadata) {
|
|
616
|
+
// promptTokenCount includes cachedContentTokenCount, so subtract to get fresh input
|
|
617
|
+
const promptTokens = responseData.usageMetadata.promptTokenCount || 0;
|
|
618
|
+
const cacheReadTokens = responseData.usageMetadata.cachedContentTokenCount || 0;
|
|
619
|
+
const thinkingTokens = responseData.usageMetadata.thoughtsTokenCount || 0;
|
|
620
|
+
output.usage = {
|
|
621
|
+
input: promptTokens - cacheReadTokens,
|
|
622
|
+
output: (responseData.usageMetadata.candidatesTokenCount || 0) + thinkingTokens,
|
|
623
|
+
cacheRead: cacheReadTokens,
|
|
624
|
+
cacheWrite: 0,
|
|
625
|
+
totalTokens: responseData.usageMetadata.totalTokenCount || 0,
|
|
626
|
+
...(thinkingTokens > 0 ? { reasoningTokens: thinkingTokens } : {}),
|
|
627
|
+
cost: {
|
|
628
|
+
input: 0,
|
|
629
|
+
output: 0,
|
|
630
|
+
cacheRead: 0,
|
|
631
|
+
cacheWrite: 0,
|
|
632
|
+
total: 0,
|
|
633
|
+
},
|
|
634
|
+
};
|
|
635
|
+
calculateCost(model, output.usage);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
if (currentBlock) {
|
|
640
|
+
pushBlockEndEvent(currentBlock, blockIndex(), output, stream);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
return hasContent;
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
let receivedContent = false;
|
|
647
|
+
let currentResponse = response;
|
|
648
|
+
|
|
649
|
+
const emptyStreamRetryBudget = resolveRetryBudget(options?.streamMaxRetries, MAX_EMPTY_STREAM_RETRIES);
|
|
650
|
+
for (let emptyAttempt = 0; emptyAttempt <= emptyStreamRetryBudget; emptyAttempt++) {
|
|
651
|
+
if (options?.signal?.aborted) {
|
|
652
|
+
throw new Error("Request was aborted");
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
if (emptyAttempt > 0) {
|
|
656
|
+
const backoffMs = EMPTY_STREAM_BASE_DELAY_MS * 2 ** (emptyAttempt - 1);
|
|
657
|
+
try {
|
|
658
|
+
await scheduler.wait(backoffMs, { signal: options?.signal });
|
|
659
|
+
} catch {
|
|
660
|
+
// Normalize AbortError to expected message for consistent error handling
|
|
661
|
+
throw new Error("Request was aborted");
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
if (!requestUrl) {
|
|
665
|
+
throw new Error("Missing request URL");
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
currentResponse = await (options?.fetch ?? fetch)(requestUrl, {
|
|
669
|
+
method: "POST",
|
|
670
|
+
headers: requestHeaders,
|
|
671
|
+
body: requestBodyJson,
|
|
672
|
+
signal: options?.signal,
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
if (!currentResponse.ok) {
|
|
676
|
+
const retryErrorText = await currentResponse.text();
|
|
677
|
+
throw createGeminiCliHttpError(currentResponse, retryErrorText, false);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const streamed = await streamResponse(currentResponse);
|
|
682
|
+
if (streamed) {
|
|
683
|
+
receivedContent = true;
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (emptyAttempt < emptyStreamRetryBudget) {
|
|
688
|
+
resetOutput();
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if (!receivedContent) {
|
|
693
|
+
throw new Error("Cloud Code Assist API returned an empty response");
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
if (options?.signal?.aborted) {
|
|
697
|
+
throw new Error("Request was aborted");
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (output.stopReason === "aborted" || output.stopReason === "error") {
|
|
701
|
+
throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
output.duration = Date.now() - startTime;
|
|
705
|
+
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
706
|
+
stream.push({ type: "done", reason: output.stopReason, message: output });
|
|
707
|
+
stream.end();
|
|
708
|
+
} catch (error) {
|
|
709
|
+
for (const block of output.content) {
|
|
710
|
+
if ("index" in block) {
|
|
711
|
+
delete (block as { index?: number }).index;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
715
|
+
output.errorStatus = extractHttpStatusFromError(error);
|
|
716
|
+
output.transportFailure = transportFailureFacts(error);
|
|
717
|
+
output.errorMessage = await appendRawHttpRequestDumpFor400(
|
|
718
|
+
error instanceof Error ? error.message : JSON.stringify(error),
|
|
719
|
+
error,
|
|
720
|
+
rawRequestDump,
|
|
721
|
+
);
|
|
722
|
+
output.duration = Date.now() - startTime;
|
|
723
|
+
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
724
|
+
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
725
|
+
stream.end();
|
|
726
|
+
}
|
|
727
|
+
})();
|
|
728
|
+
|
|
729
|
+
return stream;
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
const INT63_MASK = (1n << 63n) - 1n;
|
|
733
|
+
const ANTIGRAVITY_RANDOM_BOUND = 9_000_000_000_000_000_000n;
|
|
734
|
+
|
|
735
|
+
function formatSignedDecimalSessionId(value: bigint): string {
|
|
736
|
+
return `-${value.toString()}`;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
function deriveSignedDecimalFromHash(text: string): string {
|
|
740
|
+
const digest = createHash("sha256").update(text).digest();
|
|
741
|
+
let value = 0n;
|
|
742
|
+
for (let index = 0; index < 8; index += 1) {
|
|
743
|
+
value = (value << 8n) | BigInt(digest[index] ?? 0);
|
|
744
|
+
}
|
|
745
|
+
return formatSignedDecimalSessionId(value & INT63_MASK);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
function randomBoundedInt63(maxExclusive: bigint): bigint {
|
|
749
|
+
while (true) {
|
|
750
|
+
const bytes = randomBytes(8);
|
|
751
|
+
let value = 0n;
|
|
752
|
+
for (const byte of bytes) {
|
|
753
|
+
value = (value << 8n) | BigInt(byte);
|
|
754
|
+
}
|
|
755
|
+
value &= INT63_MASK;
|
|
756
|
+
if (value < maxExclusive) {
|
|
757
|
+
return value;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
function randomSignedDecimalSessionId(): string {
|
|
763
|
+
return formatSignedDecimalSessionId(randomBoundedInt63(ANTIGRAVITY_RANDOM_BOUND));
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
function getFirstUserTextForAntigravitySession(context: Context): string | undefined {
|
|
767
|
+
for (const message of context.messages) {
|
|
768
|
+
if (message.role !== "user") {
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (typeof message.content === "string") {
|
|
773
|
+
return message.content;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
if (Array.isArray(message.content)) {
|
|
777
|
+
const firstTextPart = message.content.find((item): item is TextContent => item.type === "text");
|
|
778
|
+
return firstTextPart?.text;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
return undefined;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
return undefined;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
function deriveAntigravitySessionId(context: Context): string {
|
|
788
|
+
const text = getFirstUserTextForAntigravitySession(context);
|
|
789
|
+
if (text && text.trim().length > 0) {
|
|
790
|
+
return deriveSignedDecimalFromHash(text);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
return randomSignedDecimalSessionId();
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
function normalizeAntigravityTools(
|
|
797
|
+
tools: CloudCodeAssistRequest["request"]["tools"],
|
|
798
|
+
): CloudCodeAssistRequest["request"]["tools"] {
|
|
799
|
+
return tools?.map(tool => ({
|
|
800
|
+
...tool,
|
|
801
|
+
functionDeclarations: tool.functionDeclarations.map(declaration => {
|
|
802
|
+
if ("parameters" in declaration) {
|
|
803
|
+
return declaration;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
const { parametersJsonSchema, ...rest } = declaration;
|
|
807
|
+
return {
|
|
808
|
+
...rest,
|
|
809
|
+
parameters: normalizeSchemaForCCA(parametersJsonSchema),
|
|
810
|
+
};
|
|
811
|
+
}),
|
|
812
|
+
}));
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
export function buildRequest(
|
|
816
|
+
model: Model<"google-gemini-cli">,
|
|
817
|
+
context: Context,
|
|
818
|
+
projectId: string,
|
|
819
|
+
options: GoogleGeminiCliOptions = {},
|
|
820
|
+
isAntigravity = false,
|
|
821
|
+
): CloudCodeAssistRequest {
|
|
822
|
+
const systemPrompts = normalizeSystemPrompts(context.systemPrompt);
|
|
823
|
+
const contents = convertMessages(model, context);
|
|
824
|
+
const generationConfig: CloudCodeAssistRequest["request"]["generationConfig"] = {};
|
|
825
|
+
if (options.temperature !== undefined) {
|
|
826
|
+
generationConfig.temperature = options.temperature;
|
|
827
|
+
}
|
|
828
|
+
if (options.maxTokens !== undefined) {
|
|
829
|
+
generationConfig.maxOutputTokens = options.maxTokens;
|
|
830
|
+
}
|
|
831
|
+
if (options.topP !== undefined) {
|
|
832
|
+
generationConfig.topP = options.topP;
|
|
833
|
+
}
|
|
834
|
+
if (options.topK !== undefined) {
|
|
835
|
+
generationConfig.topK = options.topK;
|
|
836
|
+
}
|
|
837
|
+
if (options.minP !== undefined) {
|
|
838
|
+
generationConfig.minP = options.minP;
|
|
839
|
+
}
|
|
840
|
+
if (options.presencePenalty !== undefined) {
|
|
841
|
+
generationConfig.presencePenalty = options.presencePenalty;
|
|
842
|
+
}
|
|
843
|
+
if (options.repetitionPenalty !== undefined) {
|
|
844
|
+
generationConfig.repetitionPenalty = options.repetitionPenalty;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// Thinking config
|
|
848
|
+
if (options.thinking?.enabled && model.reasoning) {
|
|
849
|
+
generationConfig.thinkingConfig = {
|
|
850
|
+
includeThoughts: true,
|
|
851
|
+
};
|
|
852
|
+
// Gemini 3 models use thinkingLevel, older models use thinkingBudget
|
|
853
|
+
if (options.thinking.level !== undefined) {
|
|
854
|
+
// Cast to any since our GoogleThinkingLevel mirrors Google's ThinkingLevel enum values
|
|
855
|
+
generationConfig.thinkingConfig.thinkingLevel = options.thinking.level as any;
|
|
856
|
+
} else if (options.thinking.budgetTokens !== undefined) {
|
|
857
|
+
generationConfig.thinkingConfig.thinkingBudget = options.thinking.budgetTokens;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
const request: CloudCodeAssistRequest["request"] = {
|
|
862
|
+
contents,
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
if (isAntigravity) {
|
|
866
|
+
request.sessionId = deriveAntigravitySessionId(context);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// System instruction must be object with parts, not plain string.
|
|
870
|
+
// Evidence: Real Antigravity IDE sets role: "user" on systemInstruction
|
|
871
|
+
// (confirmed in request body dumps from network interception).
|
|
872
|
+
// Only applied for Antigravity path — standard gemini-cli omits role.
|
|
873
|
+
if (systemPrompts.length > 0) {
|
|
874
|
+
request.systemInstruction = {
|
|
875
|
+
...(isAntigravity && { role: "user" }),
|
|
876
|
+
parts: systemPrompts.map(text => ({ text })),
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
if (Object.keys(generationConfig).length > 0) {
|
|
881
|
+
request.generationConfig = generationConfig;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
const resolvedToolChoice = resolveToolChoice(model, options.toolChoice);
|
|
885
|
+
if (context.tools && context.tools.length > 0) {
|
|
886
|
+
const convertedTools = convertTools(context.tools, model);
|
|
887
|
+
request.tools = isAntigravity ? normalizeAntigravityTools(convertedTools) : convertedTools;
|
|
888
|
+
const resolved = resolvedToolChoice;
|
|
889
|
+
if (resolved.resolvedChoice) {
|
|
890
|
+
request.toolConfig = {
|
|
891
|
+
functionCallingConfig: {
|
|
892
|
+
mode: mapToolChoice(resolved.resolvedChoice as string),
|
|
893
|
+
},
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
if (isAntigravity && !isClaudeModel(model.id) && request.generationConfig?.maxOutputTokens !== undefined) {
|
|
899
|
+
delete request.generationConfig.maxOutputTokens;
|
|
900
|
+
if (Object.keys(request.generationConfig).length === 0) {
|
|
901
|
+
delete request.generationConfig;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// Claude Antigravity: use VALIDATED mode only when tools are present
|
|
906
|
+
// and the caller hasn't explicitly requested "none" tool choice.
|
|
907
|
+
//
|
|
908
|
+
// Evidence:
|
|
909
|
+
// - Real Antigravity IDE sends VALIDATED for Claude requests with tools
|
|
910
|
+
// (confirmed via network interception of official IDE traffic)
|
|
911
|
+
// - The original Vibrato code used resolvedToolChoice.resolvedLevel to gate
|
|
912
|
+
// VALIDATED, but the real IDE doesn't check tool choice resolution —
|
|
913
|
+
// it sends VALIDATED whenever tools exist and toolChoice != "none"
|
|
914
|
+
// - omp reference: packages/ai/src/providers/google-gemini-cli.ts
|
|
915
|
+
// `antigravityClaudeToolConfig` guard pattern
|
|
916
|
+
if (
|
|
917
|
+
isAntigravity &&
|
|
918
|
+
isClaudeModel(model.id) &&
|
|
919
|
+
context.tools &&
|
|
920
|
+
context.tools.length > 0 &&
|
|
921
|
+
options?.toolChoice !== "none"
|
|
922
|
+
) {
|
|
923
|
+
request.toolConfig = {
|
|
924
|
+
functionCallingConfig: {
|
|
925
|
+
mode: "VALIDATED" as FunctionCallingConfigMode,
|
|
926
|
+
},
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// Stateless system instruction injection: send on EVERY Antigravity request.
|
|
931
|
+
// This is safer than client-side session dedup because:
|
|
932
|
+
// - preambleConfig server-side persistence is unproven
|
|
933
|
+
// - A failed first request would poison the session if we skipped injection
|
|
934
|
+
// - Token cost is acceptable for Antigravity's long-context models
|
|
935
|
+
//
|
|
936
|
+
// Evidence:
|
|
937
|
+
// - Real Antigravity IDE sends the full system prompt on every request
|
|
938
|
+
// (confirmed via repeated request dumps — no client-side dedup observed)
|
|
939
|
+
// - The [ignore] wrapper was a Vibrato-original addition not present in the
|
|
940
|
+
// real IDE wire format. Removed for byte-faithful emulation.
|
|
941
|
+
// - preambleConfig: { mode: "SYSTEM_INSTRUCTION_MODE_REPLACE" } is the
|
|
942
|
+
// mechanism the real IDE uses to deliver system instructions. Without it,
|
|
943
|
+
// the server may append (not replace) the system prompt.
|
|
944
|
+
// - omp reference: `sessionSystemInstructionSent` Map was omp's approach;
|
|
945
|
+
// we chose stateless injection for simplicity and safety.
|
|
946
|
+
if (isAntigravity && shouldInjectAntigravitySystemInstruction(model.id)) {
|
|
947
|
+
const existingParts = request.systemInstruction?.parts ?? [];
|
|
948
|
+
request.systemInstruction = {
|
|
949
|
+
role: "user",
|
|
950
|
+
parts: [{ text: ANTIGRAVITY_SYSTEM_INSTRUCTION }, ...existingParts],
|
|
951
|
+
};
|
|
952
|
+
request.preambleConfig = {
|
|
953
|
+
mode: "SYSTEM_INSTRUCTION_MODE_REPLACE",
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
return {
|
|
958
|
+
project: projectId,
|
|
959
|
+
model: model.id,
|
|
960
|
+
request,
|
|
961
|
+
...(isAntigravity
|
|
962
|
+
? {
|
|
963
|
+
requestType: "agent",
|
|
964
|
+
userAgent: "antigravity",
|
|
965
|
+
requestId: `agent-${randomUUID()}`,
|
|
966
|
+
}
|
|
967
|
+
: {}),
|
|
968
|
+
};
|
|
969
|
+
}
|