> ## Documentation Index
> Fetch the complete documentation index at: https://chatcli.edilsonfreitas.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Native Tool Use (Structured API)

> Tool calls via native OpenAI, Anthropic, ZAI, MiniMax, Moonshot, and OpenRouter APIs, with cache_control support for KV cache optimization.

ChatCLI supports **tool calls via native API** for OpenAI, Anthropic, ZAI (Zhipu AI), MiniMax, Moonshot (Kimi), and OpenRouter, replacing the XML-embedded-in-prompt approach with structured API calls. This improves accuracy, reduces token consumption, and enables cache optimizations.

***

## Why Native Tool Use?

| Aspect | XML in Prompt | Native API |
| :- | :- | :- |
| Accuracy | Depends on the model parsing XML | Structured by the API, unambiguous |
| Tokens | XML consumes context window tokens | Separate fields, more efficient |
| Cache | No optimization | `cache_control:ephemeral` on Anthropic |
| Validation | Manual | Automatic by the provider API |
| Compatibility | Any provider | OpenAI, Anthropic, ZAI, MiniMax, Moonshot, OpenRouter (others continue with XML) |

***

## Architecture

### ToolAwareClient Interface

The `ToolAwareClient` interface extends the base `LLMClient` with tool support:

```go theme={"system"}
type ToolAwareClient interface {
    LLMClient
    SendPromptWithTools(ctx context.Context, prompt string, history []models.Message,
        tools []models.ToolDefinition, maxTokens int) (*models.LLMResponse, error)
    SupportsNativeTools() bool
}
```

### Automatic Detection

Detection is done via type assertion, with no configuration required:

```go theme={"system"}
if client.IsToolAware(c) {
    tac, _ := client.AsToolAware(c)
    resp, err := tac.SendPromptWithTools(ctx, prompt, history, tools, maxTokens)
    // resp.ToolCalls contains the structured calls
}
```

<Info>Providers that do not implement `ToolAwareClient` continue to work normally via `SendPrompt`.</Info>

### Provider Tool Use Support

Not all providers implement native tool use. Features like `/coder` mode and multi-agent orchestration work best with providers that support `SendPromptWithTools`:

| Provider | Native Tool Use | Streaming | Impact |
| - | - | - | - |
| **OpenAI** | Yes | Yes | Full `/coder` and multi-agent support |
| **Anthropic (Claude)** | Yes | Yes (OAuth) | Full `/coder` and multi-agent support |
| **Google (Gemini)** | No | No | Falls back to text-based tool parsing — `/coder` works via XML extraction |
| **ZAI (Zhipu AI)** | Yes | Yes | Full `/coder` and multi-agent support |
| **MiniMax** | Yes | Yes | Full `/coder` and multi-agent support. Disabled when `MINIMAX_API_COMPAT=anthropic` (falls back to XML). |
| **OpenRouter** | Yes | Yes | Full `/coder` and multi-agent support. Uses OpenAI-compatible function calling. Tool definitions can also be injected via `OPENROUTER_TOOLS`. |
| **xAI (Grok)** | No | No | Falls back to text-based tool parsing |
| **GitHub Copilot** | No | No | Falls back to text-based tool parsing |
| **Ollama** | No | No | Falls back to text-based tool parsing |
| **StackSpot** | No | No | Falls back to text-based tool parsing |

<Warning>
  When using providers without native tool use, the agent and coder modes still function but rely on XML-based tool call parsing from the LLM's text output. This is less reliable than native tool calling and may occasionally require format correction retries (up to 3 attempts). For production `/coder` workflows, **OpenAI, Claude, ZAI, MiniMax, or OpenRouter are recommended**.
</Warning>

***

## Data Types

