feat(web): session stats line, live turn status, drop replaced-ID list (AG-4)
- Remove the "换掉的标识" mapping list under humanized reports; the raw
report text is kept only as "原文" in the result line's 技术信息 (no mapping).
- Session stats line above the overview bar, always shown: tool calls, MCP
calls (only when any), tokens used and left to the budget (K/M + percent),
cost; live while running, fixed after the run ends.
- Live turn status: "思考中 / 调用工具中 / 回答中 · 已调用 N 次工具、M 次 MCP";
after the turn the count merges into each progress line ("调用 N 次工具").
- agent.spawn calls answered with an existing same-goal child (reused=true)
are not counted in "派出了 N 个子会话".
Screenshots (desktop + mobile): apps/web/test/screenshots/ag4/ (gitignored).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
793b87e3b6
commit
919dc02200
5 files changed
+263
-39
No files matched your search
@@ -42,7 +42,7 @@ import {
|
||||
import { RunPlan } from "./agent-interaction.tsx";
|
||||
import { shortGoalTitle } from "./agent-store.ts";
|
||||
import { SubagentTree } from "./agent-subagent-tree.tsx";
|
||||
import { stepProgress } from "./conversation-model.ts";
|
||||
import { callCounts, sessionStatsParts, stepProgress } from "./conversation-model.ts";
|
||||
import {
|
||||
NEW_RUN_COMMANDS,
|
||||
PROPOSE_FIRST,
|
||||
@@ -140,6 +140,47 @@ export function GoalComposer({
|
||||
* 顶部概况条:一行「步骤 4/5 · 当前:核对下载任务」;展开看步骤清单、子会话和技术信息(模型、预算、用量、ID)。
|
||||
* 不 sticky、不压在会话上;没有步骤和子会话时只在运行中显示状态。
|
||||
*/
|
||||
/**
|
||||
* 会话统计(AG-4):概况条上方恒定一行小字——工具调用、MCP、已用 token、距上限、费用;
|
||||
* 运行中随事件流实时更新,结束后固定为快照里的最终值。
|
||||
*/
|
||||
export function RunStatsLine({
|
||||
snapshot,
|
||||
live,
|
||||
className,
|
||||
}: {
|
||||
snapshot: RunSnapshot;
|
||||
live: AgentStreamState;
|
||||
className?: string;
|
||||
}) {
|
||||
const r = snapshot.run;
|
||||
const u = { ...r.usage, ...(live.usage ?? {}) };
|
||||
const n = callCounts(live.items.flatMap((i) => (i.kind === "tool" ? [i.call] : [])));
|
||||
const parts = sessionStatsParts(
|
||||
{
|
||||
toolCalls: Math.max(r.toolCallCount - n.mcp, n.tools),
|
||||
mcpCalls: n.mcp,
|
||||
totalTokens: u.totalTokens ?? null,
|
||||
maxTokens: r.budget.maxTokens ?? null,
|
||||
costUsd: u.costUsd ?? null,
|
||||
},
|
||||
{ tokens: formatTokens, usd: formatUsd },
|
||||
);
|
||||
return (
|
||||
<section aria-label="会话统计" className={cn("shrink-0", className)}>
|
||||
{/* 窄屏折行,不截断(费用在最后) */}
|
||||
<p data-slot="run-stats" className="flex flex-wrap gap-x-1.5 px-1 text-meta text-muted-foreground tabular-nums">
|
||||
{parts.map((t, i) => (
|
||||
<span key={t} className="whitespace-nowrap">
|
||||
{i ? "· " : ""}
|
||||
{t}
|
||||
</span>
|
||||
))}
|
||||
</p>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export function RunOverviewBar({
|
||||
snapshot,
|
||||
status,
|
||||
@@ -338,6 +379,7 @@ export function AgentRunPanel({
|
||||
</StatusBadge>
|
||||
</div>
|
||||
) : null}
|
||||
<RunStatsLine snapshot={run.data} live={live} className={column} />
|
||||
<RunOverviewBar
|
||||
snapshot={run.data}
|
||||
status={shownStatus}
|
||||
|
||||
Reference in new issue
Block a user