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
@@ -60,6 +60,7 @@ import {
|
||||
runningText,
|
||||
toolSummary,
|
||||
} from "./conversation-model.ts";
|
||||
import { collectNames, humanizeReport } from "./report-humanize.ts";
|
||||
import { ToolCallIo } from "./tool-call-card-io.tsx";
|
||||
import type { AgentStreamState, StreamItem, ToolCallView } from "./use-agent-stream.ts";
|
||||
|
||||
@@ -439,6 +440,7 @@ export function AgentConversation({
|
||||
userMessages = [],
|
||||
audit,
|
||||
after,
|
||||
knownNames,
|
||||
}: {
|
||||
run: AgentRunView;
|
||||
live: AgentStreamState;
|
||||
@@ -446,6 +448,8 @@ export function AgentConversation({
|
||||
audit?: InvocationAudit[];
|
||||
/** 流末尾追加的内容(其它审批卡、实际结果行) */
|
||||
after?: ReactNode;
|
||||
/** 工具结果之外已知的「ID → 名字」(子会话),汇报兜底换名用 */
|
||||
knownNames?: [string, string][];
|
||||
}) {
|
||||
const active = isRunActive(run.status) && !live.finished;
|
||||
const waiting = run.status === "waiting" || run.status === "running" || run.status === "queued";
|
||||
@@ -460,6 +464,7 @@ export function AgentConversation({
|
||||
const lastKey = live.items.at(-1)?.key;
|
||||
const tail = live.items.at(-1);
|
||||
const blocks = buildConversation(live.items, userMessages);
|
||||
const names = collectNames(live.items, knownNames);
|
||||
const anim = "animate-in fade-in-0 slide-in-from-bottom-1 duration-base ease-pop motion-reduce:animate-none";
|
||||
|
||||
const lastBlock = blocks.at(-1);
|
||||
@@ -501,18 +506,21 @@ export function AgentConversation({
|
||||
) : null}
|
||||
{p.body.map((t) => {
|
||||
const streaming = streamingText && t.key === lastKey;
|
||||
// 旧会话 / 不守汇报格式的模型:UUID、能力 ID、原因码换成名称和人话,原文进技术信息
|
||||
const human = streaming ? null : humanizeReport(t.text, names);
|
||||
return (
|
||||
<div key={t.key} className={cn("w-full min-w-0", freshKeys.has(t.key) && anim)}>
|
||||
<StreamingResponse
|
||||
className="max-w-[72ch]"
|
||||
status={streaming ? "streaming" : "complete"}
|
||||
copyText={t.text}
|
||||
copyText={human?.text ?? t.text}
|
||||
announce={false}
|
||||
showActions={false}
|
||||
>
|
||||
{/* 流式中按原文显示(半截 Markdown 会闪),结束后按安全子集渲染 */}
|
||||
{streaming ? t.text : <Markdown text={t.text} />}
|
||||
{human ? <Markdown text={human.text} /> : t.text}
|
||||
</StreamingResponse>
|
||||
{human?.replaced.length ? <ReplacedIds replaced={human.replaced} /> : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -556,6 +564,32 @@ export function AgentConversation({
|
||||
);
|
||||
}
|
||||
|
||||
/** 汇报里被换掉的原文(ID、能力、原因码),收在技术信息里 */
|
||||
function ReplacedIds({ replaced }: { replaced: { from: string; to: string }[] }) {
|
||||
const uniq = [...new Map(replaced.map((r) => [r.from, r] as const)).values()];
|
||||
return (
|
||||
<TechInfo
|
||||
title="正文原文"
|
||||
className="mt-1"
|
||||
items={[
|
||||
{
|
||||
label: "换掉的标识",
|
||||
value: (
|
||||
<ul className="space-y-0.5">
|
||||
{uniq.map((r) => (
|
||||
<li key={r.from}>
|
||||
{r.from} → {r.to || "(省略)"}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
),
|
||||
wide: true,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// ── 实际结果 ──
|
||||
|
||||
/** 实际结果的一句话(服务端从下载计划 / 下载任务 / 整理记录汇总,不采信模型文本) */
|
||||
@@ -592,10 +626,13 @@ export function ResultLine({
|
||||
run,
|
||||
report,
|
||||
live,
|
||||
subagents = 0,
|
||||
}: {
|
||||
run: AgentRunView;
|
||||
report: GoalReport | null;
|
||||
live: AgentStreamState;
|
||||
/** 实际派出的子会话数(会话树里的直接子会话,不含被拒绝的派发) */
|
||||
subagents?: number;
|
||||
}) {
|
||||
const u = { ...run.usage, ...(live.usage ?? {}) };
|
||||
const durationMs =
|
||||
@@ -623,6 +660,7 @@ export function ResultLine({
|
||||
<p className="flex min-w-0 flex-wrap items-center gap-x-1.5 gap-y-0.5 text-meta text-muted-foreground">
|
||||
{report ? null : <LoaderCircle aria-hidden className="size-3.5 animate-spin motion-reduce:animate-none" />}
|
||||
<span className={cn("text-foreground/85", bad && "text-warning")}>实际结果:{resultText(report)}</span>
|
||||
{subagents ? <span className="tabular-nums">· 派出 {subagents} 个子会话</span> : null}
|
||||
{durationMs ? <span className="tabular-nums">· {durationLabel(durationMs)}</span> : null}
|
||||
{u.costUsd ? <span className="tabular-nums">· 约 {formatUsd(u.costUsd)}</span> : null}
|
||||
</p>
|
||||
@@ -643,7 +681,7 @@ export function ResultLine({
|
||||
items={[
|
||||
{
|
||||
label: "说明",
|
||||
value: "上面的正文是智能体的说法,未经核查;实际结果取自下载任务和整理记录。",
|
||||
value: "上面的正文是智能体的说法,未经核查;实际结果取自下载任务、整理记录和会话树。",
|
||||
wide: true,
|
||||
mono: false,
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user