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

# Tool Calling

> Enable LLMs to call functions and interact with external tools on-device

<Note>
  Tool calling lets the LLM decide **when** and **how** to invoke your functions, then incorporates
  the results into its response — all running on-device for maximum privacy.
</Note>

## Basic Usage

```typescript theme={null}
import { RunAnywhere, ToolDefinition, ToolCallingResult } from '@runanywhere/core'

// 1. Define a tool
const weatherTool: ToolDefinition = {
  name: 'get_weather',
  description: 'Get the current weather for a given city',
  parameters: [
    {
      name: 'city',
      type: 'string',
      description: 'The city name, e.g. "San Francisco"',
      required: true,
    },
  ],
}

// 2. Register it with an executor
RunAnywhere.registerTool(weatherTool, async (args) => {
  return { temperature: 72, condition: 'sunny' }
})

// 3. Generate with tools
const result: ToolCallingResult = await RunAnywhere.generateWithTools(
  'What is the weather in San Francisco?',
  { tools: [weatherTool], autoExecute: true }
)

console.log(result.text) // "The weather in San Francisco is 72°F and sunny."
console.log(result.toolCalls) // [{ toolName: 'get_weather', arguments: { city: 'San Francisco' } }]
console.log(result.toolResults) // [{ toolName: 'get_weather', success: true, result: { ... } }]
```

## Setup

### Defining Tools

Each tool is described by a `ToolDefinition` that tells the LLM what the tool does and what arguments it accepts.

```typescript theme={null}
import { ToolDefinition } from '@runanywhere/core'

const tools: ToolDefinition[] = [
  {
    name: 'get_weather',
    description: 'Get the current weather for a given city',
    parameters: [
      {
        name: 'city',
        type: 'string',
        description: 'The city name, e.g. "San Francisco"',
        required: true,
      },
      {
        name: 'unit',
        type: 'string',
        description: 'Temperature unit: "celsius" or "fahrenheit"',
        required: false,
        defaultValue: 'celsius',
        enum: ['celsius', 'fahrenheit'],
      },
    ],
  },
  {
    name: 'calculate',
    description: 'Evaluate a mathematical expression',
    parameters: [
      {
        name: 'expression',
        type: 'string',
        description: 'Math expression, e.g. "2 + 3 * 4"',
        required: true,
      },
    ],
  },
]
```

### Registering & Clearing Tools

```typescript theme={null}
// Clear any previously registered tools
RunAnywhere.clearTools()

// Register each tool with its executor function
RunAnywhere.registerTool(tools[0], async (args: Record<string, unknown>) => {
  const city = args.city as string
  const unit = (args.unit as string) ?? 'celsius'
  // Call a weather API or return mock data
  return { temperature: unit === 'celsius' ? 22 : 72, condition: 'sunny', city }
})

RunAnywhere.registerTool(tools[1], async (args: Record<string, unknown>) => {
  const expr = args.expression as string
  try {
    const result = Function(`"use strict"; return (${expr})`)()
    return { result: Number(result) }
  } catch {
    return { error: 'Invalid expression' }
  }
})
```

<Tip>
  Always call `RunAnywhere.clearTools()` before re-registering tools to avoid duplicates — for
  example, when your component remounts.
</Tip>

## API Reference

### `RunAnywhere.registerTool()`

Register a tool definition with its executor function.

```typescript theme={null}
RunAnywhere.registerTool(
  definition: ToolDefinition,
  executor: (args: Record<string, unknown>) => Promise<Record<string, unknown>>
): void
```

| Parameter    | Type                                                                  | Description                                         |
| ------------ | --------------------------------------------------------------------- | --------------------------------------------------- |
| `definition` | `ToolDefinition`                                                      | The tool's name, description, and parameters        |
| `executor`   | `(args: Record<string, unknown>) => Promise<Record<string, unknown>>` | Async function invoked when the LLM calls this tool |

### `RunAnywhere.clearTools()`

Remove all registered tools.

```typescript theme={null}
RunAnywhere.clearTools(): void
```

### `RunAnywhere.generateWithTools()`

Run a full tool-calling loop: generate → parse → execute → re-generate until the LLM produces a final text response or the call limit is reached.

```typescript theme={null}
await RunAnywhere.generateWithTools(
  prompt: string,
  options?: ToolCallingOptions
): Promise<ToolCallingResult>
```

| Parameter | Type                  | Description                 |
| --------- | --------------------- | --------------------------- |
| `prompt`  | `string`              | The user's input prompt     |
| `options` | `ToolCallingOptions?` | Generation and tool options |

