export type AgentActivityTraceKind = "activity" | "think"; export type AgentActivityTraceStatus = "live" | "done"; export type AgentActivityTraceItem = Readonly<{ id: string; kind: AgentActivityTraceKind; status: AgentActivityTraceStatus; label: string; text?: string; startedAt?: number; tool?: string; }>; const THINKING_TEXT_LIMIT = 8_000; export function emptyActivityTrace(): readonly AgentActivityTraceItem[] { return []; } export function appendActivityTraceThinking( rows: readonly AgentActivityTraceItem[], text: string, ): readonly AgentActivityTraceItem[] { if (!text) return rows; const last = rows.at(-1); if (last?.kind === "think" && last.status === "live") { return rows.map((row, index) => ( index === rows.length - 1 ? { ...row, text: `${row.text ?? ""}${text}`.slice(0, THINKING_TEXT_LIMIT) } : row )); } const frozen = freezeLiveThink(rows); const thinkCount = frozen.filter((row) => row.kind === "think").length; return [ ...frozen, { id: `think-${thinkCount + 1}`, kind: "think", status: "live", label: "思考", text: text.slice(0, THINKING_TEXT_LIMIT), }, ]; } export function startActivityTraceStep( rows: readonly AgentActivityTraceItem[], tool: string, label: string, startedAt = Date.now(), ): readonly AgentActivityTraceItem[] { const frozen = freezeLiveThink(rows); const last = frozen.at(-1); if (last?.kind === "activity" && last.status === "live" && last.tool === tool) { return frozen; } const closed = frozen.map((row) => ( row.kind === "activity" && row.status === "live" ? { ...row, status: "done" as const } : row )); const toolCount = closed.filter((row) => row.kind === "activity" && row.tool === tool).length; return [ ...closed, { id: `activity-${tool}-${toolCount + 1}`, kind: "activity", status: "live", label, startedAt, tool, }, ]; } export function completeActivityTraceStep( rows: readonly AgentActivityTraceItem[], tool: string, label?: string, ): readonly AgentActivityTraceItem[] { for (let index = rows.length - 1; index >= 0; index -= 1) { const row = rows[index]; if (row?.kind === "activity" && row.tool === tool && row.status === "live") { return rows.map((item, current) => ( current === index ? { ...item, status: "done" as const, label: label ?? item.label } : item )); } } return rows; } export function freezeLiveThink( rows: readonly AgentActivityTraceItem[], ): readonly AgentActivityTraceItem[] { return rows.map((row) => ( row.kind === "think" && row.status === "live" ? { ...row, status: "done" as const } : row )); } export function completeActivityTrace( rows: readonly AgentActivityTraceItem[], ): readonly AgentActivityTraceItem[] { return freezeLiveThink(rows).map((row) => ( row.status === "live" ? { ...row, status: "done" as const } : row )); }