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

# Function Tools

> Let your agent run custom Python functions to act and call external services.

Function tools are Python functions decorated with `@function_tool` that let an agent perform actions and call external services during a conversation. The LLM decides when to invoke them. Tools may be synchronous or asynchronous, suitable for I/O like HTTP requests.

## External Tools

External tools are standalone functions passed into the agent's constructor via the `tools` parameter. Use this to share common tools across multiple agents.

<CodeGroup>
  ```python title="main.py" Python theme={null}
  from zrt import Agent, function_tool

  # External tool defined outside the class
  @function_tool
  def get_weather(location: str) -> str:
      """Get weather information for a specific location."""
      return f"Weather in {location}: Sunny, 72°F"

  class WeatherAgent(Agent):
      def __init__(self, pipeline):
          super().__init__(
              agent_id="weather-assistant",
              instructions="You are a weather assistant.",
              pipeline=pipeline,
              tools=[get_weather],  # Register the external tool
          )
  ```
</CodeGroup>

## Internal Tools

Internal tools are methods defined inside your agent class and decorated with `@function_tool`. Use this for logic specific to the agent that needs its internal state via `self`.

<CodeGroup>
  ```python title="main.py" Python theme={null}
  from zrt import Agent, function_tool

  class FinanceAgent(Agent):
      def __init__(self, pipeline):
          super().__init__(
              agent_id="finance-assistant",
              instructions="You are a helpful financial assistant.",
              pipeline=pipeline,
          )
          self.portfolio = {"AAPL": 10, "GOOG": 5}

      @function_tool
      def get_portfolio_value(self) -> dict:
          """Get the current value of the user's stock portfolio."""
          # Access agent state via self
          return {"total_value": 5000, "holdings": self.portfolio}
  ```
</CodeGroup>

## Tool Chaining and Parallel Calls

Agents can chain tools in a turn: call a tool, pass its result back to the LLM, and repeat until a final text reply. Some LLMs (Anthropic Claude, OpenAI GPT‑4o) may request multiple tool calls in one response; those run concurrently using `asyncio.gather`. Google Gemini issues one tool call at a time.

To cap how many tool calls a single turn may make, set `max_tool_calls_per_turn` on the Context Window config of the `Pipeline`. It defaults to `10` and acts as a safety limit against infinite tool-call loops.

<CodeGroup>
  ```python title="main.py" Python theme={null}
  from zrt import Pipeline, ContextWindow

  pipeline = Pipeline(
      # ...stt, llm, tts, vad, turn_detector
      context_window=ContextWindow(
          max_tool_calls_per_turn=10,  # Allow up to 10 tool calls per turn
      ),
  )
  ```
</CodeGroup>

## Updating Tools at Runtime

You can change an agent's tools while a session is running with `Agent.update_tools(...)`. This adds, removes, or replaces tools without restarting the session.

* `Agent.update_tools(tools)` updates the agent's tool list. It is synchronous.
* Every entry must be a valid tool. Invalid entries raise an error when the tools are registered.

<CodeGroup>
  ```python Python theme={null}
  # add a tool
  agent.update_tools(agent.tools + [get_horoscope])
  # remove a tool
  agent.update_tools([t for t in agent.tools if t is not get_horoscope])
  # replace all tools
  agent.update_tools([get_horoscope])
  ```
</CodeGroup>

To update tools mid-session, schedule the change as a background task from `on_enter`, where the live session is available:

<CodeGroup>
  ```python title="main.py" Python theme={null}
  import asyncio
  from zrt import Agent

  class VoiceAgent(Agent):
      def __init__(self, pipeline):
          super().__init__(
              agent_id="assistant",
              instructions="You are a helpful voice assistant.",
              pipeline=pipeline,
          )

      async def on_enter(self):
          await self.session.say("Hi! How can I help?")

          async def update_tools_later():
              await asyncio.sleep(20)
              # Apply the change to the live session after a delay.
              self.update_tools(self.tools + [get_horoscope])

          asyncio.create_task(update_tools_later())
  ```
</CodeGroup>

<Note>
  Sarvam AI LLM: When using Sarvam AI as the LLM option, function tool calls and MCP tools will not work. Consider using alternative LLM providers if you need function tool support.
</Note>

## What's Next

<CardGroup cols={2}>
  <Card title="MCP" icon="plug" href="/build/tools-and-capabilities/mcp">
    Auto-discover tools from an MCP server instead of writing them by hand.
  </Card>

  <Card title="RAG" icon="database" href="/build/tools-and-capabilities/rag">
    Ground answers in a knowledge base with custom retrieval.
  </Card>

  <Card title="Run Your Agent" icon="play" href="/build/run-the-runtime">
    Run the agent with its tools in a live session.
  </Card>
</CardGroup>

## References

<Tabs>
  <Tab title="Python">
    #### Examples

    <CardGroup cols={2}>
      <Card title="Tool Chaining" icon="github" href="https://github.com/ZeroRuntimeAI/zrt-python-sdk-examples/blob/main/features/function_tools.py">
        Chain multiple function tools in one turn.
      </Card>
    </CardGroup>

    #### SDK Reference

    <CardGroup cols={2}>
      <Card title="FunctionTool" icon="wrench" href="/api-reference/python/core/tools-and-mcp#functiontool">
        `FunctionTool` in the Python API reference.
      </Card>
    </CardGroup>
  </Tab>
</Tabs>
