Hmbown/CodeWhale · error · anyhow::Error

Antigravity cloud-code tools are not implemented yet; send a

Error message

Antigravity cloud-code tools are not implemented yet; send a text-only turn or use the google provider

What it means

The Antigravity cloud-code request builder rejects any request whose `tools` list is non-empty, because tool calling is not implemented on that adapter. The bail happens locally during request construction, before any HTTP call, failing closed instead of silently dropping tools. System prompts are rejected separately (SystemPromptUnsupported) just above this check.

Source

Thrown at crates/tui/src/client/cloud_code.rs:57

/// Minimum GenerateContent JSON body. Tools, images, and unknown roles fail
/// closed — those shapes are unproven on this wire.
pub fn build_generate_content_body(request: &MessageRequest) -> Result<Value> {
    let has_system_text = match request.system.as_ref() {
        Some(SystemPrompt::Text(text)) => !text.trim().is_empty(),
        Some(SystemPrompt::Blocks(blocks)) => {
            blocks.iter().any(|block| !block.text.trim().is_empty())
        }
        None => false,
    };
    if has_system_text {
        return Err(CloudCodeRequestError::SystemPromptUnsupported.into());
    }
    if request
        .tools
        .as_ref()
        .is_some_and(|tools| !tools.is_empty())
    {
        bail!(
            "Antigravity cloud-code tools are not implemented yet; send a text-only turn or use the google provider"
        );
    }
    let mut contents = Vec::new();
    for message in &request.messages {
        let role = match message.role.as_str() {
            "user" => "user",
            "assistant" | "model" => "model",
            other => bail!("Antigravity cloud-code does not accept role {other:?}"),
        };
        let mut parts = Vec::new();
        for block in &message.content {
            match block {
                ContentBlock::Text { text, .. } if !text.trim().is_empty() => {
                    parts.push(json!({ "text": text }));
                }
                ContentBlock::Text { .. } => {}
                _ => bail!(

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Send a text-only turn: clear the tool list for requests on the antigravity route
  2. Switch the session to the `google` provider when tool use is required
  3. Disable tools in the provider/session config for antigravity lanes

Example fix

// before
request.tools = default_tool_catalog(); // non-empty -> bail on antigravity

// after
if provider_is_antigravity(&client) {
    request.tools = None;
}
client.create_message_stream(request).await?;
Defensive patterns

Strategy: fallback

Validate before calling

let tools = if provider_is_antigravity(&client) { None } else { request.tools.take() };
// or: route tool-carrying requests to google before building
anyhow::ensure!(
    provider_is_antigravity(&client) == false || request.tools.as_ref().is_none_or(|t| t.is_empty()),
    "antigravity route requires a text-only turn"
);

Type guard

fn route_accepts_tools(provider: ApiProvider) -> bool {
    provider != ApiProvider::Antigravity
}

Try / catch

let request = if request.tools.as_ref().is_some_and(|t| !t.is_empty()) && provider != ApiProvider::Antigravity {
    request
} else {
    request.without_tools() // degrade to text-only instead of failing the turn
};

Prevention

When it happens

Trigger: Sending a request with `request.tools` populated (any non-empty list, e.g. the default shell/read/write tool set) while the provider is Antigravity on the cloud-code dialect.

Common situations: Default tool configuration is active globally when the user switches a session to the antigravity provider; an agent loop that always attaches its tool catalog regardless of provider capability.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/c0704ca66e63a179. Report an issue: GitHub.