跳转到内容

ToolCall 工具调用 alpha

一次工具调用的卡片:阶段、参数与结果,运行时自动展开、结束后自动收起,用户手动操作过一次后不再自动开合。

用法

等待批准不是运行中:闸门常驻在开关与详情之间,不会被折叠隐藏

找到 3 条结果。
这一步要先经你批准。

组件结构

加粗的是必需部件。

data-scope="tool-call"root · trigger · indicator · label · summary · status · duration · approval · content · input · output · error

示例

自动开合与锁存

运行时自动展开、结束时自动收起;用户手动开合过一次之后,阶段如何变化都不再自动开合

{ "path": "src/index.ts" }

上一次开合来自:还没动过

摘要与耗时

详情收起时也能看到查询内容与运行时长;两个时刻由宿主提供,组件自身不读取时钟

多次调用分组

外层套一层手风琴作为分组头:计数使用等宽数位,整组开合归手风琴,卡片各自独立

形态、语气与尺寸

三轴只改变该外壳与正文分开的方式,阶段与展开逻辑不受影响

设计指引

何时使用

  • Agent 界面中展示正在执行的操作:查询了什么、传了什么参数、返回了什么。
  • 一次调用需要先经用户批准才能执行。

何时不用

  • 展示思考过程而不是一次调用时,使用思考过程,两者共用同一台状态机但正文形态不同。
  • 只需要一个状态色块时,使用徽标,配 toneOfToolCallPhase(phase) 取语气。
  • 多次调用一次只展开一张时,外层使用手风琴,每格放一张。

特性

  • 五档阶段:参数传输中、参数完整、等待批准、已完成、出错。等待批准不是运行中:协议层的审批只改变审批状态、不改变工具状态,没有这一档时等待中的调用会被视为运行中。
  • 自动开合的锁存依靠转移的放置位置,不依靠布尔位:用户点击过一次之后,阶段变化在结构上无法到达任何转移,自动开合永久停用。
  • 审批闸门常驻在开关与详情之间,不会被折叠隐藏。
  • 收起使用 hidden + inert:退场动画完成前内容仍在渲染,inert 把这段窗口挡在读屏与 Tab 序列之外。
  • 开关行保留摘要位与耗时位:详情收起时也能看到查询内容与运行时长。
  • 耗时由宿主提供两个时刻,toolCallDuration(startTime, endTime) 计算毫秒数;组件自身不读时钟也不启动定时器,秒数跳动由宿主驱动。

组合

  • 参数与结果使用代码视图:参数在流式期是不完整的 JSON,把 complete 接为“阶段不是参数传输中”即可。富文本结果使用流式正文
  • 结果是代码改动时,详情区放差异视图;收起态的摘要取它的 stats 组成 +{added} −{removed} 文件名 写进摘要位,减号使用 U+2212 而不是连字符。摘要需要悬停查看全文时使用悬浮卡片,不自行向 body 挂载节点。
  • 审批区放审批
  • 复制不内建,与剪贴板组合;多张并排需要方向键跳转时外层使用工具栏
  • 一轮中运行多次工具时,外层使用手风琴分组:手风琴的开关写“运行了 N 个工具”,计数段加 font-variant-numeric: tabular-nums 避免数字跳动时左右移动;整组的开合由手风琴的 aria-expanded 承担,卡片各自只管理自身。

最佳实践

  • 工具名与状态都写在开关内,它们自然构成开关的可访问名称(“搜索,已完成”)。
  • 出错态要容忍没有错误文本:流被中止时未获得结果的调用会被收尾为出错,但没有原因。
  • 摘要位只放一句可一眼读完的参数(查询词、文件路径),完整 JSON 留给详情内的代码视图。
  • 耗时文案使用 translations.ranFor 模板串,秒数由宿主代入;endTime 缺席时不渲染该位。

反模式

  • 每张卡各开一个 aria-live:一屏五张卡就是五个活动区域互相打断。
  • 用禁用表达“暂不能展开”:读屏用户无法得知它的存在。

API 参考

产物

