How to Register Local Tools for LLM Execution in Tambo AI: A Complete Guide

Register local tools for LLM execution in Tambo AI by wrapping JavaScript functions in TamboTool objects and passing them to <TamboProvider> for static registration or calling registerTool() from the useTambo hook for dynamic registration.

Tambo AI enables LLM-driven applications to execute local JavaScript tools directly in the user's browser. When you register local tools for LLM execution in Tambo AI, you create a bridge between the model's reasoning capabilities and your application's functionality. This guide covers the complete implementation using the tambo-ai/tambo repository's React SDK.

Understanding Local Tool Registration in Tambo AI

Local tools are plain JavaScript functions that the LLM can invoke during a conversation. When you register local tools for LLM execution, Tambo AI maintains a tool registry (Map<string, TamboTool>) that maps tool names to their implementations.

During conversation, when the model emits a tool_use event, the SDK looks up the tool name in this registry and executes the corresponding function via executeClientTool located in react-sdk/src/v1/utils/tool-executor.ts (source).

Static vs Dynamic Tool Registration

Tambo AI supports two patterns to register local tools for LLM execution:

Static Registration with TamboProvider

Static registration occurs at application startup. You pass an array of TamboTool objects to the tools prop of <TamboProvider>. The provider builds the registry once at mount time using the internal registerAllTools function.

This approach is ideal for core application functionality that must be available immediately.

Dynamic Registration with useTambo

Dynamic registration allows you to add tools at runtime based on user actions or authentication state. The useTambo hook exposes registerTool and registerTools methods that update the registry on-the-fly.

This pattern is defined in react-sdk/src/v1/hooks/use-tambo-v1.ts (source).

Step-by-Step: Register Local Tools for LLM Execution

Follow these steps to implement local tool registration in your Tambo AI application.

Step 1: Define the Tool Function

Create the JavaScript function that performs the desired action. This function runs entirely in the browser.

// utils/api.ts
export const getWeather = async (city: string) => {
  const res = await fetch(`/api/weather?city=${encodeURIComponent(city)}`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return await res.json();
};

Step 2: Create the TamboTool Definition

Wrap your function in a TamboTool object that provides metadata for the LLM. This definition includes Zod schemas for runtime validation.

// tools/weatherTool.ts
import { TamboTool } from "@tambo-ai/react";
import { z } from "zod";
import { getWeather } from "../utils/api";

export const weatherTool: TamboTool = {
  name: "get_weather",
  description: "Fetch current weather information for a specified city",
  tool: getWeather,
  inputSchema: z.string().describe("The city to fetch weather for"),
  outputSchema: z.object({
    location: z.object({ name: z.string() }),
    temperature: z.number(),
    condition: z.string(),
  }),
};

The inputSchema and outputSchema are validated at runtime. Mismatched arguments produce clear errors rather than silent failures.

Step 3: Register the Tool Statically or Dynamically

Static registration via TamboProvider:

// src/lib/tambo.ts
import { TamboProvider } from "@tambo-ai/react";
import { weatherTool } from "./tools/weatherTool";

export const TamboApp = () => (
  <TamboProvider tools={[weatherTool]}>
    <App />
  </TamboProvider>
);

Dynamic registration via useTambo:

// src/components/AuthGate.tsx
import { useTambo } from "@tambo-ai/react";
import { weatherTool } from "../tools/weatherTool";
import { useEffect } from "react";

export const AuthGate = () => {
  const { registerTool } = useTambo();

  useEffect(() => {
    registerTool(weatherTool);
  }, [registerTool]);

  return <>{/* rest of UI */}</>;
};

Both approaches ultimately populate the central registry managed by registerAllTools in apps/web/lib/tambo/tools/tool-registry.ts (source).

Step 4: Enable Streaming Execution (Optional)

For tools that can handle partial arguments and provide real-time updates, enable streaming execution:

export const chartTool: TamboTool = {
  name: "update_chart",
  description: "Update the chart visualization with new data",
  tool: updateChart,
  inputSchema: z.object({
    title: z.string().optional(),
    values: z.array(z.number()).optional(),
  }),
  outputSchema: z.void(),
  annotations: { tamboStreamableHint: true },
};

When tamboStreamableHint: true is set, the SDK invokes executeStreamableToolCall and createThrottledStreamableExecutor from react-sdk/src/v1/utils/tool-executor.ts (source). This throttles repeated calls while arguments stream in, enabling real-time UI updates without flooding the browser.

How Tool Execution Works Under the Hood

When you register local tools for LLM execution in Tambo AI, the following execution flow occurs:

  1. Registry Construction: Tools are stored in a Map<string, TamboTool> registry, either at provider mount time or dynamically via registerTool.

  2. Tool Invocation: When the LLM emits a tool_use event, the SDK calls executeClientTool in react-sdk/src/v1/utils/tool-executor.ts (source).

  3. Validation: Input arguments are validated against the inputSchema using Zod before execution.

  4. Execution: The wrapped function runs in the browser, performing local computations or API calls.

  5. Result Handling: The output is validated against outputSchema, optionally transformed via transformToContent, and returned as a ToolResultContent object that the SDK injects back into the conversation thread.

Type definitions for TamboTool are located in packages/core/src/ui-tools.ts, while server-side tool counterparts reside in packages/backend/src/util/tools.ts.

Summary

  • Register local tools for LLM execution in Tambo AI by wrapping JavaScript functions in TamboTool objects that include Zod schemas for validation.
  • Use static registration via <TamboProvider tools={...}> for tools needed at application startup.
  • Use dynamic registration via the registerTool method from useTambo() for runtime tool addition.
  • Enable streaming execution by setting annotations.tamboStreamableHint: true for tools that support partial argument processing.
  • The tool registry is maintained in react-sdk/src/v1/utils/tool-executor.ts and apps/web/lib/tambo/tools/tool-registry.ts, with execution handled by executeClientTool.

Frequently Asked Questions

What is the difference between static and dynamic tool registration in Tambo AI?

Static registration occurs when you pass tools to the tools prop of <TamboProvider>, building the registry once at component mount. Dynamic registration uses the registerTool function returned by useTambo() to add tools at runtime based on user actions or authentication state. Both methods ultimately populate the same central registry used by executeClientTool.

How does Tambo AI validate tool inputs and outputs?

Tambo AI uses Zod schemas defined in the inputSchema and outputSchema properties of a TamboTool object. When a tool is invoked, arguments are validated against inputSchema before execution, and return values are validated against outputSchema afterward. This runtime validation prevents silent failures and provides clear error messages when data doesn't match expected shapes.

Can I register tools that update the UI in real-time as the LLM streams arguments?

Yes. Set annotations: { tamboStreamableHint: true } in your TamboTool definition. This enables the streaming executor (executeStreamableToolCall and createThrottledStreamableExecutor in react-sdk/src/v1/utils/tool-executor.ts) to invoke your tool repeatedly as partial arguments arrive, throttled to avoid performance issues. This pattern is ideal for tools that update charts or visualizations incrementally.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →