tools

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

assistant-ui Tools

assistant-ui Tools

Always consult assistant-ui.com/llms.txt for latest API.
Tools let LLMs trigger actions with custom UI rendering.
请始终参考assistant-ui.com/llms.txt获取最新API。
工具允许LLMs通过自定义UI渲染来触发操作。

References

参考资料

  • ./references/make-tool.md -- makeAssistantTool/useAssistantTool
  • ./references/tool-ui.md -- makeAssistantToolUI rendering
  • ./references/human-in-loop.md -- Confirmation patterns
  • ./references/make-tool.md -- makeAssistantTool/useAssistantTool
  • ./references/tool-ui.md -- makeAssistantToolUI渲染
  • ./references/human-in-loop.md -- 确认模式

Tool Types

工具类型

Where does the tool execute?
├─ Backend (LLM calls API) → AI SDK tool()
│  └─ Want custom UI? → makeAssistantToolUI
└─ Frontend (browser-only) → makeAssistantTool
   └─ Want custom UI? → makeAssistantToolUI
工具执行位置?
├─ 后端(LLM调用API)→ AI SDK tool()
│  └─ 需要自定义UI?→ makeAssistantToolUI
└─ 前端(仅浏览器)→ makeAssistantTool
   └─ 需要自定义UI?→ makeAssistantToolUI

Backend Tool with UI

带UI的后端工具

ts
// Backend (app/api/chat/route.ts)
import { tool, stepCountIs } from "ai";
import { z } from "zod";

const tools = {
  get_weather: tool({
    description: "Get weather for a city",
    inputSchema: z.object({ city: z.string() }),
    execute: async ({ city }) => ({ temp: 22, city }),
  }),
};

const result = streamText({
  model: openai("gpt-4o"),
  messages,
  tools,
  stopWhen: stepCountIs(5),
});
tsx
// Frontend
import { makeAssistantToolUI } from "@assistant-ui/react";

const WeatherToolUI = makeAssistantToolUI({
  toolName: "get_weather",
  render: ({ args, result, status }) => {
    if (status === "running") return <div>Loading weather...</div>;
    return <div>{result?.city}: {result?.temp}°C</div>;
  },
});

// Register in app
<AssistantRuntimeProvider runtime={runtime}>
  <WeatherToolUI />
  <Thread />
</AssistantRuntimeProvider>
ts
// Backend (app/api/chat/route.ts)
import { tool, stepCountIs } from "ai";
import { z } from "zod";

const tools = {
  get_weather: tool({
    description: "Get weather for a city",
    inputSchema: z.object({ city: z.string() }),
    execute: async ({ city }) => ({ temp: 22, city }),
  }),
};

const result = streamText({
  model: openai("gpt-4o"),
  messages,
  tools,
  stopWhen: stepCountIs(5),
});
tsx
// Frontend
import { makeAssistantToolUI } from "@assistant-ui/react";

const WeatherToolUI = makeAssistantToolUI({
  toolName: "get_weather",
  render: ({ args, result, status }) => {
    if (status === "running") return <div>Loading weather...</div>;
    return <div>{result?.city}: {result?.temp}°C</div>;
  },
});

// Register in app
<AssistantRuntimeProvider runtime={runtime}>
  <WeatherToolUI />
  <Thread />
</AssistantRuntimeProvider>

Frontend-Only Tool

仅前端工具

tsx
import { makeAssistantTool } from "@assistant-ui/react";
import { z } from "zod";

const CopyTool = makeAssistantTool({
  toolName: "copy_to_clipboard",
  parameters: z.object({ text: z.string() }),
  execute: async ({ text }) => {
    await navigator.clipboard.writeText(text);
    return { success: true };
  },
});

<AssistantRuntimeProvider runtime={runtime}>
  <CopyTool />
  <Thread />
</AssistantRuntimeProvider>
tsx
import { makeAssistantTool } from "@assistant-ui/react";
import { z } from "zod";

const CopyTool = makeAssistantTool({
  toolName: "copy_to_clipboard",
  parameters: z.object({ text: z.string() }),
  execute: async ({ text }) => {
    await navigator.clipboard.writeText(text);
    return { success: true };
  },
});

<AssistantRuntimeProvider runtime={runtime}>
  <CopyTool />
  <Thread />
</AssistantRuntimeProvider>

API Reference

API参考

tsx
// makeAssistantToolUI props
interface ToolUIProps {
  toolCallId: string;
  toolName: string;
  args: Record<string, unknown>;
  argsText: string;
  result?: unknown;
  status: "running" | "complete" | "incomplete" | "requires-action";
  submitResult: (result: unknown) => void;  // For interactive tools
}
tsx
// makeAssistantToolUI props
interface ToolUIProps {
  toolCallId: string;
  toolName: string;
  args: Record<string, unknown>;
  argsText: string;
  result?: unknown;
  status: "running" | "complete" | "incomplete" | "requires-action";
  submitResult: (result: unknown) => void;  // For interactive tools
}

Human-in-the-Loop

人机协作模式

tsx
const DeleteToolUI = makeAssistantToolUI({
  toolName: "delete_file",
  render: ({ args, status, submitResult }) => {
    if (status === "requires-action") {
      return (
        <div>
          <p>Delete {args.path}?</p>
          <button onClick={() => submitResult({ confirmed: true })}>Confirm</button>
          <button onClick={() => submitResult({ confirmed: false })}>Cancel</button>
        </div>
      );
    }
    return <div>File deleted</div>;
  },
});
tsx
const DeleteToolUI = makeAssistantToolUI({
  toolName: "delete_file",
  render: ({ args, status, submitResult }) => {
    if (status === "requires-action") {
      return (
        <div>
          <p>Delete {args.path}?</p>
          <button onClick={() => submitResult({ confirmed: true })}>Confirm</button>
          <button onClick={() => submitResult({ confirmed: false })}>Cancel</button>
        </div>
      );
    }
    return <div>File deleted</div>;
  },
});

Common Gotchas

常见问题

Tool UI not rendering
  • toolName
    must match exactly (case-sensitive)
  • Register UI inside
    AssistantRuntimeProvider
Tool not being called
  • Check tool description is clear
  • Use
    stopWhen: stepCountIs(n)
    to allow multi-step
Result not showing
  • Tool must return a value
  • Check
    status === "complete"
    before accessing result
工具UI未渲染
  • toolName
    必须完全匹配(区分大小写)
  • AssistantRuntimeProvider
    内部注册UI
工具未被调用
  • 检查工具描述是否清晰
  • 使用
    stopWhen: stepCountIs(n)
    来允许多步骤执行
结果未显示
  • 工具必须返回值
  • 在访问结果前检查
    status === "complete"