工具组摘要

对话记录里,一串连续的工具调用折叠成一行。本页规定这一行写什么:用一句短话说明这些调用做了什么,由客户端根据记录里已有的工具调用生成;如果这串调用改了文件,就带一个 +N −M 徽标。本页也评估是否值得为整轮加一行摘要。

这一行从哪来

assistant-bubble.tsx 把一轮的有序 blocks 切成段:每个文本块单独成段,每串连续的思考和工具块合成一个 ExecutionStrip(execution-strip.tsx),标题由 summarizeToolGroup() 生成。没有有序 blocks 的旧记录走 LegacyRuntimeTrace,它把调用交给同一个函数。折叠行是一行 28px,见聊天轮次视觉规范。

每个调用带的数据

字段来源用途
toolblock通过 tool-presentation.ts 的 presentTool() 归类,和时间线行用同一套分类。
inputblock,调用参数的完整 JSON路径(file_path、path)、命令、搜索模式、URL。edit 带 old_string/new_string,write 带 content,apply_patch 带整个补丁。
result、is_error、outcomeblock成功或失败。edit 的结果写 (N replacements);apply_patch 的结果写 Added、Updated 或 Deleted。
运行中msg.tools[].status哪个调用正在跑。
turnFiles助手消息,结束时从变更日志写入整轮权威的逐文件 op(create/modify/delete)和 added/removed。按路径聚合,没有工具调用 id,只在本轮结束后才有。

所以一轮里两个组改了同一个文件时,不能直接从 turnFiles 读每组的统计。统计从参数推导,缺的部分用 turnFiles 补。

摘要语法

短语

组内调用按类型分桶,每桶一个短语,放在该桶第一次出现的位置,读起来就是事情发生的顺序。短语之间用","连接(英文用 ", ",首字母大写)。思考只在组里没有别的内容时写"思考",否则省略,因为每轮都会思考。

类型(工具)一个多个进行中
命令(bash、process、terminal_use、execute_code)运行了 1 条命令运行了 3 条命令正在运行命令…
新建文件(write 新路径、apply_patch Add File)创建了 pill-shadow.html创建了 2 个文件正在创建 pill-shadow.html…
修改文件(edit、覆盖已有文件的 write、apply_patch Update)修改了 app.tsx修改了 4 个文件正在修改 app.tsx…
删除文件(apply_patch Delete File)删除了 old.css删除了 2 个文件正在删除 old.css…
读取(read、pdf)读取了 package.json读取了 3 个文件正在读取 package.json…
列目录(list)列出了 1 个目录列出了 2 个目录正在列出目录…
代码搜索(grep、glob、semble_*、lsp_*)搜索了"tl-toggle"搜索了 3 次正在搜索"tl-toggle"…
网页搜索(web_search)搜索了网页搜索了 2 次网页正在搜索网页…
抓取(web_fetch)抓取了 docs.anthropic.com抓取了 3 个网页正在抓取 docs.anthropic.com…
浏览器(web_use、agent_browser、playwright_browser)操作了浏览器正在操作浏览器…
子代理(agent、task、send_message)运行了子代理 Reviewer运行了 2 个子代理正在运行子代理 Reviewer…
图片(image_generate / image_analyze)生成了 1 张图片生成了 2 张图片正在生成图片…
待办(todo_*)更新了待办正在更新待办…
提问(ask_user_question)提了 1 个问题正在提问…
记忆(memory_*)读写了记忆正在读写记忆…
程序 / 技能运行了程序 deploy、使用了技能 pdf运行了 2 个程序正在运行程序 deploy…
其他(MCP、自定义)使用了 linear_search(两次时加" 2 次")使用了 linear_search 和 jira_create;使用了 3 个工具正在使用 linear_search…

命名:只有一个文件时写文件名(basename)。命令从不写进标题,因为命令很长,展开后的行里已经有。搜索模式加引号,截到 24 个字符。抓取只写主机名。一个桶只在它恰好有一个目标时才写出目标名,所以出现第二个文件后,"读取了 a.ts"就变成"读取了 2 个文件"。同一文件的重复调用只算一次。

数字:英文单数用 "a"/"an",两个及以上用数字。中文一律用数字加量词(1 条命令、3 个文件、2 次)。

失败:组里任何调用失败时,标题后面跟一个淡红色的"· 1 个失败"。失败的调用仍计入所属的桶;写文件失败不计入徽标。

进行中

当这个组是流式中这一轮的最新部分时,已完成的桶保持过去时,正在执行的调用所属的桶改成进行时并以"…"结尾,并移到行尾(最新一步在眼睛预期的位置),例如"读取了 2 个文件,正在运行命令…"。扫光效果保留。调用完成后,短语回到过去时,放回它第一次出现的位置。组里目前只有思考时,标题是"思考中…"。

截断

屏幕上标题只占一行:标题 span 设 min-width:0 和 CSS 省略号,失败提示、徽标和箭头设 flex:none,永远不会被挤掉。不设字符上限,同一个标题在窄侧栏和宽窗口都能正确显示。这一行不带任何悬停提示:它是对话内容,不是需要解释用途的按钮,展开后就能看到每一次调用。

改动徽标

组里至少有一个写文件调用成功,并且所有成功的写文件调用统计都已知时,才显示徽标。徽标把这些统计加起来,0 也显示(+16 −0),复用本轮文件卡片的 .turn-files-diff 样式。每个调用的统计来源:

write 算"创建"还是"修改"也按这个规则:turnFiles 出现前,本轮之前没读过、没改过该路径的 write 才算"创建";turnFiles 标为 modify 后改成"修改"。

文案

所有短语都走 useTranslation() 现有的 text(en, zh)。每个桶一条:过去时和进行时两种形式,每种又分单目标和计数两种写法。中文过去时用"了",进行时用"正在":"运行了 1 条命令,创建了 pill-shadow.html"、"读取了 2 个文件,正在运行命令…"。

在哪生成

全部由客户端根据结构化工具数据生成,是 tool-presentation.ts 旁边的一个纯函数。不需要模型调用,也不需要改后端。可选的后端改进有一项:在每条变更日志记录上写入工具调用 id,并随工具结果下发该调用的 {path, op, added, removed}。这样流式期间 write 的统计也精确,两个组改同一文件时每组的统计也精确。

预览

每组对比同一批调用的按类别计数标题和本设计的标题。都是 15px 的折叠行,和对话记录一致。

运行命令,然后新建文件
计数
摘要
排查后修一个文件
计数
摘要
网页调研
计数
摘要
MCP 和自定义工具
计数
摘要
有命令失败
计数
摘要
进行中(流式)
计数
摘要
摘要
窄面板里的长组(悬停显示完整标题)
计数
摘要

整轮摘要

评估过在一轮顶部加一行,例如"读取了 9 个文件,修改了 3 个文件,运行了 6 条命令 · +40 −12"。

不做整轮摘要行。别处需要把一轮压成一行时(消息导航、悬停预览、父轮次里的子代理行),由那个界面调用确定性的汇总函数。

实现

实现状态

已按本文实现。可选的后端改进(变更日志记录带工具调用 id)没有做,所以覆盖已有文件的 write 要等本轮结束后才显示徽标。