自定义元素<xh-tool-call>
Vue 组件XhToolCallApproval XhToolCallContent XhToolCallDuration XhToolCallError XhToolCallIndicator XhToolCallInput XhToolCallLabel XhToolCallOutput XhToolCallRoot XhToolCallStatus XhToolCallSummary XhToolCallTrigger
组合式函数useToolCall
状态机toolCallMachine
皮肤@xihan-ui/styles/tool-call.css

Props

属性类型必填说明
runningboolean本次调用正在运行。适配器用 isToolCallRunning(phase) 折叠得出,作者只写 phase。
openboolean
defaultOpenboolean
autoDisclosureboolean运行时自动展开、结束时自动收起,默认开启;用户手动开合过一次即永久停用。
disabledboolean
onOpenChange(details: ToolCallOpenChangeDetails) => void
endTimenumber本次调用结束的时刻。可能缺席:仍在运行,或流被中止时兜底收尾不写该字段。
phaseToolCallPhase本次调用所处的阶段,默认 input-available。
sizeSize
startTimenumber本次调用开始的时刻,毫秒时间戳。
toneTone
translationsPartial<ToolCallTranslations>
variantControlVariant形态:outline 描边、subtle 底色分区、ghost 无壳内联。默认 outline。

事件

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
open-changeToolCallOpenChangeDetails开合变化;detail 为 { open: boolean, source: 'user' | 'auto' | 'api' }

插槽

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhToolCallRootdefaultToolCallRootSlotProps

状态

公开状态写入 data-state

部件取值
root'open' | 'closed'
trigger'open' | 'closed'
indicator'open' | 'closed'
labelprops.phase
summaryprops.phase
statusprops.phase
durationprops.phase
approvalprops.phase
content'open' | 'closed'
inputprops.phase
outputprops.phase
errorprops.phase

以下名称仅用于内部状态机。

状态auto.collapsed · auto.expanded · held.collapsed · held.expanded

事件TOGGLE · OPEN · CLOSE · PHASE.ACTIVE · PHASE.SETTLE · CONTROLLED.OPEN · CONTROLLED.CLOSE · PRESS.START · PRESS.END

判据isOpenControlled · isAutoAllowed · isAutoEnabled · canPress

connect API

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
openboolean
phaseToolCallPhase
runningboolean该档是否视为运行中。
settledboolean该档是否视为已落定:运行完成,或失败。
erroredboolean该档是否视为失败。
disabledboolean
statusTextstring读屏文案,由宿主写入会话级的播报区。
durationMsnumber | undefined运行时长,毫秒;两个时刻任一缺席即 undefined。
setOpen(next: boolean) => void
getRootProps() => T['element']
getTriggerProps() => T['button']
getIndicatorProps() => T['element']
getLabelProps() => T['element']
getSummaryProps() => T['element']
getStatusProps() => T['element']
getDurationProps() => T['element']
getApprovalProps() => T['element']
getContentProps() => T['element']
getInputProps() => T['element']
getOutputProps() => T['element']
getErrorProps() => T['element']

无障碍

键盘

规格出处:W3C APG

按键生效条件行为
Enter / Space焦点在折叠开关上且未禁用展开或收起详情,并把自动开合永久停用
Enter / Space按住折叠开关且未禁用按住期间 trigger 投影 data-pressed,与指针 :active 同一副按压面(disclosure trigger 只换面不缩放);抬起、失焦或转禁用撤下。运行中照常接

ARIA

以下属性由 connect 生成。

部件属性
triggeraria-controlscontent 部件的 id
triggeraria-describedbyerror 部件的 id | undefined
triggeraria-expanded'true' | 'false'
indicatoraria-hidden'true'
contentaria-labelledbytrigger 部件的 id
contentrole'region'
  • 开关带 aria-expandedaria-controls,详情区是 role=region 且由开关命名。
  • 出错时开关才补 aria-describedby 指向错误区,无条件挂载会指向作者未渲染的节点。
  • 卡片自身不开活动区域:一屏多张卡各开一个会互相打断。播报文本由 statusText 交出,由宿主写进会话级的播报区。

样式参考

皮肤

@xihan-ui/styles/tool-call.css 使用 [data-scope="tool-call"][data-part="root"] 部件选择器,位于 xihan.componentsxihan.motion 层。覆盖样式使用 xihan.overrides

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性

connect 生成;条件不成立时不输出无值属性。