### `RunAnywhere.parseToolCall()`

Manually parse raw LLM output to extract a tool call. Useful when you want full control over the tool-calling loop instead of using `autoExecute`.

```typescript theme={null}
await RunAnywhere.parseToolCall(
  llmOutput: string
): Promise<ParsedToolCall>
```

| Parameter   | Type     | Description                  |
| ----------- | -------- | ---------------------------- |
| `llmOutput` | `string` | Raw text output from the LLM |

### Types

#### `ToolDefinition`

```typescript theme={null}
interface ToolDefinition {
  name: string
  description: string
  parameters: ToolParameter[]
}
```

#### `ToolParameter`

```typescript theme={null}
interface ToolParameter {
  name: string
  type: 'string' | 'number' | 'boolean' | 'object' | 'array'
  description: string
  required?: boolean
  defaultValue?: string
  enum?: string[]
}
```

| Field          | Type        | Description                                             |
| -------------- | ----------- | ------------------------------------------------------- |
| `name`         | `string`    | Parameter name                                          |
| `type`         | `string`    | One of `string`, `number`, `boolean`, `object`, `array` |
| `description`  | `string`    | Human-readable description for the LLM                  |
| `required`     | `boolean?`  | Whether the parameter is required (default: `false`)    |
| `defaultValue` | `string?`   | Default value when the parameter is omitted             |
| `enum`         | `string[]?` | Allowed values — constrains the LLM's choices           |

#### `ToolCallingOptions`

```typescript theme={null}
interface ToolCallingOptions {
  tools?: ToolDefinition[]
  maxToolCalls?: number
  autoExecute?: boolean
  temperature?: number
  maxTokens?: number
}
```

| Field          | Type                | Default | Description                             |
| -------------- | ------------------- | ------- | --------------------------------------- |
| `tools`        | `ToolDefinition[]?` | —       | Override registered tools for this call |
| `maxToolCalls` | `number?`           | `5`     | Maximum tool invocations per generation |
| `autoExecute`  | `boolean?`          | `true`  | Automatically execute parsed tool calls |
| `temperature`  | `number?`           | `0.7`   | Sampling temperature (0.0–2.0)          |
| `maxTokens`    | `number?`           | `256`   | Maximum tokens to generate              |

#### `ToolCallingResult`

```typescript theme={null}
interface ToolCallingResult {
  text: string
  toolCalls: Array<{
    toolName: string
    arguments: Record<string, unknown>
  }>
  toolResults: Array<{
    toolName: string
    success: boolean
    result?: unknown
    error?: string
  }>
}
```

| Field         | Type     | Description                                   |
| ------------- | -------- | --------------------------------------------- |
| `text`        | `string` | Final text response from the LLM              |
| `toolCalls`   | `Array`  | All tool calls the LLM made during generation |
| `toolResults` | `Array`  | Execution results for each tool call          |

#### `ParsedToolCall`

```typescript theme={null}
interface ParsedToolCall {
  toolCall?: {
    toolName: string
    arguments: Record<string, unknown>
  }
  text: string
}
```

| Field      | Type      | Description                                 |
| ---------- | --------- | ------------------------------------------- |
| `toolCall` | `object?` | Extracted tool call, if the LLM invoked one |
| `text`     | `string`  | Remaining text after tool-call extraction   |

## Examples

### Complete React Native Component

A full example with weather, calculator, and time tools wired into a chat-style UI.