<AccordionGroup>
  <Accordion title="ToolDefinition" icon="cube">
    Defines a tool available to the model:

    ```go theme={"system"}
    type ToolDefinition struct {
        Type     string          `json:"type"`     // "function"
        Function ToolFunctionDef `json:"function"`
    }

    type ToolFunctionDef struct {
        Name        string                 `json:"name"`
        Description string                 `json:"description"`
        Parameters  map[string]interface{} `json:"parameters"` // JSON Schema
    }
    ```
  </Accordion>

  <Accordion title="ToolCall and ToolResult" icon="arrow-right-arrow-left">
    Represent a tool call by the model and its result:

    ```go theme={"system"}
    type ToolCall struct {
        ID        string                 `json:"id"`
        Type      string                 `json:"type"`       // "function"
        Name      string                 `json:"name"`
        Arguments map[string]interface{} `json:"arguments"`
    }

    type ToolResult struct {
        ToolCallID string `json:"tool_call_id"`
        Content    string `json:"content"`
        IsError    bool   `json:"is_error,omitempty"`
    }
    ```

    The `IsError` field (aligned with Anthropic's Messages API) is emitted natively as `is_error: true` in Claude's `tool_result` block. For OpenAI-compatible providers (OpenAI, Moonshot, MiniMax, ZAI, OpenRouter), the `models.Message` also carries `ErrorCode` (`ENOENT`, `Timeout`, `ExitCode:N`, `InvalidArgs`, …) and the adapter prepends content with `[ERROR:<code>]` — the model gets the signal even without a native error field.
  </Accordion>

  <Accordion title="LLMResponse" icon="reply">
    Unified response that can contain text and/or tool calls:

    ```go theme={"system"}
    type LLMResponse struct {
        Content    string     `json:"content"`
        ToolCalls  []ToolCall `json:"tool_calls,omitempty"`
        Usage      *UsageInfo `json:"usage,omitempty"`
        StopReason string     `json:"stop_reason,omitempty"`
    }
    ```
  </Accordion>
</AccordionGroup>

***

## Provider Implementations

<Tabs>
  <Tab title="OpenAI">
    Uses the `tools` field in the Chat Completions API:

    * Sends tools as a `tools` array with `tool_choice: "auto"`
    * Processes `tool_calls` in `choices[0].message`
    * `tool` messages in the history link results to the `tool_call_id`
  </Tab>

  <Tab title="Anthropic (Claude)">
    Uses the `tools` field in the Messages API with cache optimization:

    * Sends tools in the `tools` field of the request
    * System prompt includes `cache_control: { type: "ephemeral" }` for KV cache reuse
    * Tool results are sent as `tool_result` content blocks in `user` messages
    * When the result has `IsError=true`, the adapter sets native `is_error: true` + a defensive `[ERROR:<code>]` prefix in content
    * Supports all authentication types (API key, OAuth token)
  </Tab>
</Tabs>

### Tool result with is\_error / ErrorCode (provider-agnostic)

Tool results carry two orthogonal signals that travel to the model:

* **`IsError bool`** — true when the tool executed but reported a business-level failure (non-zero exit, HTTP 4xx, file not found, invalid args schema). False = success.
* **`ErrorCode string`** — locale-independent classification: `ENOENT`, `EACCES`, `EISDIR`, `EEXIST`, `Timeout`, `Canceled`, `ExitCode:N`, `NetworkError`, `DNSError`, `InvalidArgs`, etc. Empty when `IsError=false`.

| Provider family | How it's emitted |
| - | - |
| Anthropic (claudeai, Bedrock Claude, StackSpot Claude) | `{"type":"tool_result","is_error":true,"content":"[ERROR:ENOENT] <body>"}` |
| OpenAI Chat Completions (openai, moonshot, minimax, zai, openrouter, xai, copilot) | `{"role":"tool","tool_call_id":...,"content":"[ERROR:ENOENT] <body>"}` |
| Others (no native support) | content with `[ERROR]` header when applicable |

The model pattern-matches on `[ERROR:<code>]` to decide retry/recovery without parsing English — `InvalidArgs` means "fix the schema", `Timeout` means "try again", `ENOENT` means "wrong file".

### ContentBlock with Cache Control

For Anthropic, the system prompt is split into blocks with cache control:

```go theme={"system"}
type ContentBlock struct {
    Type         string        `json:"type"`
    Text         string        `json:"text"`
    CacheControl *CacheControl `json:"cache_control,omitempty"`
}

type CacheControl struct {
    Type string `json:"type"` // "ephemeral"
}
```

<Tip>The `cache_control:ephemeral` tells Anthropic that the system prompt block can be cached between requests, significantly reducing latency and cost in long conversations.</Tip>

***

## Fallback Integration

The fallback chain (`llm/fallback`) supports `SendPromptWithTools` automatically. Providers without native tool use support are skipped in the tool call chain but remain available for plain text requests.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.