import { ApprovalRequestId, isToolLifecycleItemType } from "@t3tools/contracts";import type { OrchestrationLatestTurn, OrchestrationThread, OrchestrationThreadActivity, ToolLifecycleItemType, TurnId, UserInputQuestion,} from "@t3tools/contracts";import { formatDuration } from "@t3tools/shared/orchestrationTiming"; import * as Arr from "effect/Array";import * as Order from "effect/Order"; export interface PendingApproval { readonly requestId: ApprovalRequestId; readonly requestKind: "command" | "file-read" | "file-change"; readonly createdAt: string; readonly detail?: string;} export interface PendingUserInput { readonly requestId: ApprovalRequestId; readonly createdAt: string; readonly questions: ReadonlyArray<UserInputQuestion>;} export interface PendingUserInputDraftAnswer { readonly selectedOptionLabel?: string; readonly customAnswer?: string;} export interface ThreadFeedActivity { readonly id: string; readonly createdAt: string; readonly turnId: TurnId | null; readonly summary: string; readonly detail: string | null; readonly fullDetail: string | null; readonly copyText: string; readonly icon: | "agent" | "alert" | "check" | "command" | "edit" | "eye" | "globe" | "hammer" | "message" | "warning" | "wrench" | "zap"; readonly toolLike: boolean; readonly status: "success" | "failure" | "neutral" | null;} const MAX_VISIBLE_WORK_LOG_ENTRIES = 1; type WorkLogToolLifecycleStatus = "inProgress" | "completed" | "failed" | "declined" | "stopped"; interface WorkLogEntry { id: string; createdAt: string; turnId: TurnId | null; label: string; detail?: string; command?: string; rawCommand?: string; changedFiles?: ReadonlyArray<string>; tone: "thinking" | "tool" | "info" | "error"; toolTitle?: string; itemType?: ToolLifecycleItemType; requestKind?: PendingApproval["requestKind"]; toolLifecycleStatus?: WorkLogToolLifecycleStatus; toolData?: unknown;} interface DerivedWorkLogEntry extends WorkLogEntry { activityKind: OrchestrationThreadActivity["kind"]; collapseKey?: string;} type RawThreadFeedEntry = | { readonly type: "message"; readonly id: string; readonly createdAt: string; readonly message: OrchestrationThread["messages"][number]; } | { readonly type: "activity"; readonly id: string; readonly createdAt: string; readonly turnId: TurnId | null; readonly activity: ThreadFeedActivity; }; export type ThreadFeedEntry = | Extract<RawThreadFeedEntry, { type: "message" }> | { readonly type: "working"; readonly id: string; readonly createdAt: string; } | { readonly type: "activity-group"; readonly id: string; readonly createdAt: string; readonly turnId: TurnId | null; readonly activities: ReadonlyArray<ThreadFeedActivity>; } | { readonly type: "work-toggle"; readonly id: string; readonly createdAt: string; readonly turnId: TurnId | null; readonly groupId: string; readonly hiddenCount: number; readonly expanded: boolean; readonly onlyToolActivities: boolean; } | { readonly type: "turn-fold"; readonly id: string; readonly createdAt: string; readonly turnId: TurnId; readonly label: string; readonly expanded: boolean; }; export type ThreadFeedLatestTurn = Pick< OrchestrationLatestTurn, "turnId" | "state" | "startedAt" | "completedAt">; function requestKindFromRequestType(requestType: unknown): PendingApproval["requestKind"] | null { switch (requestType) { case "command_execution_approval": case "exec_command_approval": return "command"; case "file_read_approval": return "file-read"; case "file_change_approval": case "apply_patch_approval": return "file-change"; default: return null; }} function isStalePendingRequestFailureDetail(detail: string | undefined): boolean { const normalized = detail?.toLowerCase(); if (!normalized) { return false; } return ( normalized.includes("stale pending approval request") || normalized.includes("stale pending user-input request") || normalized.includes("unknown pending approval request") || normalized.includes("unknown pending permission request") || normalized.includes("unknown pending user-input request") );} function parseApprovalRequestId(value: unknown): ApprovalRequestId | null { return typeof value === "string" && value.length > 0 ? ApprovalRequestId.make(value) : null;} function parseUserInputQuestions( payload: Record<string, unknown> | null,): ReadonlyArray<UserInputQuestion> | null { const questions = payload?.questions; if (!Array.isArray(questions)) { return null; } const parsed = questions .map<UserInputQuestion | null>((entry) => { if (!entry || typeof entry !== "object") return null; const question = entry as Record<string, unknown>; if ( typeof question.id !== "string" || typeof question.header !== "string" || typeof question.question !== "string" || !Array.isArray(question.options) ) { return null; } const options = question.options .map<UserInputQuestion["options"][number] | null>((option) => { if (!option || typeof option !== "object") return null; const record = option as Record<string, unknown>; if (typeof record.label !== "string" || typeof record.description !== "string") { return null; } return { label: record.label, description: record.description, }; }) .filter((option): option is UserInputQuestion["options"][number] => option !== null); if (options.length === 0) { return null; } return { id: question.id, header: question.header, question: question.question, options, multiSelect: question.multiSelect === true, }; }) .filter((question): question is UserInputQuestion => question !== null); return parsed.length > 0 ? parsed : null;} function normalizeDraftAnswer(value: string | undefined): string | null { if (typeof value !== "string") { return null; } const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : null;} function resolvePendingUserInputAnswer( draft: PendingUserInputDraftAnswer | undefined,): string | null { const customAnswer = normalizeDraftAnswer(draft?.customAnswer); if (customAnswer) { return customAnswer; } return normalizeDraftAnswer(draft?.selectedOptionLabel);} function deriveWorkLogEntries( activities: ReadonlyArray<OrchestrationThreadActivity>,): DerivedWorkLogEntry[] { const ordered = Arr.sort(activities, activityOrder); const entries: DerivedWorkLogEntry[] = []; for (const activity of ordered) { if (activity.kind === "tool.started") continue; if (activity.kind === "task.started") continue; if (activity.kind === "context-window.updated") continue; if (activity.summary === "Checkpoint captured") continue; if (isPlanBoundaryToolActivity(activity)) continue; entries.push(toDerivedWorkLogEntry(activity)); } return collapseDerivedWorkLogEntries(entries);} function isPlanBoundaryToolActivity(activity: OrchestrationThreadActivity): boolean { if (activity.kind !== "tool.updated" && activity.kind !== "tool.completed") { return false; } const payload = activity.payload && typeof activity.payload === "object" ? (activity.payload as Record<string, unknown>) : null; return typeof payload?.detail === "string" && payload.detail.startsWith("ExitPlanMode:");} function toDerivedWorkLogEntry(activity: OrchestrationThreadActivity): DerivedWorkLogEntry { const payload = activity.payload && typeof activity.payload === "object" ? (activity.payload as Record<string, unknown>) : null; const commandPreview = extractToolCommand(payload); const changedFiles = extractChangedFiles(payload); const title = extractToolTitle(payload); const isTaskActivity = activity.kind === "task.progress" || activity.kind === "task.completed"; const taskSummary = isTaskActivity && typeof payload?.summary === "string" && payload.summary.length > 0 ? payload.summary : null; const taskDetailAsLabel = isTaskActivity && !taskSummary && typeof payload?.detail === "string" && payload.detail.length > 0 ? payload.detail : null; const taskLabel = taskSummary || taskDetailAsLabel; const entry: DerivedWorkLogEntry = { id: activity.id, createdAt: activity.createdAt, turnId: activity.turnId, label: taskLabel || activity.summary, tone: activity.kind === "task.progress" ? "thinking" : activity.tone === "approval" ? "info" : activity.tone, activityKind: activity.kind, }; const itemType = extractWorkLogItemType(payload); const requestKind = extractWorkLogRequestKind(payload); if ( !taskDetailAsLabel && payload && typeof payload.detail === "string" && payload.detail.length > 0 ) { const detail = stripTrailingExitCode(payload.detail).output; if (detail) { entry.detail = detail; } } if (commandPreview.command) { entry.command = commandPreview.command; } if (commandPreview.rawCommand) { entry.rawCommand = commandPreview.rawCommand; } if (changedFiles.length > 0) { entry.changedFiles = changedFiles; } if (title) { entry.toolTitle = title; } if (itemType === "mcp_tool_call") { const data = asRecord(payload?.data); if (data?.item !== undefined) { entry.toolData = data.item; } } if (itemType) { entry.itemType = itemType; } if (requestKind) { entry.requestKind = requestKind; } let toolLifecycleStatus = extractWorkLogToolLifecycleStatus(payload); if (!toolLifecycleStatus && activity.kind === "tool.completed") { toolLifecycleStatus = "completed"; } if (toolLifecycleStatus) { entry.toolLifecycleStatus = toolLifecycleStatus; } const collapseKey = deriveToolLifecycleCollapseKey(entry); if (collapseKey) { entry.collapseKey = collapseKey; } return entry;} function collapseDerivedWorkLogEntries( entries: ReadonlyArray<DerivedWorkLogEntry>,): DerivedWorkLogEntry[] { const collapsed: DerivedWorkLogEntry[] = []; for (const entry of entries) { const previous = collapsed.at(-1); if (previous && shouldCollapseToolLifecycleEntries(previous, entry)) { collapsed[collapsed.length - 1] = mergeDerivedWorkLogEntries(previous, entry); continue; } collapsed.push(entry); } return collapsed;} function shouldCollapseToolLifecycleEntries( previous: DerivedWorkLogEntry, next: DerivedWorkLogEntry,): boolean { if (previous.activityKind !== "tool.updated" && previous.activityKind !== "tool.completed") { return false; } if (next.activityKind !== "tool.updated" && next.activityKind !== "tool.completed") { return false; } if (previous.activityKind === "tool.completed") { return false; } return previous.collapseKey !== undefined && previous.collapseKey === next.collapseKey;} function mergeDerivedWorkLogEntries( previous: DerivedWorkLogEntry, next: DerivedWorkLogEntry,): DerivedWorkLogEntry { const changedFiles = mergeChangedFiles(previous.changedFiles, next.changedFiles); const detail = next.detail ?? previous.detail; const command = next.command ?? previous.command; const rawCommand = next.rawCommand ?? previous.rawCommand; const toolTitle = next.toolTitle ?? previous.toolTitle; const itemType = next.itemType ?? previous.itemType; const requestKind = next.requestKind ?? previous.requestKind; const collapseKey = next.collapseKey ?? previous.collapseKey; const toolLifecycleStatus = next.toolLifecycleStatus ?? previous.toolLifecycleStatus; const toolData = next.toolData ?? previous.toolData; return { ...previous, ...next, ...(detail ? { detail } : {}), ...(command ? { command } : {}), ...(rawCommand ? { rawCommand } : {}), ...(changedFiles.length > 0 ? { changedFiles } : {}), ...(toolTitle ? { toolTitle } : {}), ...(itemType ? { itemType } : {}), ...(requestKind ? { requestKind } : {}), ...(collapseKey ? { collapseKey } : {}), ...(toolLifecycleStatus ? { toolLifecycleStatus } : {}), ...(toolData !== undefined ? { toolData } : {}), };} function mergeChangedFiles( previous: ReadonlyArray<string> | undefined, next: ReadonlyArray<string> | undefined,): string[] { const merged = [...(previous ?? []), ...(next ?? [])]; if (merged.length === 0) { return []; } return [...new Set(merged)];} function deriveToolLifecycleCollapseKey(entry: DerivedWorkLogEntry): string | undefined { if (entry.activityKind !== "tool.updated" && entry.activityKind !== "tool.completed") { return undefined; } const normalizedLabel = normalizeCompactToolLabel(entry.toolTitle ?? entry.label); const detail = entry.detail?.trim() ?? ""; const itemType = entry.itemType ?? ""; if (normalizedLabel.length === 0 && detail.length === 0 && itemType.length === 0) { return undefined; } return [itemType, normalizedLabel, detail].join("\u001f");} function normalizeCompactToolLabel(value: string): string { return value.replace(/\s+(?:complete|completed)\s*$/i, "").trim();} function workLogEntryIsToolLike(entry: WorkLogEntry): boolean { if (entry.tone === "tool" || entry.tone === "thinking" || entry.tone === "error") { return true; } if (entry.command !== undefined && entry.command.trim().length > 0) { return true; } if (entry.requestKind !== undefined) { return true; } return entry.itemType !== undefined && isToolLifecycleItemType(entry.itemType);} function toolDetailTextLooksLikeFailure(text: string): boolean { const normalized = text.toLowerCase(); return ( normalized.includes("file not found") || normalized.includes("no files found") || normalized.includes("enoent") || normalized.includes("no such file or directory") || normalized.includes("no such file") || normalized.includes("commandnotfoundexception") || normalized.includes("command not found") || (normalized.includes("cannot find path") && normalized.includes("because it does not exist")) || (normalized.includes("is not recognized") && normalized.includes("the term '")) || /<exited with exit code\s+[1-9]\d*\s*>/i.test(text) || /exit(?:ed)? with exit code\s+[1-9]\d*/i.test(text) || /exit code\s*[:\s]\s*[1-9]\d*\b/i.test(text) );} function workEntryIndicatesToolFailure(entry: WorkLogEntry): boolean { if (entry.tone === "error") { return true; } if (entry.toolLifecycleStatus === "failed" || entry.toolLifecycleStatus === "declined") { return true; } if (!workLogEntryIsToolLike(entry)) { return false; } return toolDetailTextLooksLikeFailure([entry.detail, entry.command].filter(Boolean).join("\n"));} function workEntryIndicatesToolSuccess(entry: WorkLogEntry): boolean { if (!workLogEntryIsToolLike(entry) || workEntryIndicatesToolFailure(entry)) { return false; } if (entry.tone === "thinking") { return false; } return ( entry.toolLifecycleStatus !== "inProgress" && entry.toolLifecycleStatus !== "stopped" && entry.toolLifecycleStatus !== "failed" && entry.toolLifecycleStatus !== "declined" );} function workEntryStatus(entry: WorkLogEntry): ThreadFeedActivity["status"] { if (!workLogEntryIsToolLike(entry)) { return null;Lines 1–500 of 1386. Load more
import { ApprovalRequestId, isToolLifecycleItemType } from "@t3tools/contracts"; import type { OrchestrationLatestTurn, OrchestrationThread, OrchestrationThreadActivity, ToolLifecycleItemType, TurnId, UserInputQuestion, } from "@t3tools/contracts"; import { formatDuration } from "@t3tools/shared/orchestrationTiming"; import * as Arr from "effect/Array"; import * as Order from "effect/Order"; export interface PendingApproval { readonly requestId: ApprovalRequestId; readonly requestKind: "command" | "file-read" | "file-change"; readonly createdAt: string; readonly detail?: string; } export interface PendingUserInput { readonly requestId: ApprovalRequestId; readonly createdAt: string; readonly questions: ReadonlyArray<UserInputQuestion>; } export interface PendingUserInputDraftAnswer { readonly selectedOptionLabel?: string; readonly customAnswer?: string; } export interface ThreadFeedActivity { readonly id: string; readonly createdAt: string; readonly turnId: TurnId | null; readonly summary: string; readonly detail: string | null; readonly fullDetail: string | null; readonly copyText: string; readonly icon: | "agent" | "alert" | "check" | "command" | "edit" | "eye" | "globe" | "hammer" | "message" | "warning" | "wrench" | "zap"; readonly toolLike: boolean; readonly status: "success" | "failure" | "neutral" | null; } const MAX_VISIBLE_WORK_LOG_ENTRIES = 1; type WorkLogToolLifecycleStatus = "inProgress" | "completed" | "failed" | "declined" | "stopped"; interface WorkLogEntry { id: string; createdAt: string; turnId: TurnId | null; label: string; detail?: string; command?: string; rawCommand?: string; changedFiles?: ReadonlyArray<string>; tone: "thinking" | "tool" | "info" | "error"; toolTitle?: string; itemType?: ToolLifecycleItemType; requestKind?: PendingApproval["requestKind"]; toolLifecycleStatus?: WorkLogToolLifecycleStatus; toolData?: unknown; } interface DerivedWorkLogEntry extends WorkLogEntry { activityKind: OrchestrationThreadActivity["kind"]; collapseKey?: string; } type RawThreadFeedEntry = | { readonly type: "message"; readonly id: string; readonly createdAt: string; readonly message: OrchestrationThread["messages"][number]; } | { readonly type: "activity"; readonly id: string; readonly createdAt: string; readonly turnId: TurnId | null; readonly activity: ThreadFeedActivity; }; export type ThreadFeedEntry = | Extract<RawThreadFeedEntry, { type: "message" }> | { readonly type: "working"; readonly id: string; readonly createdAt: string; } | { readonly type: "activity-group"; readonly id: string; readonly createdAt: string; readonly turnId: TurnId | null; readonly activities: ReadonlyArray<ThreadFeedActivity>; } | { readonly type: "work-toggle"; readonly id: string; readonly createdAt: string; readonly turnId: TurnId | null; readonly groupId: string; readonly hiddenCount: number; readonly expanded: boolean; readonly onlyToolActivities: boolean; } | { readonly type: "turn-fold"; readonly id: string; readonly createdAt: string; readonly turnId: TurnId; readonly label: string; readonly expanded: boolean; }; export type ThreadFeedLatestTurn = Pick< OrchestrationLatestTurn, "turnId" | "state" | "startedAt" | "completedAt" >; function requestKindFromRequestType(requestType: unknown): PendingApproval["requestKind"] | null { switch (requestType) { case "command_execution_approval": case "exec_command_approval": return "command"; case "file_read_approval": return "file-read"; case "file_change_approval": case "apply_patch_approval": return "file-change"; default: return null; } } function isStalePendingRequestFailureDetail(detail: string | undefined): boolean { const normalized = detail?.toLowerCase(); if (!normalized) { return false; } return ( normalized.includes("stale pending approval request") || normalized.includes("stale pending user-input request") || normalized.includes("unknown pending approval request") || normalized.includes("unknown pending permission request") || normalized.includes("unknown pending user-input request") ); } function parseApprovalRequestId(value: unknown): ApprovalRequestId | null { return typeof value === "string" && value.length > 0 ? ApprovalRequestId.make(value) : null; } function parseUserInputQuestions( payload: Record<string, unknown> | null, ): ReadonlyArray<UserInputQuestion> | null { const questions = payload?.questions; if (!Array.isArray(questions)) { return null; } const parsed = questions .map<UserInputQuestion | null>((entry) => { if (!entry || typeof entry !== "object") return null; const question = entry as Record<string, unknown>; if ( typeof question.id !== "string" || typeof question.header !== "string" || typeof question.question !== "string" || !Array.isArray(question.options) ) { return null; } const options = question.options .map<UserInputQuestion["options"][number] | null>((option) => { if (!option || typeof option !== "object") return null; const record = option as Record<string, unknown>; if (typeof record.label !== "string" || typeof record.description !== "string") { return null; } return { label: record.label, description: record.description, }; }) .filter((option): option is UserInputQuestion["options"][number] => option !== null); if (options.length === 0) { return null; } return { id: question.id, header: question.header, question: question.question, options, multiSelect: question.multiSelect === true, }; }) .filter((question): question is UserInputQuestion => question !== null); return parsed.length > 0 ? parsed : null; } function normalizeDraftAnswer(value: string | undefined): string | null { if (typeof value !== "string") { return null; } const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : null; } function resolvePendingUserInputAnswer( draft: PendingUserInputDraftAnswer | undefined, ): string | null { const customAnswer = normalizeDraftAnswer(draft?.customAnswer); if (customAnswer) { return customAnswer; } return normalizeDraftAnswer(draft?.selectedOptionLabel); } function deriveWorkLogEntries( activities: ReadonlyArray<OrchestrationThreadActivity>, ): DerivedWorkLogEntry[] { const ordered = Arr.sort(activities, activityOrder); const entries: DerivedWorkLogEntry[] = []; for (const activity of ordered) { if (activity.kind === "tool.started") continue; if (activity.kind === "task.started") continue; if (activity.kind === "context-window.updated") continue; if (activity.summary === "Checkpoint captured") continue; if (isPlanBoundaryToolActivity(activity)) continue; entries.push(toDerivedWorkLogEntry(activity)); } return collapseDerivedWorkLogEntries(entries); } function isPlanBoundaryToolActivity(activity: OrchestrationThreadActivity): boolean { if (activity.kind !== "tool.updated" && activity.kind !== "tool.completed") { return false; } const payload = activity.payload && typeof activity.payload === "object" ? (activity.payload as Record<string, unknown>) : null; return typeof payload?.detail === "string" && payload.detail.startsWith("ExitPlanMode:"); } function toDerivedWorkLogEntry(activity: OrchestrationThreadActivity): DerivedWorkLogEntry { const payload = activity.payload && typeof activity.payload === "object" ? (activity.payload as Record<string, unknown>) : null; const commandPreview = extractToolCommand(payload); const changedFiles = extractChangedFiles(payload); const title = extractToolTitle(payload); const isTaskActivity = activity.kind === "task.progress" || activity.kind === "task.completed"; const taskSummary = isTaskActivity && typeof payload?.summary === "string" && payload.summary.length > 0 ? payload.summary : null; const taskDetailAsLabel = isTaskActivity && !taskSummary && typeof payload?.detail === "string" && payload.detail.length > 0 ? payload.detail : null; const taskLabel = taskSummary || taskDetailAsLabel; const entry: DerivedWorkLogEntry = { id: activity.id, createdAt: activity.createdAt, turnId: activity.turnId, label: taskLabel || activity.summary, tone: activity.kind === "task.progress" ? "thinking" : activity.tone === "approval" ? "info" : activity.tone, activityKind: activity.kind, }; const itemType = extractWorkLogItemType(payload); const requestKind = extractWorkLogRequestKind(payload); if ( !taskDetailAsLabel && payload && typeof payload.detail === "string" && payload.detail.length > 0 ) { const detail = stripTrailingExitCode(payload.detail).output; if (detail) { entry.detail = detail; } } if (commandPreview.command) { entry.command = commandPreview.command; } if (commandPreview.rawCommand) { entry.rawCommand = commandPreview.rawCommand; } if (changedFiles.length > 0) { entry.changedFiles = changedFiles; } if (title) { entry.toolTitle = title; } if (itemType === "mcp_tool_call") { const data = asRecord(payload?.data); if (data?.item !== undefined) { entry.toolData = data.item; } } if (itemType) { entry.itemType = itemType; } if (requestKind) { entry.requestKind = requestKind; } let toolLifecycleStatus = extractWorkLogToolLifecycleStatus(payload); if (!toolLifecycleStatus && activity.kind === "tool.completed") { toolLifecycleStatus = "completed"; } if (toolLifecycleStatus) { entry.toolLifecycleStatus = toolLifecycleStatus; } const collapseKey = deriveToolLifecycleCollapseKey(entry); if (collapseKey) { entry.collapseKey = collapseKey; } return entry; } function collapseDerivedWorkLogEntries( entries: ReadonlyArray<DerivedWorkLogEntry>, ): DerivedWorkLogEntry[] { const collapsed: DerivedWorkLogEntry[] = []; for (const entry of entries) { const previous = collapsed.at(-1); if (previous && shouldCollapseToolLifecycleEntries(previous, entry)) { collapsed[collapsed.length - 1] = mergeDerivedWorkLogEntries(previous, entry); continue; } collapsed.push(entry); } return collapsed; } function shouldCollapseToolLifecycleEntries( previous: DerivedWorkLogEntry, next: DerivedWorkLogEntry, ): boolean { if (previous.activityKind !== "tool.updated" && previous.activityKind !== "tool.completed") { return false; } if (next.activityKind !== "tool.updated" && next.activityKind !== "tool.completed") { return false; } if (previous.activityKind === "tool.completed") { return false; } return previous.collapseKey !== undefined && previous.collapseKey === next.collapseKey; } function mergeDerivedWorkLogEntries( previous: DerivedWorkLogEntry, next: DerivedWorkLogEntry, ): DerivedWorkLogEntry { const changedFiles = mergeChangedFiles(previous.changedFiles, next.changedFiles); const detail = next.detail ?? previous.detail; const command = next.command ?? previous.command; const rawCommand = next.rawCommand ?? previous.rawCommand; const toolTitle = next.toolTitle ?? previous.toolTitle; const itemType = next.itemType ?? previous.itemType; const requestKind = next.requestKind ?? previous.requestKind; const collapseKey = next.collapseKey ?? previous.collapseKey; const toolLifecycleStatus = next.toolLifecycleStatus ?? previous.toolLifecycleStatus; const toolData = next.toolData ?? previous.toolData; return { ...previous, ...next, ...(detail ? { detail } : {}), ...(command ? { command } : {}), ...(rawCommand ? { rawCommand } : {}), ...(changedFiles.length > 0 ? { changedFiles } : {}), ...(toolTitle ? { toolTitle } : {}), ...(itemType ? { itemType } : {}), ...(requestKind ? { requestKind } : {}), ...(collapseKey ? { collapseKey } : {}), ...(toolLifecycleStatus ? { toolLifecycleStatus } : {}), ...(toolData !== undefined ? { toolData } : {}), }; } function mergeChangedFiles( previous: ReadonlyArray<string> | undefined, next: ReadonlyArray<string> | undefined, ): string[] { const merged = [...(previous ?? []), ...(next ?? [])]; if (merged.length === 0) { return []; } return [...new Set(merged)]; } function deriveToolLifecycleCollapseKey(entry: DerivedWorkLogEntry): string | undefined { if (entry.activityKind !== "tool.updated" && entry.activityKind !== "tool.completed") { return undefined; } const normalizedLabel = normalizeCompactToolLabel(entry.toolTitle ?? entry.label); const detail = entry.detail?.trim() ?? ""; const itemType = entry.itemType ?? ""; if (normalizedLabel.length === 0 && detail.length === 0 && itemType.length === 0) { return undefined; } return [itemType, normalizedLabel, detail].join("\u001f"); } function normalizeCompactToolLabel(value: string): string { return value.replace(/\s+(?:complete|completed)\s*$/i, "").trim(); } function workLogEntryIsToolLike(entry: WorkLogEntry): boolean { if (entry.tone === "tool" || entry.tone === "thinking" || entry.tone === "error") { return true; } if (entry.command !== undefined && entry.command.trim().length > 0) { return true; } if (entry.requestKind !== undefined) { return true; } return entry.itemType !== undefined && isToolLifecycleItemType(entry.itemType); } function toolDetailTextLooksLikeFailure(text: string): boolean { const normalized = text.toLowerCase(); return ( normalized.includes("file not found") || normalized.includes("no files found") || normalized.includes("enoent") || normalized.includes("no such file or directory") || normalized.includes("no such file") || normalized.includes("commandnotfoundexception") || normalized.includes("command not found") || (normalized.includes("cannot find path") && normalized.includes("because it does not exist")) || (normalized.includes("is not recognized") && normalized.includes("the term '")) || /<exited with exit code\s+[1-9]\d*\s*>/i.test(text) || /exit(?:ed)? with exit code\s+[1-9]\d*/i.test(text) || /exit code\s*[:\s]\s*[1-9]\d*\b/i.test(text) ); } function workEntryIndicatesToolFailure(entry: WorkLogEntry): boolean { if (entry.tone === "error") { return true; } if (entry.toolLifecycleStatus === "failed" || entry.toolLifecycleStatus === "declined") { return true; } if (!workLogEntryIsToolLike(entry)) { return false; } return toolDetailTextLooksLikeFailure([entry.detail, entry.command].filter(Boolean).join("\n")); } function workEntryIndicatesToolSuccess(entry: WorkLogEntry): boolean { if (!workLogEntryIsToolLike(entry) || workEntryIndicatesToolFailure(entry)) { return false; } if (entry.tone === "thinking") { return false; } return ( entry.toolLifecycleStatus !== "inProgress" && entry.toolLifecycleStatus !== "stopped" && entry.toolLifecycleStatus !== "failed" && entry.toolLifecycleStatus !== "declined" ); } function workEntryStatus(entry: WorkLogEntry): ThreadFeedActivity["status"] { if (!workLogEntryIsToolLike(entry)) { return null;