Skip to content

fix(antigravity): reject caller-supplied tools instead of silently ignoring them - #405

Open
r-uben wants to merge 6 commits into
pleaseai:mainfrom
r-uben:fix/404-antigravity-reject-caller-tools
Open

fix(antigravity): reject caller-supplied tools instead of silently ignoring them#405
r-uben wants to merge 6 commits into
pleaseai:mainfrom
r-uben:fix/404-antigravity-reject-caller-tools

Conversation

@r-uben

@r-uben r-uben commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

The antigravity_cli transport never read tools or tool_choice. A request carrying
them got a 200 with a text-only body and stop_reason: "end_turn" — including when the
caller sent tool_choice: {"type": "any"}, which the Messages contract says must produce a
tool_use block.

Callers that drive their own agent loop cannot act on that response. In practice a Claude
Code subagent goes idle with no result, or dies with a confusing mid-response server error.
Nothing told the caller the provider could not serve its tools.

This fails the request closed instead, with a 400 invalid_request_error naming the
limitation.

Why not forward the tools instead

agy resolves its own tool calls internally and has no mode that hands them back. agy --help (1.1.15) exposes only --dangerously-skip-permissions and the
--input-format/--output-format stream-json pair — there is no "emit tool requests
instead of executing them" mode to translate. So this is not "add tool support"; it is
"stop reporting success for a request we silently degraded".

Callers that need a real tool loop should use the antigravity HTTP provider or gemini,
both of which translate tools and tool_choice properly.

The one judgement call

tool_choice: {"type": "none"} is exempt. The caller has declared it does not want tool
calls, so a text-only answer is exactly what it asked for; refusing it would break callers
that pass a tool list they never intend the model to use.

Everything else is refused, including a bare tools array with no tool_choice — which is
the shape Claude Code subagents actually send, and therefore the shape that has to fail
loudly for this fix to be worth anything. An empty tools: [] carries no capability
request and is not refused.

Test plan

Five unit tests in src/adapters/antigravity/mod.rs:

  • caller_tools_without_a_choice_are_rejected — the reported shape
  • a_forcing_tool_choice_is_rejectedtool_choice: any with no tools
  • tool_choice_none_is_allowed_even_alongside_tools — the exemption
  • an_empty_tools_array_is_not_a_tool_request — no false positive
  • a_plain_prompt_is_untouched — the ordinary path

Local gate green: cargo fmt --all --check clean, cargo clippy --all-targets --all-features -- -D warnings clean, cargo test --all-features --workspace 1695 passed /
0 failed plus every integration suite.

Reproduced against a live gateway before and after, on gemini-3.6-flash and
gemini-3.1-pro.

Docs

  • README.md and site/src/content/docs/guides/providers.mdx — both described the old
    quiet-drop behavior; now state the refusal and the none exemption.
  • site/src/content/docs/reference/configuration.md and its ko/ja/zh-cn copies — the
    kind row gains the same clause.
  • The README translations do not carry the antigravity-cli paragraph at all, so there was
    nothing to keep in sync there.

Note on the deprecated transport

This touches a transport the project has deprecated in favour of the antigravity HTTP
provider, which is normally an argument against spending review on it. Worth flagging that
the HTTP path is not universally usable yet: on my Antigravity subscription it returns
429 Resource has been exhausted for every model, including a bare prompt with no tools,
while the agy CLI path serves the same models on the same Google account at the same
moment. Auth and project discovery both succeed — Google just refuses the quota. So the
deprecated transport is still the working one for at least some subscriptions, and a silent
hang is a poor thing to leave them on.

Closes #404


Summary by cubic

Rejects caller-supplied tools in the antigravity_cli transport and fails closed with a 400 invalid_request_error. Previously it silently dropped tools/tool_choice and returned a text-only 200 (stop_reason: "end_turn"), which broke agent loops and violated tool_choice: {"type":"any"}. Closes #404.

  • Rejects only requests that actually ask for a tool call: a non-empty tools array or tool_choice of any/tool; accepts tool_choice: {"type":"none"}, tool_choice: {"type":"auto"} with no tools, and tools: [].
  • Error names antigravity-cli and points callers to antigravity/gemini; unit tests cover refusal and exemptions; README and guides/reference (en/ja/ko/zh-cn) document the rule.

