> ## 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                                                                                                         |
| **GitHub Models**      | No              | No          | Falls back to text-based tool parsing (OpenAI-compatible API)                                                                                 |
| **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.