```typescript ToolCallingDemo.tsx theme={null}
import React, { useState, useCallback, useEffect } from 'react'
import {
  View,
  Text,
  TextInput,
  TouchableOpacity,
  ScrollView,
  ActivityIndicator,
  StyleSheet,
} from 'react-native'
import {
  RunAnywhere,
  ToolDefinition,
  ToolCallingResult,
} from '@runanywhere/core'

const TOOLS: ToolDefinition[] = [
  {
    name: 'get_weather',
    description: 'Get the current weather for a given city',
    parameters: [
      { name: 'city', type: 'string', description: 'City name', required: true },
      {
        name: 'unit',
        type: 'string',
        description: 'Temperature unit',
        required: false,
        defaultValue: 'fahrenheit',
        enum: ['celsius', 'fahrenheit'],
      },
    ],
  },
  {
    name: 'calculate',
    description: 'Evaluate a mathematical expression',
    parameters: [
      { name: 'expression', type: 'string', description: 'Math expression', required: true },
    ],
  },
  {
    name: 'get_time',
    description: 'Get the current time in a given timezone',
    parameters: [
      {
        name: 'timezone',
        type: 'string',
        description: 'IANA timezone, e.g. "America/New_York"',
        required: true,
      },
    ],
  },
]

function registerAllTools(): void {
  RunAnywhere.clearTools()

  RunAnywhere.registerTool(TOOLS[0], async (args) => {
    const city = args.city as string
    const unit = (args.unit as string) ?? 'fahrenheit'
    const temp = unit === 'celsius' ? 22 : 72
    return { city, temperature: temp, unit, condition: 'partly cloudy' }
  })

  RunAnywhere.registerTool(TOOLS[1], async (args) => {
    const expr = args.expression as string
    try {
      const value = Function(`"use strict"; return (${expr})`)()
      return { expression: expr, result: Number(value) }
    } catch {
      return { expression: expr, error: 'Could not evaluate expression' }
    }
  })

  RunAnywhere.registerTool(TOOLS[2], async (args) => {
    const tz = args.timezone as string
    try {
      const time = new Date().toLocaleTimeString('en-US', { timeZone: tz })
      return { timezone: tz, currentTime: time }
    } catch {
      return { timezone: tz, error: 'Invalid timezone' }
    }
  })
}

interface Message {
  role: 'user' | 'assistant'
  text: string
  toolCalls?: ToolCallingResult['toolCalls']
}

export default function ToolCallingDemo(): React.JSX.Element {
  const [prompt, setPrompt] = useState('')
  const [messages, setMessages] = useState<Message[]>([])
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    registerAllTools()
  }, [])

  const handleSend = useCallback(async () => {
    const trimmed = prompt.trim()
    if (!trimmed || loading) return

    setMessages((prev) => [...prev, { role: 'user', text: trimmed }])
    setPrompt('')
    setLoading(true)

    try {
      const result = await RunAnywhere.generateWithTools(trimmed, {
        tools: TOOLS,
        maxToolCalls: 3,
        autoExecute: true,
        temperature: 0.7,
        maxTokens: 512,
      })

      setMessages((prev) => [
        ...prev,
        { role: 'assistant', text: result.text, toolCalls: result.toolCalls },
      ])
    } catch (err) {
      const message = err instanceof Error ? err.message : 'Tool calling failed'
      setMessages((prev) => [...prev, { role: 'assistant', text: `Error: ${message}` }])
    } finally {
      setLoading(false)
    }
  }, [prompt, loading])

  return (
    <View style={styles.container}>
      <ScrollView style={styles.messages}>
        {messages.map((msg, i) => (
          <View key={i} style={msg.role === 'user' ? styles.userBubble : styles.aiBubble}>
            <Text style={styles.messageText}>{msg.text}</Text>
            {msg.toolCalls?.map((tc, j) => (
              <Text key={j} style={styles.toolCallText}>
                🔧 {tc.toolName}({JSON.stringify(tc.arguments)})
              </Text>
            ))}
          </View>
        ))}
        {loading && <ActivityIndicator style={styles.loader} />}
      </ScrollView>
      <View style={styles.inputRow}>
        <TextInput
          style={styles.input}
          value={prompt}
          onChangeText={setPrompt}
          placeholder="Ask about weather, math, or time..."
        />
        <TouchableOpacity style={styles.sendButton} onPress={handleSend} disabled={loading}>
          <Text style={styles.sendText}>Send</Text>
        </TouchableOpacity>
      </View>
    </View>
  )
}

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: '#f5f5f5' },
  messages: { flex: 1, padding: 16 },
  userBubble: {
    alignSelf: 'flex-end', backgroundColor: '#007AFF', borderRadius: 16,
    padding: 12, marginBottom: 8, maxWidth: '80%',
  },
  aiBubble: {
    alignSelf: 'flex-start', backgroundColor: '#fff', borderRadius: 16,
    padding: 12, marginBottom: 8, maxWidth: '80%',
    shadowColor: '#000', shadowOpacity: 0.05, shadowRadius: 4, elevation: 1,
  },
  messageText: { fontSize: 15, color: '#1a1a1a' },
  toolCallText: { fontSize: 12, color: '#888', marginTop: 4, fontFamily: 'monospace' },
  loader: { marginVertical: 12 },
  inputRow: { flexDirection: 'row', padding: 12, backgroundColor: '#fff' },
  input: {
    flex: 1, backgroundColor: '#f0f0f0', borderRadius: 20,
    paddingHorizontal: 16, paddingVertical: 10, fontSize: 15,
  },
  sendButton: {
    marginLeft: 8, backgroundColor: '#007AFF', borderRadius: 20,
    paddingHorizontal: 20, justifyContent: 'center',
  },
  sendText: { color: '#fff', fontWeight: '600' },
})
```

