工具展示

Agent 调用业务自己的工具时,用 renderers.tools 按工具名登记它怎么显示。

tool-renderers.tsx
import { Chatkit, type ChatkitToolViewProps, useChatRuntime } from '@volcengine/chatkit';
import { createMockAdapter } from '@volcengine/chatkit/adapters/mock';
import '@volcengine/chatkit/styles.css';

// Mock 的这个场景依次调用四个工具:report_heartbeat、query_order、shell、web_search。
const adapter = createMockAdapter({ getScenarioId: () => 'product-tools' });

interface OrderResult {
  orderId: string;
  status: string;
  item: string;
  carrier: string;
  trackingNo: string;
}

// 换展开区:行头不变,展开后是自己的组件
function OrderDetail({ result, status }: ChatkitToolViewProps) {
  if (status !== 'completed') return <p>正在查询订单…</p>;
  const order = result as OrderResult;
  return (
    <div className="demo-card">
      <header>
        订单 {order.orderId}
        <span className="demo-badge">{order.status}</span>
      </header>
      {order.item}
      <div className="demo-muted">
        {order.carrier} {order.trackingNo}
      </div>
    </div>
  );
}

// 整行自己画
function ShellRow({ args, status }: ChatkitToolViewProps) {
  return (
    <div className="demo-chips">
      <span className="demo-badge">{status === 'completed' ? '已执行' : '执行中'}</span>
      <code>{String(args?.command ?? '')}</code>
    </div>
  );
}

// 工具展示的四档,从改得最少到改得最多。
export default function ToolRenderers() {
  const runtime = useChatRuntime({ sessionId: 'tool-renderers', adapter });
  if (!runtime) return null;
  return (
    <Chatkit
      runtime={runtime}
      settings={{
        tools: { groupDefaultExpanded: true, detailDefaultExpanded: true },
        runStatus: { collapseOnComplete: false },
        recommendations: ['查一下我的订单到哪了'],
      }}
      renderers={{
        tools: {
          web_search: { runningLabel: '正在查配送时效', successLabel: '已查到配送时效' }, // 只改文字
          query_order: { detail: OrderDetail }, // 换展开区
          shell: { render: ShellRow }, // 整行自己画
          report_heartbeat: { hidden: true }, // 不显示
        },
      }}
    />
  );
}
四档:只改文字的搜索、换了展开区的订单查询、整行自己显示的命令、不显示的心跳新窗口打开

四档

从改得最少到改得最多:

档位写法效果
只改文字{ runningLabel, successLabel }这一行的标题换成自己的文字,其余不变
换展开区{ detail: Component }标题行不变,展开后显示自己的组件
整行自己显示{ render: Component }这一行完全由自己的组件显示
不显示{ hidden: true }这个工具不出现在界面上
<Chatkit
  sessions={sessions}
  renderers={{
    tools: {
      web_search: { runningLabel: '正在搜索资料', successLabel: '已搜索资料' },
      get_weather: { detail: WeatherCard },
      create_order: { render: OrderRow },
      heartbeat: { hidden: true },
    },
  }}
/>

按已有的工具显示:alias

后端的工具名和内置认识的名字不一样时,让它按内置的某个工具显示:

renderers={{ tools: { bash: { alias: 'exec' } } }} // bash 按内置的「执行命令」显示

内置认识的工具:read_file、write_file、edit_file、delete_file、exec、web_search、web_fetch、grep。

一次匹配一组:match

工具名没有精确命中时,按模式匹配。适合一个 MCP 服务下的所有工具:

renderers={{
  tools: {
    github: { match: /^github_/, runningLabel: '正在访问 GitHub', successLabel: '已访问 GitHub' },
  },
}}

match 可以是正则,也可以是函数 (toolName) => boolean。正则依次检查原始名与规范化后的名字;函数只收到原始名。精确名称和别名优先于模式,多个模式命中时采用登记顺序中的第一个。

组件拿到的参数

detail 与 render 的组件拿到同一组参数(ChatkitToolViewProps):

参数说明
title本次调用的展示标题,可通过内容更新补充
metadata业务附加信息
defaultNode仅整行 render 中提供默认工具行;detail 中为空
toolName工具名,后端给的原始名字
toolCallId这次调用的 id
args入参;还没收全时为空
result结果;还没有结果时为空
partialResult运行中陆续给出的部分结果
statusrunning、completed、failed、cancelled
error失败时的展示信息;当前 code 固定为 TOOL_FAILED,message 取字符串结果,否则为空。不是后端原始错误对象
run所属那一轮的运行信息
import type { ChatkitToolViewProps } from '@volcengine/chatkit';

function WeatherCard({ args, result, status }: ChatkitToolViewProps) {
  if (status === 'running') return <p>正在查询 {String(args?.city ?? '')} 的天气…</p>;
  if (status === 'failed') return <p>查询失败</p>;
  if (status === 'cancelled') return <p>查询已取消</p>;
  if (result == null) return <p>查询结束,暂无结果</p>;
  return <Weather data={result as WeatherData} />;
}

配置项

配置项类型默认说明
renderers.toolsRecord<string, ChatkitToolRenderer>—工具:按工具名登记。
settings.toolFlow"group" | "step" | "none"'group'执行过程的显示方式:`group` 合并成可折叠的执行流;`step` 逐个工具一行;`none` 不显示。
settings.tools.groupDefaultExpandedbooleanfalse执行流默认是否展开。没有设置时跟着 `reasoning.defaultExpanded` 走。
settings.tools.detailDefaultExpandedbooleanfalse单个工具的详情(入参 / 结果)默认是否展开。

说明

  • 工具名先统一格式再查:驼峰、连字符、点、空格都视为相同,并去掉 mcp__服务名__ 前缀。getWeather、get-weather、mcp__tools__get_weather 都能命中 get_weather。
  • 给内置工具登记时,只改写了的部分,其余保持内置的显示。
  • 同时写了 detail 与 render 时,render 生效。
  • hidden 只隐藏工具展示,不会禁止调用或阻止参数、结果到达浏览器;敏感内容应在后端或适配器中处理。
  • 自定义组件需处理运行中、失败、取消和空结果;不能把所有非运行中状态都视为成功。结果结构应按具体工具校验。
  • 工具调用属于执行过程:这一轮完成后随执行过程收起,点状态行展开回看。要一直显示在回答里的内容用业务卡片。
  • 执行流整体的显示方式(合并、逐个、不显示)用 settings.toolFlow,见思考与工具调用。