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

# Integrate data via Tool Calling

> Connect your data to the API endpoint to present data-based answers

Generative UI is most useful when the model can call into your data and services.
C1 supports **tool integration**, so that your UIs are powered by live data rather than raw LLM responses.

## What are tools?

A tool is an API or function you expose to the model.
Instead of guessing/hallucinating values, the model can call your tool and use the results to generate UI.

Examples of tools:

* Fetching live stock prices from a finance API
* Querying a database for users or orders
* Calling an internal microservice
* Running a calculation or simulation

## How tools fit into the flow

Tool calling / Function calling behaves in the same way as any standardized LLM endpoint.
To learn more in depth refer to the [OpenAI Guide](https://platform.openai.com/docs/guides/function-calling)
on how it works.

```mermaid theme={null}
flowchart LR

  U[User request]:::node --> M["Thesys C1"]
  M --> T["Tool call: API / DB / function"]
  T --> M
  M --> DSL["C1 DSL (typed UI spec)"]
  DSL --> R["C1 React SDK"]
  R --> UI["Rendered UI (chart, table, form)"]
```

## Example: Integrating Web Search

This guide demonstrates how to equip an agent with a web search tool, enabling it to provide up-to-the-minute information.

### 1. Define a tool for the agent to use

To get started, we need to define the tool and how the agent should use it. For our company's research assistant, a web search tool is crucial for gathering current information. This guide adds a web search tool powered by [Tavily](https://tavily.com) to search the web.

You may need to install additional dependencies such as `zod`, `zod-to-json-schema`, and `@tavily/core`. You can install them using npm:

<CodeGroup dropdown>
  ```ts cli theme={null}
  > npm install zod zod-to-json-schema @tavily/core
  ```

  ```python cli theme={null}
  > pip install tavily-python
  ```
</CodeGroup>

<CodeGroup dropdown>
  ```ts app/api/chat/tools.ts theme={null}
  import { JSONSchema } from "openai/lib/jsonschema.mjs";
  import { RunnableToolFunctionWithParse } from "openai/lib/RunnableFunction.mjs";
  import { z } from "zod";
  import { zodToJsonSchema } from "zod-to-json-schema";
  import { tavily } from "@tavily/core";

  const tavilyClient = tavily({ apiKey: process.env.TAVILY_API_KEY });

  export const tools: [
    RunnableToolFunctionWithParse<{
      searchQuery: string;
    }>
  ] = [
    {
      type: "function",
      function: {
        name: "web_search",
        description:
          "Search the web for a given query, will return details about anything including business",
        parse: (input) => {
          return JSON.parse(input) as { searchQuery: string };
        },
        parameters: zodToJsonSchema(
          z.object({
            searchQuery: z.string().describe("search query"),
          })
        ) as JSONSchema,
        function: async ({ searchQuery }: { searchQuery: string }) => {
          const results = await tavilyClient.search(searchQuery, {
            maxResults: 5,
          });

          return JSON.stringify(results);
        },
        strict: true,
      },
    },
  ];
  ```

  ```python tool.py theme={null}
  import os
  import json
  from typing import Callable, Dict
  from tavily import TavilyClient


  tavily_client = TavilyClient(api_key=os.environ.get("TAVILY_API_KEY", ""))


  def web_search(searchQuery: str) -> str:
      results = tavily_client.search(query=searchQuery, max_results=5)
      return json.dumps(results)


  tools = [
      {
          "type": "function",
          "function": {
              "name": "web_search",
              "description": "Search the web for a given query, will return details about anything including business",
              "parameters": {
                  "type": "object",
                  "properties": {
                      "searchQuery": {
                          "type": "string",
                          "description": "search query",
                      }
                  },
                  "required": ["searchQuery"],
                  "additionalProperties": False,
              },
              "strict": True,
          },
      }
  ]


  tool_impls: Dict[str, Callable[..., str]] = {
      "web_search": web_search,
  }
  ```
</CodeGroup>

### 2. Instruct the agent to use the tool

Now that the agent has a tool, we need to teach it when and how to use it. A system prompt is the perfect way to provide these instructions.
We can tell the agent to use the `web_search` tool whenever it needs current information to answer a question about a company.

Here's a sample system prompt:

<CodeGroup dropdown>
  ```ts app/api/chat/systemPrompt.ts theme={null}
  export const systemPrompt = `
    You are a business research assistant just like crunchbase. You answer questions about a company or domain.
    given a company name or domain, you will search the web for the latest information.`;
  ```

  ```python system_prompt.py theme={null}
  SYSTEM_PROMPT = """
  You are a business research assistant just like crunchbase. You answer questions about a company or domain.
  given a company name or domain, you will search the web for the latest information.
  """
  ```
</CodeGroup>

### 3. Pass the tool to the agent

Now you just need to pass the tool call function to the agent so it can start using the tool. If you've followed the [Quickstart](/guides/setup) guide, you can
pass the tool call function to the agent by making a couple of small changes:

1. Import the `tools` and `systemPrompt` to your `route.ts` file.
2. Replace the `create` call in your `route.ts` file with a convenient `runTools` call that takes the list of tools available to the agent.

Here's an example of how to do this:

<CodeGroup dropdown>
  ```ts src/app/api/route.ts theme={null}
  import { systemPrompt } from "./systemPrompt";
  import { tools } from "./tools";

  export async function POST(req: NextRequest) {
    ...
    const llmStream = await client.beta.chat.completions.runTools({
      model: "c1/anthropic/claude-sonnet-4/v-20251230",
      messages: [
        { role: "system", content: systemPrompt },
        ...messages
      ],
      tools,
      stream: true,
    });
    ...
  }
  ```

  ```python main.py theme={null}
  import os
  import json
  from typing import Any, Dict, List, Optional
  from fastapi import FastAPI
  from pydantic import BaseModel
  from openai import OpenAI
  from tool import tools, tool_impls
  from system_prompt import SYSTEM_PROMPT


  app = FastAPI()

  client = OpenAI(
      api_key=os.environ.get("THESYS_API_KEY"),
      base_url="https://api.thesys.dev/v1/embed",
  )


  def run_chat_with_tools(
      messages: List[str]
  ) -> str:
      messages: List[Dict[str, Any]] = [
          {"role": "system", "content": SYSTEM_PROMPT},
          ...messages
      ]

      completion = client.chat.completions.create(
          model="c1/anthropic/claude-sonnet-4/v-20251230",
          messages=messages,
          tools=tools,
      )

      while True:
          choice = completion.choices[0]
          message = choice.message
          tool_calls = message.tool_calls or []

          # If there are no tool calls, return the assistant's answer
          if not tool_calls:
              return message.content or ""

          # Record the assistant message that requested tools
          messages.append(
              {
                  "role": "assistant",
                  "content": message.content or "",
                  "tool_calls": [
                      {
                          "id": tc.id,
                          "type": "function",
                          "function": {
                              "name": tc.function.name,
                              "arguments": tc.function.arguments,
                          },
                      }
                      for tc in tool_calls
                  ],
              }
          )

          # Execute tools and append results
          for tool_call in tool_calls:
              name = tool_call.function.name
              args = json.loads(tool_call.function.arguments or "{}")
              result = tool_impls[name](**args)
              messages.append(
                  {
                      "role": "tool",
                      "tool_call_id": tool_call.id,
                      "content": result,
                  }
              )

          # Ask the model again with tool results
          completion = client.chat.completions.create(
              model="c1/anthropic/claude-sonnet-4/v-20251230",
              messages=messages,
              tools=tools,
          )




  @app.post("/chat")
  def chat():
    return run_chat_with_tools(messages)
  ```
</CodeGroup>

### 4. Test it out

Try asking "Who is the current president of United States?"