### Manual Tool Call Parsing

Use `parseToolCall()` when you need to inspect or modify tool calls before execution.

```typescript theme={null}
const llmOutput = await RunAnywhere.generate('What is the weather in Tokyo?', {
  maxTokens: 256,
})

const parsed = await RunAnywhere.parseToolCall(llmOutput.text)

if (parsed.toolCall) {
  console.log('Tool:', parsed.toolCall.toolName) // "get_weather"
  console.log('Args:', parsed.toolCall.arguments) // { city: "Tokyo" }
  console.log('Remaining text:', parsed.text)

  // Execute manually, apply rate limits, log, etc.
} else {
  console.log('No tool call found — plain text response')
}
```

### Multi-Step Tool Chain

The LLM can chain multiple tool calls in a single generation when `maxToolCalls > 1`.

```typescript theme={null}
const result = await RunAnywhere.generateWithTools(
  'What is 15% of the temperature in New York right now?',
  {
    tools: TOOLS,
    maxToolCalls: 3,
    autoExecute: true,
  }
)

// The LLM will:
// 1. Call get_weather({ city: "New York" })  → { temperature: 72 }
// 2. Call calculate({ expression: "72 * 0.15" }) → { result: 10.8 }
// 3. Return a final text answer

console.log(result.text)
// "15% of the current temperature in New York (72°F) is 10.8°F."
console.log(result.toolCalls.length) // 2
```

## Error Handling

<Warning>
  Tool executors should always return a result object — never throw. If a tool fails, return an
  object with an `error` field so the LLM can recover gracefully.
</Warning>

```typescript theme={null}
RunAnywhere.registerTool(weatherTool, async (args) => {
  const city = args.city as string

  try {
    const response = await fetch(`https://api.weather.example/v1?city=${encodeURIComponent(city)}`)
    if (!response.ok) {
      return { error: `Weather API returned ${response.status}` }
    }
    const data = await response.json()
    return { temperature: data.temp, condition: data.condition }
  } catch (err) {
    return { error: err instanceof Error ? err.message : 'Network request failed' }
  }
})
```

### Common Error Scenarios

| Scenario               | Cause                                                     | Resolution                                                           |
| ---------------------- | --------------------------------------------------------- | -------------------------------------------------------------------- |
| Tool not found         | Tool name in LLM output doesn't match any registered tool | Verify `ToolDefinition.name` matches exactly                         |
| Argument type mismatch | LLM passes wrong type for a parameter                     | Cast defensively in the executor; provide clear `description` values |
| Max calls exceeded     | LLM enters a tool-call loop                               | Lower `maxToolCalls` or refine tool descriptions                     |
| Executor timeout       | External API call hangs                                   | Add `AbortController` timeouts inside executors                      |
| No tool call parsed    | Model doesn't emit a tool-call token                      | Use a model that supports tool calling; check prompt clarity         |

## Platform Differences

<Note>
  The React Native SDK uses `RunAnywhere` directly for tool calling — there is no separate
  `ToolCalling` class like the Web SDK.
</Note>

| Feature                  | React Native (`@runanywhere/core`) | Web (`@runanywhere/web`)      |
| ------------------------ | ---------------------------------- | ----------------------------- |
| Entry point              | `RunAnywhere.registerTool()`       | `ToolCalling.registerTool()`  |
| Executor argument type   | `Record<string, unknown>`          | `Record<string, ToolValue>`   |
| Manual parsing           | `RunAnywhere.parseToolCall()`      | Not available                 |
| Parameter `enum` field   | Supported                          | `enumValues` (different name) |
| Parameter `defaultValue` | Supported                          | Not available                 |

## Related

<CardGroup cols={2}>
  <Card title="LLM Generation" icon="brain" href="/react-native/llm/generate">
    Full text generation API
  </Card>

  <Card title="Streaming" icon="water" href="/react-native/llm/stream">
    Real-time token streaming
  </Card>

  <Card title="System Prompts" icon="robot" href="/react-native/llm/system-prompts">
    Control AI behavior
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/react-native/error-handling">
    SDK error reference
  </Card>
</CardGroup>
