Persist active run event history
This commit is contained in:
@@ -64,12 +64,25 @@ export type ClawRunStatus = {
|
||||
| "interrupted";
|
||||
current_stage?: string;
|
||||
started_at?: number;
|
||||
events?: ClawRunEvent[];
|
||||
};
|
||||
|
||||
type ClawActiveRunStatus = ClawRunStatus & {
|
||||
status: "queued" | "running";
|
||||
};
|
||||
|
||||
type ClawRunEvent = {
|
||||
type?: string;
|
||||
tool_name?: string;
|
||||
tool_call_id?: string;
|
||||
arguments?: unknown;
|
||||
assistant_content?: string;
|
||||
ok?: boolean;
|
||||
metadata?: {
|
||||
output_preview?: unknown;
|
||||
};
|
||||
};
|
||||
|
||||
type ClawStoredToolCall = {
|
||||
id?: string;
|
||||
name?: string;
|
||||
@@ -471,11 +484,7 @@ export function toReplayRepository(
|
||||
}
|
||||
if (isActiveRunStatus(runStatus)) {
|
||||
const id = `${fallbackSessionId}-run-${runStatus.run_id ?? "active"}`;
|
||||
const text =
|
||||
runStatus.status === "queued"
|
||||
? "当前会话已有任务在执行,本轮正在排队。"
|
||||
: runStatus.current_stage || "后端正在执行这个会话。";
|
||||
const parts = [{ type: "reasoning", text }] as UIMessage["parts"];
|
||||
const parts = buildActiveRunParts(runStatus) as UIMessage["parts"];
|
||||
const uiMessage: UIMessage = {
|
||||
id,
|
||||
role: "assistant",
|
||||
@@ -520,6 +529,92 @@ function isActiveRunStatus(
|
||||
return runStatus?.status === "queued" || runStatus?.status === "running";
|
||||
}
|
||||
|
||||
function buildActiveRunParts(runStatus: ClawActiveRunStatus) {
|
||||
const eventLines = summarizeRunEvents(runStatus);
|
||||
const fallback =
|
||||
runStatus.status === "queued"
|
||||
? "当前会话已有任务在执行,本轮正在排队。"
|
||||
: runStatus.current_stage || "后端正在执行这个会话。";
|
||||
const reasoningText = eventLines.length ? eventLines.join("\n") : fallback;
|
||||
return [
|
||||
{ type: "reasoning", text: reasoningText },
|
||||
...buildRunToolParts(runStatus.events ?? []),
|
||||
];
|
||||
}
|
||||
|
||||
function summarizeRunEvents(runStatus: ClawActiveRunStatus) {
|
||||
const lines: string[] = [];
|
||||
for (const event of runStatus.events ?? []) {
|
||||
if (event.type === "run_queued") {
|
||||
lines.push("当前会话已有任务在执行,本轮正在排队。");
|
||||
}
|
||||
if (event.type === "run_started") {
|
||||
lines.push("后端已开始执行本轮任务。");
|
||||
}
|
||||
if (event.type === "tool_start") {
|
||||
lines.push(
|
||||
event.tool_name ? `调用工具 ${event.tool_name}` : "正在调用工具",
|
||||
);
|
||||
}
|
||||
if (event.type === "tool_result") {
|
||||
lines.push(
|
||||
event.tool_name ? `工具完成 ${event.tool_name}` : "工具调用完成",
|
||||
);
|
||||
}
|
||||
if (event.type === "final_text_start") {
|
||||
lines.push("正在整理回复");
|
||||
}
|
||||
if (event.type === "user_review_required") {
|
||||
lines.push("等待用户 review");
|
||||
}
|
||||
}
|
||||
if (runStatus.current_stage && lines.at(-1) !== runStatus.current_stage) {
|
||||
lines.push(runStatus.current_stage);
|
||||
}
|
||||
return lines.slice(-40);
|
||||
}
|
||||
|
||||
function buildRunToolParts(events: readonly ClawRunEvent[]) {
|
||||
const resultById = new Map<string, ClawRunEvent>();
|
||||
for (const event of events) {
|
||||
if (event.type === "tool_result" && event.tool_call_id) {
|
||||
resultById.set(event.tool_call_id, event);
|
||||
}
|
||||
}
|
||||
const seen = new Set<string>();
|
||||
return events.flatMap((event) => {
|
||||
if (
|
||||
event.type !== "tool_start" ||
|
||||
!event.tool_call_id ||
|
||||
!event.tool_name ||
|
||||
seen.has(event.tool_call_id)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
seen.add(event.tool_call_id);
|
||||
const result = resultById.get(event.tool_call_id);
|
||||
const outputPreview = result?.metadata?.output_preview;
|
||||
const output =
|
||||
typeof outputPreview === "string"
|
||||
? outputPreview
|
||||
: result
|
||||
? result.ok === false
|
||||
? "工具执行失败,等待最终结果汇总。"
|
||||
: "工具调用完成,等待最终结果汇总。"
|
||||
: undefined;
|
||||
return [
|
||||
{
|
||||
type: "dynamic-tool",
|
||||
toolName: event.tool_name,
|
||||
toolCallId: event.tool_call_id,
|
||||
state: output === undefined ? "input-available" : "output-available",
|
||||
input: attachStageNote(event.arguments ?? {}, event.assistant_content),
|
||||
...(output === undefined ? {} : { output }),
|
||||
},
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
function getReplayMessages(
|
||||
messages: readonly ClawStoredMessage[],
|
||||
runStatus?: ClawRunStatus | null,
|
||||
|
||||
Reference in New Issue
Block a user