Migration

  • To drive a tool loop, route to antigravity or gemini; otherwise send a plain prompt or set tool_choice: {"type":"none"}. tool_choice: {"type":"auto"} with no tools and tools: [] are accepted.

Written for commit e598e93. Summary will update on new commits.

@greptile-apps

greptile-apps Bot commented Aug 19, 2026

Copy link
Copy Markdown

Greptile Summary

The PR makes antigravity-cli reject unsupported caller-supplied tool requests instead of silently returning text-only responses.

  • Adds request validation and focused unit coverage for forced, automatic, disabled, and empty tool configurations.
  • Documents the refusal behavior and supported exemptions across the provider guide, configuration reference, and translated READMEs.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/adapters/antigravity/mod.rs Adds early validation for unsupported tool requests with tests covering the accepted and rejected request shapes.
README.md Documents the CLI transport’s tool-request refusal behavior and exemptions.
site/src/content/docs/guides/providers.mdx Expands provider guidance to explain why caller-controlled tool loops are unsupported and which alternatives to use.
README.ja.md Adds a Japanese Antigravity CLI section consistent with the English operational and security guidance.
README.ko.md Adds a Korean Antigravity CLI section consistent with the English operational and security guidance.
README.zh-CN.md Adds a Simplified Chinese Antigravity CLI section consistent with the English operational and security guidance.

Reviews (4): Last reviewed commit: "Merge branch 'main' into fix/404-antigra..." | Re-trigger Greptile

Comment thread README.md Outdated

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces validation to reject requests carrying caller-supplied tools or unsupported tool_choice values in the Antigravity provider, returning a 400 Bad Request instead of silently ignoring them. Documentation and tests have been updated accordingly. Feedback suggests improving the robustness of the tool_choice check by supporting both the object format {"type": "none"} and the plain string format "none".

