fix(web): 智能体汇报展示层兜底与进度口径(FIX-7)
- 汇报正文里的 UUID、能力 ID、原因码展示时换成名称和人话,原文收进「正文原文」,历史不改 - 步骤进度统一 stepProgress:分子只数完成,跳过单独计(「4/6 · 跳过 2」) - 进度行不再把失败的调用算进动作计数(3 次被拒的派发曾写成「派出了 5 个子会话」); 实际结果行按会话树显示派出的子会话数 - 会话标题里的 ISO 时间与 download_failed 等码转人话 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
1b22bb5131
commit
417af9f253
9 files changed
+393
-27
No files matched your search
@@ -62,14 +62,15 @@ const joinNouns = (xs: string[]) =>
|
||||
|
||||
/**
|
||||
* 「查了 1 个站点、2 个下载任务和媒体库,搜了 3 次资源」:按能力元数据的 verb / noun 计数,
|
||||
* 同一动作的对象合并,动作按第一次出现排序;被拒绝和隐藏的调用不计入。超过 4 种动作只写前 3 种。
|
||||
* 同一动作的对象合并,动作按第一次出现排序;被拒绝、失败和隐藏的调用不计入(失败的在进度行另计「N 项失败」,
|
||||
* 否则 3 次被预算拒绝的派发 + 2 次成功会写成「派出了 5 个子会话」)。超过 4 种动作只写前 3 种。
|
||||
*/
|
||||
export function activitySummary(calls: Pick<ToolCallView, "capabilityId" | "status" | "outputSummary">[]): string {
|
||||
const groups: Group[] = [];
|
||||
for (const c of calls) {
|
||||
const a = activityOf(c.capabilityId);
|
||||
if (a.hidden) continue;
|
||||
if (c.status === "denied" || authDenial(c)) continue;
|
||||
if (c.status === "denied" || c.status === "failed" || authDenial(c)) continue;
|
||||
let g = groups.find((x) => x.verb === a.verb);
|
||||
if (!g) {
|
||||
g = { verb: a.verb, nouns: [] };
|
||||
@@ -85,6 +86,34 @@ export function activitySummary(calls: Pick<ToolCallView, "capabilityId" | "stat
|
||||
return groups.map(text).join(",");
|
||||
}
|
||||
|
||||
// ── 步骤进度 ──
|
||||
|
||||
type StepLike = { status: "pending" | "running" | "done" | "skipped" | "failed"; title: string };
|
||||
|
||||
/**
|
||||
* 步骤进度(概况条与展开的步骤清单共用一个口径):分子只数完成的步骤,跳过的单独计。
|
||||
* 「4/6 · 跳过 2」;全部结束且有跳过时状态写「完成 4 · 跳过 2」,不再写「全部完成」。
|
||||
* pct 按已结束(完成 + 跳过 + 失败)算进度条宽度。
|
||||
*/
|
||||
export function stepProgress(steps: readonly StepLike[]) {
|
||||
const done = steps.filter((s) => s.status === "done").length;
|
||||
const skipped = steps.filter((s) => s.status === "skipped").length;
|
||||
const failedStep = steps.find((s) => s.status === "failed") ?? null;
|
||||
const failed = steps.filter((s) => s.status === "failed").length;
|
||||
const total = steps.length;
|
||||
const current = steps.find((s) => s.status === "running") ?? steps.find((s) => s.status === "pending") ?? null;
|
||||
const count = `${done}/${total}${skipped ? ` · 跳过 ${skipped}` : ""}`;
|
||||
const status = failedStep
|
||||
? `失败:${failedStep.title}`
|
||||
: current
|
||||
? `当前:${current.title}`
|
||||
: skipped
|
||||
? `完成 ${done} · 跳过 ${skipped}`
|
||||
: "全部完成";
|
||||
const pct = total ? Math.round(((done + skipped + failed) / total) * 100) : 0;
|
||||
return { done, skipped, failed, total, current, failedStep, count, status, pct };
|
||||
}
|
||||
|
||||
/** 正在进行的那一步:「正在检测站点」 */
|
||||
export function runningText(call: Pick<ToolCallView, "capabilityId">): string {
|
||||
const a = activityOf(call.capabilityId);
|
||||
|
||||
Reference in new issue
Block a user