部件属性
rootdata-disabled''(条件成立时才出现)
rootdata-errored''(条件成立时才出现)
rootdata-loading''(条件成立时才出现)
rootdata-settled''(条件成立时才出现)
rootdata-sizeprops.size
rootdata-state'open' | 'closed'
rootdata-toneprops.tone
rootdata-variantprops.variant
triggerdata-disabled''(条件成立时才出现)
triggerdata-pressed''(条件成立时才出现)
triggerdata-state'open' | 'closed'
triggerdata-xh-action-control''
triggerdata-xh-action-display'always'
triggerdata-xh-action-profile'disclosure-trigger'
triggerdata-xh-action-sizeprops.size
triggerdata-xh-action-variant'ghost'
indicatordata-state'open' | 'closed'
labeldata-stateprops.phase
summarydata-stateprops.phase
statusdata-stateprops.phase
durationdata-loading''(条件成立时才出现)
durationdata-stateprops.phase
approvaldata-stateprops.phase
contentdata-state'open' | 'closed'
inputdata-stateprops.phase
outputdata-stateprops.phase
errordata-stateprops.phase

CSS 变量

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-tool-call-bgrootbackgrounddefault
variant=subtle
--xh-bg-subtle
--xh-bg-surface
tool-call 的 root 部件 background 覆盖槽。
--xh-tool-call-borderrootborderdefault--xh-border-defaulttool-call 的 root 部件 border 覆盖槽。
--xh-tool-call-border-errorrootborder-colorerrored
has([data-scope='tool-call'][data-state='output-error'])
state=output-error
--xh-border-invalidtool-call 的 root 部件 border-color 覆盖槽。
--xh-tool-call-content-gapcontentgapdefault--xh-space-2tool-call 的 content 部件 gap 覆盖槽。
--xh-tool-call-dividerapproval
content
border-block-startdefault--xh-border-subtletool-call 的 approval、content 部件 border-block-start 覆盖槽。
--xh-tool-call-duration-fgdurationcolordefault--xh-fg-subtletool-call 的 duration 部件 color 覆盖槽。
--xh-tool-call-error-fgerrorcolordefault--xh-fg-dangertool-call 的 error 部件 color 覆盖槽。
--xh-tool-call-font-sizetriggerfont-sizedefault--xh-_tool-call-font-sizetool-call 的 trigger 部件 font-size 覆盖槽。
--xh-tool-call-icon-sizeroot
trigger
--xh-icon-sizedefault--xh-_action-profile-glyph-size
--xh-glyph-size-md
tool-call 的 root、trigger 部件 --xh-icon-size 覆盖槽。
--xh-tool-call-indicator-fgindicatorcolordefault--xh-fg-subtletool-call 的 indicator 部件 color 覆盖槽。
--xh-tool-call-label-fontlabel
summary
font-familydefault--xh-font-family-monotool-call 的 label、summary 部件 font-family 覆盖槽。
--xh-tool-call-pxapproval
content
trigger
padding-inlinedefault--xh-_tool-call-pxtool-call 的 approval、content、trigger 部件 padding-inline 覆盖槽。
--xh-tool-call-pyapproval
content
trigger
padding-block
padding-block-end
padding-block-start
@keyframes xh-disclosure-collapse
@keyframes xh-disclosure-expand
default
xh-action-profile=disclosure-trigger
--xh-_tool-call-pytool-call 的 approval、content、trigger 部件 padding-block、padding-block-end、padding-block-start 覆盖槽。
--xh-tool-call-radiusrootborder-radiusdefault--xh-shape-surfacetool-call 的 root 部件 border-radius 覆盖槽。
--xh-tool-call-shadowrootbox-shadowdefault
tone
0 0 0 transparent
none
tool-call 的 root 部件 box-shadow 覆盖槽。
--xh-tool-call-shimmer-durationroot
status
animationloading--xh-shimmer-durationtool-call 的 root、status 部件 animation 覆盖槽。
--xh-tool-call-status-bg-approvalstatusbackgroundstate=awaiting-approval--xh-fg-warningtool-call 的 status 部件 background 覆盖槽。
--xh-tool-call-status-bg-donestatusbackgroundstate=output-available--xh-fg-successtool-call 的 status 部件 background 覆盖槽。
--xh-tool-call-status-bg-errorstatusbackgroundstate=output-error--xh-fg-dangertool-call 的 status 部件 background 覆盖槽。
--xh-tool-call-status-fgroot
status
color@media (prefers-reduced-motion: reduce)
@media print
default
loading
motion=reduce
where([data-motion='reduce'])
--xh-fg-mutedtool-call 的 root、status 部件 color 覆盖槽。
--xh-tool-call-status-fg-approvalstatuscolorstate=awaiting-approval--xh-fg-warningtool-call 的 status 部件 color 覆盖槽。
--xh-tool-call-status-fg-donestatuscolorstate=output-available--xh-fg-successtool-call 的 status 部件 color 覆盖槽。
--xh-tool-call-status-fg-errorstatuscolorstate=output-error--xh-fg-dangertool-call 的 status 部件 color 覆盖槽。
--xh-tool-call-status-font-sizeduration
error
status
font-sizedefault--xh-text-caption-sizetool-call 的 duration、error、status 部件 font-size 覆盖槽。
--xh-tool-call-status-pxstatuspadding-inlinestate=awaiting-approval
state=output-available
state=output-error
--xh-space-2tool-call 的 status 部件 padding-inline 覆盖槽。
--xh-tool-call-status-pystatuspadding-blockstate=awaiting-approval
state=output-available
state=output-error
--xh-space-0_5tool-call 的 status 部件 padding-block 覆盖槽。
--xh-tool-call-status-radiusstatusborder-radiusstate=awaiting-approval
state=output-available
state=output-error
--xh-shape-pilltool-call 的 status 部件 border-radius 覆盖槽。
--xh-tool-call-status-shimmer-baseroot
status
background-imageloading--xh-fg-subtletool-call 的 root、status 部件 background-image 覆盖槽。
--xh-tool-call-status-shimmer-sheenroot
status
background-imageloading--xh-fg-defaulttool-call 的 root、status 部件 background-image 覆盖槽。
--xh-tool-call-summary-bgsummarybackgrounddefault--xh-bg-subtletool-call 的 summary 部件 background 覆盖槽。
--xh-tool-call-summary-fgsummarycolordefault--xh-fg-mutedtool-call 的 summary 部件 color 覆盖槽。
--xh-tool-call-summary-font-sizesummaryfont-sizedefault--xh-text-caption-sizetool-call 的 summary 部件 font-size 覆盖槽。
--xh-tool-call-summary-pxsummarypadding-inlinedefault--xh-space-1_5tool-call 的 summary 部件 padding-inline 覆盖槽。
--xh-tool-call-summary-radiussummaryborder-radiusdefault--xh-shape-controltool-call 的 summary 部件 border-radius 覆盖槽。
--xh-tool-call-tone-barrootbox-shadowtone--xh-stroke-thicktool-call 的 root 部件 box-shadow 覆盖槽。
--xh-tool-call-tone-fgrootbox-shadowtone--xh-_tone-softtool-call 的 root 部件 box-shadow 覆盖槽。
--xh-tool-call-trigger-bg-hovertriggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hovertool-call 的 trigger 部件 background-color 覆盖槽。
--xh-tool-call-trigger-fgtriggercolordefault--xh-fg-defaulttool-call 的 trigger 部件 color 覆盖槽。
--xh-tool-call-trigger-gaptriggergapdefault--xh-space-2tool-call 的 trigger 部件 gap 覆盖槽。
--xh-tool-call-trigger-radiusroot
trigger
border-radiusvariant=ghost--xh-shape-controltool-call 的 root、trigger 部件 border-radius 覆盖槽。

动效

关键帧 xh-tool-call-enter · xh-tool-call-shimmer 随皮肤自带,不引用别处文件里的名字;共享关键帧 xh-disclosure-collapse · xh-disclosure-expandfamily/motion.css 提供,皮肤 @import 它,单独引入仍成立;rotatetransition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

皮肤之外还有一段:退场由适配器的退场闸门把关,动画播完才真收起。

prefers-reduced-motion: reduce 下本组件另有降级规则。

RTL

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;另有按 dir 分支的规则。

Released under The MIT License