Persist active run state for replay

This commit is contained in:
wuyang6
2026-05-14 11:47:37 +08:00
parent e3569b6901
commit 105d287ebd
4 changed files with 423 additions and 19 deletions
@@ -69,6 +69,10 @@ export type ClawRunStatus = {
| "interrupted";
current_stage?: string;
started_at?: number;
updated_at?: number;
finished_at?: number;
elapsed_ms?: number;
cancellable?: boolean;
pending_prompt?: string;
events?: ClawRunEvent[];
};
@@ -590,8 +594,9 @@ function buildActiveRunParts(runStatus: ClawActiveRunStatus) {
: runStatus.current_stage || "后端正在执行这个会话。";
const reasoningText = eventLines.length ? eventLines.join("\n") : fallback;
const runStartedAtMs = resolveRunStartedAtMs(runStatus);
const elapsedMs = normalizeElapsedMs(runStatus.elapsed_ms);
return [
{ type: "reasoning", text: reasoningText, runStartedAtMs },
{ type: "reasoning", text: reasoningText, runStartedAtMs, elapsedMs },
...buildRunToolParts(runStatus.events ?? []),
];
}
@@ -795,6 +800,12 @@ function resolveRunStartedAtMs(runStatus: ClawRunStatus) {
const direct = normalizeRunTimestampMs(runStatus.started_at);
if (direct !== undefined) return direct;
const updatedAt = normalizeRunTimestampMs(runStatus.updated_at);
const elapsedMs = normalizeElapsedMs(runStatus.elapsed_ms);
if (updatedAt !== undefined && elapsedMs !== undefined) {
return Math.max(0, updatedAt - elapsedMs);
}
for (const event of runStatus.events ?? []) {
if (event.type !== "run_started") continue;
const eventStarted = normalizeRunTimestampMs(event.started_at);
@@ -1884,7 +1884,6 @@ const ActivityChainSummary: FC<{
partIndex: number | undefined;
}> = ({ messageId, partIndex }) => {
const { openItem } = useActivityPanel();
const startedAtRef = useRef(Date.now());
const metadataRunStartedAtMs = useAuiState((s) => {
const value = readMetadataValue(s.message.metadata, "runStartedAtMs");
return typeof value === "number" && Number.isFinite(value) ? value : null;
@@ -1933,9 +1932,11 @@ const ActivityChainSummary: FC<{
const startedAt =
metadataRunStartedAtMs ??
contentRunStartedAtMs ??
(storedElapsedMs === null
? startedAtRef.current
: Date.now() - storedElapsedMs);
(storedElapsedMs === null ? null : Date.now() - storedElapsedMs);
if (startedAt === null) {
setElapsedMs(storedElapsedMs);
return;
}
setElapsedMs(Math.max(0, Date.now() - startedAt));
const timer = window.setInterval(() => {
setElapsedMs(Math.max(0, Date.now() - startedAt));
@@ -2021,11 +2022,12 @@ function summarizeActivityChainLabel(
(isGenericActivityLine(lastReasoningLine) ? "" : lastReasoningLine);
if (status === "running") {
const elapsed = `用时 ${formatActivityDuration(elapsedMs ?? 0)}`;
const elapsed =
elapsedMs === null ? "" : `,用时 ${formatActivityDuration(elapsedMs)}`;
if (activeDetail) {
return `${compactActivityLabel(activeDetail, 15)}${elapsed}`;
return `${compactActivityLabel(activeDetail, 15)}${elapsed}`;
}
return `思考中${elapsed}`;
return elapsed ? `思考中${elapsed}` : "思考中";
}
const label = compactActivityLabel(