Tulip Logo IconTulip
Recipes

Tool Renderers

Render tool calls in chat using client definitions while keeping server tools out of the client bundle.

Tool renderers make demos and production assistants easier to understand.

Define a renderer

"use client";

import { ToolCallCard } from "@tulip-systems/ai/chat/client";
import { defineToolClient } from "@tulip-systems/ai/tools/client";
import { Search } from "lucide-react";
import type { searchCrmRecords } from "./tool.server";

export const searchCrmRecordsToolClient = defineToolClient<typeof searchCrmRecords>({
  toolName: "search_crm_records",
  render: (part) => (
    <ToolCallCard
      part={part}
      title="CRM records zoeken"
      icon={<Search className="size-3.5" />}
      labels={{ output: "Gevonden records" }}
    />
  ),
});

Share renderers

Centralize tool renderers near the chat configuration:

export const ASSISTANT_TOOL_CLIENTS = [
  webSearchToolClient,
  delegateToSalesToolClient,
  searchCrmRecordsToolClient,
  createProspectToolClient,
];

Then pass them to messages:

<ChatThreadMessage message={message} toolRenderers={ASSISTANT_TOOL_CLIENTS} />

Guidance

  • Use import type for server tools.
  • Start with ToolCallCard before building custom cards.
  • Render important mutation tools more clearly than background read tools.
  • Keep renderers stable and reusable across full-page chat and sidepanel chat.

On this page