Comment thread src/adapters/antigravity/mod.rs Outdated
Comment on lines +628 to +631
let choice = request.get("tool_choice").filter(|c| !c.is_null());
if choice.and_then(|c| c.get("type")).and_then(Value::as_str) == Some("none") {
return Ok(());
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

[MEDIUM] Support both object and string formats for "none" tool choice

Problem: The current implementation only exempts tool_choice when it is an object of shape {"type": "none"}. However, some client libraries or API translation layers may normalize or pass tool_choice as a plain string "none" (which is standard in OpenAI-compatible APIs). If a client sends "none" as a string, the request will be rejected even though the caller explicitly requested no tools.
Rationale: Robustness and defensive programming principles. Ensuring compatibility with common client variations prevents unexpected 400 errors.
Suggestion: Update the check to support both the object shape {"type": "none"} and the plain string "none".

Suggested change
let choice = request.get("tool_choice").filter(|c| !c.is_null());
if choice.and_then(|c| c.get("type")).and_then(Value::as_str) == Some("none") {
return Ok(());
}
let choice = request.get("tool_choice").filter(|c| !c.is_null());
let is_none = choice.and_then(|c| c.get("type")).and_then(Value::as_str) == Some("none")
|| choice.and_then(Value::as_str) == Some("none");
if is_none {
return Ok(());
}
References
  1. Ensure the code behaves as intended and handles edge cases defensively. (link)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c91adac57a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread README.md Outdated
**Antigravity has two transports.** The `antigravity` provider talks to the Google Antigravity backend over HTTP, authenticated with `shunt login antigravity` — a Google authorization-code flow using Antigravity's own OAuth client and scopes, so a Gemini CLI login cannot be reused for it. It speaks the same Code Assist protocol as the `gemini` provider and currently serves the Gemini-family Antigravity models; the Claude models Antigravity also offers need request rewrites that are not implemented yet (#368).

**`antigravity-cli` is deprecated and is arbitrary code execution.** It runs the local `agy` binary in agentic mode: the CLI uses its own tools to do the work and shunt streams its progress back as Anthropic SSE. A `tools` array on the request is therefore not forwarded and no `tool_use` block is ever returned. Because a non-interactive run cannot answer a permission prompt, `agy` runs with `--dangerously-skip-permissions`, so **treat this provider as arbitrary code execution as the user running shunt**. Two settings bound it: `sandbox` (default `true`) passes `--sandbox`, which keeps reads and writes inside the workspace and is what actually contains the agent; `workspace_roots` decides only where it may *start*, gating the `Working directory:` path taken from the request's system prompt (client-controlled text) to canonicalized paths under roots you list. Keep the sandbox on and the bind on loopback. Prefer the `antigravity` provider above, which needs none of this. See the [providers guide](https://shunt.dev/guides/providers/).
**`antigravity-cli` is deprecated and is arbitrary code execution.** It runs the local `agy` binary in agentic mode: the CLI uses its own tools to do the work and shunt streams its progress back as Anthropic SSE. It can therefore never return a `tool_use` block, so a request carrying `tools`, or a `tool_choice` other than `none`, is refused with a `400` rather than silently answered as text. Because a non-interactive run cannot answer a permission prompt, `agy` runs with `--dangerously-skip-permissions`, so **treat this provider as arbitrary code execution as the user running shunt**. Two settings bound it: `sandbox` (default `true`) passes `--sandbox`, which keeps reads and writes inside the workspace and is what actually contains the agent; `workspace_roots` decides only where it may *start*, gating the `Working directory:` path taken from the request's system prompt (client-controlled text) to canonicalized paths under roots you list. Keep the sandbox on and the bind on loopback. Prefer the `antigravity` provider above, which needs none of this. See the [providers guide](https://shunt.dev/guides/providers/).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Update the maintained translations with this behavior

This updates the English README and provider guide with the new 400 rejection contract, but the maintained README.{ko,ja,zh-CN}.md and localized ko/ja/zh-cn provider guides remain unchanged, so users of those documented surfaces are not told that tool-bearing requests now fail instead of returning text. Update the corresponding translations in this change as required.

AGENTS.md reference: AGENTS.md:L57-L64

Useful? React with 👍 / 👎.

Comment thread src/adapters/antigravity/mod.rs Outdated
Comment on lines +640 to +644
let message = "The Antigravity provider cannot use caller-supplied tools. `agy` runs its own \
tool set and never returns a tool_use block, so a request carrying `tools` or \
`tool_choice` would receive a text-only reply that silently ignores them. Send the \
task as a plain prompt and let agy do the work, or route this model to a provider \
that forwards tools."

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Identify the antigravity-cli transport in the error

When a tool-bearing request reaches kind = "antigravity_cli", this message says that the “Antigravity provider” cannot use tools, even though the native antigravity provider is the documented replacement and does forward them. This can mislead an operator into avoiding the working provider; name the deprecated antigravity-cli transport explicitly in the rejection.

Useful? React with 👍 / 👎.

@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will improve performance by 10.39%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
✅ 82 untouched benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
value_parse[307200] 1.5 ms 1.3 ms +10.39%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing r-uben:fix/404-antigravity-reject-caller-tools (e598e93) with main (83ab560)

Open in CodSpeed

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="README.md">

<violation number="1" location="README.md:154">
P2: Update `README.ja.md`, `README.ko.md`, and `README.zh-CN.md` with the new `antigravity-cli` tool-request refusal behavior. Otherwise those maintained entry points document the old silent-success behavior.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant C as Client (Agent Loop)
    participant S as Shunt Server
    participant A as AntigravityAdapter
    participant P as Prompt Extractor
    participant AGY as agy Subprocess
    participant E as Error Response

    C->>S: POST /messages (tools, tool_choice)
    S->>A: handle_request(request)
    
    alt NEW: reject_caller_tools() validation
        A->>A: Check tool_choice.type
        alt tool_choice.type == "none"
            A->>A: Allow (exemption)
            A->>P: extract_antigravity_prompt()
            P->>AGY: Spawn agy CLI
            AGY-->>A: Stream text-only response
            A-->>C: 200 with text, stop_reason: "end_turn"
        else tools array non-empty OR tool_choice exists (not "none")
            A->>A: Build 400 invalid_request_error
            A->>E: Return AdapterError
            E-->>C: 400 BAD_REQUEST + error message
        else no tools, no tool_choice (plain prompt)
            A->>P: extract_antigravity_prompt()
            P->>AGY: Spawn agy CLI
            AGY-->>A: Stream text-only response
            A-->>C: 200 with text, stop_reason: "end_turn"
        end
    end

    Note over C,E: Failure path: Claude Code subagent sends tools without tool_choice
    C->>S: POST /messages (tools: [...], no tool_choice)
    S->>A: handle_request(request)
    A->>A: tools non-empty, no tool_choice
    A->>E: Reject with 400
    E-->>C: 400 invalid_request_error
    Note over C: Subagent receives clear error instead of hanging

    Note over C,E: Failure path: tool_choice: {"type": "any"} even without tools
    C->>S: POST /messages (tool_choice: {"type": "any"})
    S->>A: handle_request(request)
    A->>A: tool_choice.type == "any"
    A->>E: Reject with 400
    E-->>C: 400 invalid_request_error
    Note over C: Violates Messages contract that must produce tool_use block
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/adapters/antigravity/mod.rs Outdated
Comment thread README.md Outdated
**Antigravity has two transports.** The `antigravity` provider talks to the Google Antigravity backend over HTTP, authenticated with `shunt login antigravity` — a Google authorization-code flow using Antigravity's own OAuth client and scopes, so a Gemini CLI login cannot be reused for it. It speaks the same Code Assist protocol as the `gemini` provider and currently serves the Gemini-family Antigravity models; the Claude models Antigravity also offers need request rewrites that are not implemented yet (#368).

**`antigravity-cli` is deprecated and is arbitrary code execution.** It runs the local `agy` binary in agentic mode: the CLI uses its own tools to do the work and shunt streams its progress back as Anthropic SSE. A `tools` array on the request is therefore not forwarded and no `tool_use` block is ever returned. Because a non-interactive run cannot answer a permission prompt, `agy` runs with `--dangerously-skip-permissions`, so **treat this provider as arbitrary code execution as the user running shunt**. Two settings bound it: `sandbox` (default `true`) passes `--sandbox`, which keeps reads and writes inside the workspace and is what actually contains the agent; `workspace_roots` decides only where it may *start*, gating the `Working directory:` path taken from the request's system prompt (client-controlled text) to canonicalized paths under roots you list. Keep the sandbox on and the bind on loopback. Prefer the `antigravity` provider above, which needs none of this. See the [providers guide](https://shunt.dev/guides/providers/).
**`antigravity-cli` is deprecated and is arbitrary code execution.** It runs the local `agy` binary in agentic mode: the CLI uses its own tools to do the work and shunt streams its progress back as Anthropic SSE. It can therefore never return a `tool_use` block, so a request carrying `tools`, or a `tool_choice` other than `none`, is refused with a `400` rather than silently answered as text. Because a non-interactive run cannot answer a permission prompt, `agy` runs with `--dangerously-skip-permissions`, so **treat this provider as arbitrary code execution as the user running shunt**. Two settings bound it: `sandbox` (default `true`) passes `--sandbox`, which keeps reads and writes inside the workspace and is what actually contains the agent; `workspace_roots` decides only where it may *start*, gating the `Working directory:` path taken from the request's system prompt (client-controlled text) to canonicalized paths under roots you list. Keep the sandbox on and the bind on loopback. Prefer the `antigravity` provider above, which needs none of this. See the [providers guide](https://shunt.dev/guides/providers/).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Update README.ja.md, README.ko.md, and README.zh-CN.md with the new antigravity-cli tool-request refusal behavior. Otherwise those maintained entry points document the old silent-success behavior.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At README.md, line 154:

<comment>Update `README.ja.md`, `README.ko.md`, and `README.zh-CN.md` with the new `antigravity-cli` tool-request refusal behavior. Otherwise those maintained entry points document the old silent-success behavior.</comment>

<file context>
@@ -151,7 +151,7 @@ xAI may gate OAuth access by subscription tier — if `grok` returns 403, use th
 **Antigravity has two transports.** The `antigravity` provider talks to the Google Antigravity backend over HTTP, authenticated with `shunt login antigravity` — a Google authorization-code flow using Antigravity's own OAuth client and scopes, so a Gemini CLI login cannot be reused for it. It speaks the same Code Assist protocol as the `gemini` provider and currently serves the Gemini-family Antigravity models; the Claude models Antigravity also offers need request rewrites that are not implemented yet (#368).
 
-**`antigravity-cli` is deprecated and is arbitrary code execution.** It runs the local `agy` binary in agentic mode: the CLI uses its own tools to do the work and shunt streams its progress back as Anthropic SSE. A `tools` array on the request is therefore not forwarded and no `tool_use` block is ever returned. Because a non-interactive run cannot answer a permission prompt, `agy` runs with `--dangerously-skip-permissions`, so **treat this provider as arbitrary code execution as the user running shunt**. Two settings bound it: `sandbox` (default `true`) passes `--sandbox`, which keeps reads and writes inside the workspace and is what actually contains the agent; `workspace_roots` decides only where it may *start*, gating the `Working directory:` path taken from the request's system prompt (client-controlled text) to canonicalized paths under roots you list. Keep the sandbox on and the bind on loopback. Prefer the `antigravity` provider above, which needs none of this. See the [providers guide](https://shunt.dev/guides/providers/).
+**`antigravity-cli` is deprecated and is arbitrary code execution.** It runs the local `agy` binary in agentic mode: the CLI uses its own tools to do the work and shunt streams its progress back as Anthropic SSE. It can therefore never return a `tool_use` block, so a request carrying `tools`, or a `tool_choice` other than `none`, is refused with a `400` rather than silently answered as text. Because a non-interactive run cannot answer a permission prompt, `agy` runs with `--dangerously-skip-permissions`, so **treat this provider as arbitrary code execution as the user running shunt**. Two settings bound it: `sandbox` (default `true`) passes `--sandbox`, which keeps reads and writes inside the workspace and is what actually contains the agent; `workspace_roots` decides only where it may *start*, gating the `Working directory:` path taken from the request's system prompt (client-controlled text) to canonicalized paths under roots you list. Keep the sandbox on and the bind on loopback. Prefer the `antigravity` provider above, which needs none of this. See the [providers guide](https://shunt.dev/guides/providers/).
 
 **Migrating from the old `antigravity`.** `kind = "antigravity"` used to mean the local CLI. A config still carrying that meaning is refused by name rather than silently retargeted, and a routed `antigravity` provider with no credential refuses to start — switching transport, credentials, and egress underneath a green startup would be worse than failing. Run `shunt login antigravity`, or point the route at `antigravity-cli`.
</file context>

Comment thread site/src/content/docs/reference/configuration.md Outdated
Comment thread src/adapters/antigravity/mod.rs Outdated
@r-uben

r-uben commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Thanks — the review caught a real defect. Pushed 71a1dd0.

Accepted

tool_choice: {"type": "auto"} with no tools was refused (cubic). This was a genuine
bug and the most important finding: auto is the Anthropic SDK default and many clients
serialize it on every request, so ordinary text prompts that never wanted a tool would have
started returning 400. The rule is now scoped to what actually obliges a tool_use block
— a non-empty tools array, or a tool_choice of any/tool. Covered by
tool_choice_auto_without_tools_is_allowed and tool_choice_auto_with_tools_is_rejected.

The error named the wrong thing (codex P2, cubic P3). It said "The Antigravity provider
cannot use caller-supplied tools", but the native antigravity provider forwards them
fine; only antigravity-cli cannot. An operator reading that could switch away from the
transport that works. It now names antigravity-cli and points at antigravity/gemini,
asserted by the_error_names_the_cli_transport_and_the_working_alternative.

Docs overstated the rule (cubic P3). Corrected in all four locales: an empty tools: []
is not a tool request, and neither is auto with no tools.

Local gate after the change: fmt and clippy clean, 1698 tests pass (up 3), 0 failures.

Declined, with reasoning

Accept tool_choice as the plain string "none" (gemini-code-assist). That is the
OpenAI shape. On the Anthropic Messages endpoint tool_choice is always an object, so a
bare string is malformed input and a 400 is the correct response — silently accepting it
would mean guessing at a shape the contract does not define.

Update README.{ko,ja,zh-CN}.md and the localized provider guides (greptile P2, codex
P1, cubic P2). I checked each file rather than take the flag at face value:

$ grep -c "antigravity-cli" README.ko.md README.ja.md README.zh-CN.md
0
0
0

The same holds for site/src/content/docs/{ko,ja,zh-cn}/guides/providers.mdx: those pages
exist but have no Antigravity section at all. There is no stale sentence to correct — the
sections were never translated, which predates this PR. Satisfying the flag would mean
translating whole missing sections into three languages, which is a separate change and not
one I want to smuggle into a bug fix.

Where a translated surface does document this, I did update it: the kind row in
site/src/content/docs/{ko,ja,zh-cn}/reference/configuration.md carries the new contract in
all three languages, matching the English page.

Happy to open a follow-up issue for the missing translated Antigravity sections if that is
useful.

@r-uben

r-uben commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Filed the declined translation finding as #412 rather than leaving it as a refusal in a comment.

To be explicit about the split: the reference tables in site/src/content/docs/{ko,ja,zh-cn}/reference/configuration.md are updated in this PR, because those pages already document Antigravity and would otherwise have gone stale. The README and provider-guide translations are not, because they have no Antigravity section to make stale — grep -c -i antigravity returns 0 on all six of those files. #412 covers authoring them.

r-uben added 4 commits August 22, 2026 13:31
…opping them

The CLI transport runs `agy`, which resolves its own tool calls internally and
has no mode that hands them back to the caller. `tools` and `tool_choice` were
therefore never read: a request carrying them got a 200 whose stop_reason is
`end_turn` and which contains only text.

An agentic caller cannot act on that. A Claude Code subagent stalls waiting for
a tool call that will never arrive, and `tool_choice: {"type": "any"}` — which
the Messages contract says must produce a tool_use block — is violated outright
while still returning success.

Fail closed with a 400 invalid_request_error naming the limitation, so the
caller learns why on the first turn rather than hanging. `tool_choice` of
`none` is exempt: the caller has declared it does not want tool calls, so a
text-only answer is what it asked for.

Refs pleaseai#404
The guide, the reference table and the README all described the old
behavior — tools "not forwarded", no tool_use block — which was accurate
but read as a quiet degradation rather than a refusal. State the actual
contract: a `tools` array or a `tool_choice` other than `none` is now a
400, and say why (agy owns its tool loop, so no tool_use can be emitted).

Reference table updated in all four locales. The README translations do
not carry the antigravity-cli paragraph at all, so there is nothing to
keep in sync there.

Refs pleaseai#404
… call

Review found the first cut over-broad: it refused any `tool_choice` other
than `none`, which caught `auto` with no tools. `auto` is the Anthropic SDK
default and many clients serialize it on every request, so an ordinary text
prompt that never wanted a tool would have started failing with a 400.

Narrow the rule to what genuinely obliges a `tool_use` block: a non-empty
`tools` array, or a `tool_choice` of `any`/`tool`. `none` stays exempt even
alongside `tools`, and `auto` with no tools is now exempt too.

Also name the transport in the error. It said "The Antigravity provider
cannot use caller-supplied tools", but the native `antigravity` provider
forwards them fine — only the deprecated `antigravity-cli` cannot. An
operator reading the old text could switch away from the one that works.
The message now names `antigravity-cli` and points at the alternatives.

Docs in all four locales corrected to match the narrowed rule, including
that an empty `tools: []` is not a tool request.

Refs pleaseai#404
@r-uben
r-uben force-pushed the fix/404-antigravity-reject-caller-tools branch from 71a1dd0 to ffddf0c Compare August 22, 2026 11:37
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-31T11:39:31.329942Z e598e93 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(antigravity): caller-supplied tools and tool_choice are silently ignored, so agentic callers get an uncallable 200

2 participants