import { requestKindFromRequestType, type PendingApproval,} from "@t3tools/client-runtime/pending-requests";import { UserInputAttachmentAnswerPayload } from "@t3tools/contracts";import { foldUserInputActivities } from "@t3tools/client-runtime/work-log/user-input";import * as Option from "effect/Option";import * as Schema from "effect/Schema";import * as Arr from "effect/Array";import { shallow } from "zustand/vanilla/shallow";import { isBackgroundTaskActivity } from "@t3tools/client-runtime/state/subagentRuntime";import { commandDetailRepeatsCommand, extractCommandOutputText, extractWorkLogToolLifecycleStatus, isWorktreeSetupActivity, workEntryIndicatesToolFailure, workEntryIndicatesToolSuccess, workLogEntryIsToolLike, type WorkLogToolLifecycleStatus,} from "@t3tools/client-runtime/work-log/presentation";import { extractToolActivityPresentation } from "@t3tools/client-runtime/work-log/tool-presentation";import { isToolLifecycleItemType, type AssetResource, type OrchestrationLatestTurn, type OrchestrationThreadActivity, type OrchestrationProposedPlanId, type ToolLifecycleItemType, type ThreadId, type TurnId,} from "@t3tools/contracts"; import { isImageAttachment, type ChatAttachment, type ChatMessage, type ProposedPlan, type SessionPhase, type Thread, type ThreadSession, type TurnDiffSummary,} from "./types"; export type { PendingApproval, PendingUserInput } from "@t3tools/client-runtime/pending-requests"; export { formatDuration } from "@t3tools/shared/orchestrationTiming"; export { workEntryDisplayIndicatesToolFailure, workEntryIndicatesToolSuccess, workLogEntryIsToolLike, type WorkLogToolLifecycleStatus,} from "@t3tools/client-runtime/work-log/presentation"; export interface WorkLogEntry { questionAnswer?: UserInputAttachmentAnswerPayload; id: string; createdAt: string; turnId?: TurnId | null; /** Stable provider identity across in-progress and completed lifecycle updates. */ toolCallId?: string; label: string; detail?: string; viewedImagePath?: string; command?: string; rawCommand?: string; changedFiles?: ReadonlyArray<string>; tone: "thinking" | "tool" | "info" | "error"; toolTitle?: string; toolSurface?: import("@t3tools/contracts").ToolActivitySurface; toolIcon?: import("@t3tools/contracts").ToolActivityIcon; toolSource?: import("@t3tools/contracts").ToolActivitySource; toolData?: unknown; itemType?: ToolLifecycleItemType; requestKind?: PendingApproval["requestKind"]; /** From runtime item / task payload `status` when present (e.g. tool.updated). */ toolLifecycleStatus?: WorkLogToolLifecycleStatus; /** Originating orchestration activity kind (e.g. `user-input.requested`) for row chrome. */ sourceActivityKind?: OrchestrationThreadActivity["kind"]; /** Grouping key for subagent lifecycle rows (one row per agent). */ taskId?: string; /** Agent role (subagent_type) for labeled timeline rows. */ agentRole?: string; /** * Present on agent-spawn CTA rows: one per workflow run or per-turn batch * of direct spawns. The row renders as a call-to-action ("Kicked off N * subagents") whose live status is derived from the agent panel model at * render time; clicking opens the Agents panel. */ agentSpawn?: { /** Workflow coordinator taskId, or null for a direct-spawn batch. */ workflowId: string | null; agentTaskIds: ReadonlyArray<string>; };} const workLogCollapseKey = Symbol(); interface DerivedWorkLogEntry extends WorkLogEntry { sourceActivityKind: OrchestrationThreadActivity["kind"]; [workLogCollapseKey]?: string; toolCallId?: string; isWorkflowCoordinator?: boolean; /** Shell/monitor/plan tasks: ordinary work-log rows, never spawn CTAs. */ isBackgroundTask?: boolean;} const derivedWorkLogEntryByActivity = new WeakMap< OrchestrationThreadActivity, DerivedWorkLogEntry>(); export interface ActivePlanState { createdAt: string; turnId: TurnId | null; explanation?: string | null; steps: Array<{ durationMs?: number; step: string; status: "pending" | "inProgress" | "completed"; }>;} export interface LatestProposedPlanState { id: OrchestrationProposedPlanId; createdAt: string; updatedAt: string; turnId: TurnId | null; planMarkdown: string; implementedAt: string | null; implementationThreadId: ThreadId | null;} export type TimelineEntry = | { id: string; kind: "message"; createdAt: string; message: ChatMessage; } | { id: string; kind: "proposed-plan"; createdAt: string; proposedPlan: ProposedPlan; } | { id: string; kind: "work"; createdAt: string; entry: WorkLogEntry; }; export interface TimelineEntriesProjection { readonly messages: ReadonlyArray<ChatMessage>; readonly proposedPlans: ReadonlyArray<ProposedPlan>; readonly workEntries: ReadonlyArray<WorkLogEntry>; readonly entries: TimelineEntry[];} /** Severe failures keep the red treatment ordinary tool failures lost: runtime * errors and orchestration `*.failed` activities (provider.turn.start.failed, * checkpoint.capture.failed, ...) mean the turn or a core side effect broke, * not that a command exited nonzero. */export function workEntrySignalsSevereFailure(entry: WorkLogEntry): boolean { return ( entry.sourceActivityKind === "runtime.error" || entry.sourceActivityKind?.endsWith(".failed") === true );} /** Tool-like row with neither clear success nor failure (empty, incomplete, in progress, etc.). */export function workEntryIndicatesToolNeutralStatus(entry: WorkLogEntry): boolean { // Spawn CTA rows are never neutral-hidden: mid-run they derive from // task.progress (tone "thinking") and the neutral filter was swallowing // them exactly while the fleet ran — the one moment they matter most. if (entry.agentSpawn !== undefined) { return false; } if (!workLogEntryIsToolLike(entry)) { return false; } if (workEntryIndicatesToolFailure(entry)) { return false; } if (workEntryIndicatesToolSuccess(entry)) { return false; } return true;} type LatestTurnTiming = Pick<OrchestrationLatestTurn, "turnId" | "startedAt" | "completedAt">;type SessionActivityState = Pick<NonNullable<Thread["session"]>, "status" | "activeTurnId">; export function isLatestTurnSettled( latestTurn: LatestTurnTiming | null, session: SessionActivityState | null,): boolean { if (!latestTurn?.startedAt) return false; if (!latestTurn.completedAt) return false; if (!session) return true; if (session.status === "running") return false; return true;} export function deriveActiveWorkStartedAt( latestTurn: LatestTurnTiming | null, session: SessionActivityState | null, sendStartedAt: string | null, latestUserMessageAt: string | null = null,): string | null { const runningTurnId = session?.status === "running" ? session.activeTurnId : null; if (runningTurnId !== null) { if (latestTurn?.turnId === runningTurnId) { return latestTurn.startedAt ?? sendStartedAt ?? latestUserMessageAt; } return sendStartedAt ?? latestUserMessageAt; } if (!isLatestTurnSettled(latestTurn, session)) { return latestTurn?.startedAt ?? sendStartedAt; } return sendStartedAt;} function planStateFromActivity(activity: OrchestrationThreadActivity): ActivePlanState | null { const payload = activity.payload && typeof activity.payload === "object" ? (activity.payload as Record<string, unknown>) : null; const rawPlan = payload?.plan; if (!Array.isArray(rawPlan)) { return null; } const steps: Array<{ step: string; status: "pending" | "inProgress" | "completed"; }> = []; for (const entry of rawPlan) { if (!entry || typeof entry !== "object") { continue; } const record = entry as Record<string, unknown>; if (typeof record.step !== "string") { continue; } const status = record.status === "completed" || record.status === "inProgress" ? record.status : "pending"; steps.push({ step: record.step, status, }); } if (steps.length === 0) { return null; } return { createdAt: activity.createdAt, turnId: activity.turnId, ...(payload && "explanation" in payload ? { explanation: payload.explanation as string | null } : {}), steps, };} function addPlanStepDurations( plan: ActivePlanState, activities: ReadonlyArray<OrchestrationThreadActivity>,): ActivePlanState { const timings = new Map<string, { completedAt?: number; startedAt?: number }>(); let planStartedAt: number | undefined; const keyedSteps = (steps: ActivePlanState["steps"]) => { const occurrences = new Map<string, number>(); return steps.map((step) => { const occurrence = occurrences.get(step.step) ?? 0; occurrences.set(step.step, occurrence + 1); return { key: `${step.step}:${occurrence}`, step }; }); }; for (const activity of activities) { const snapshot = planStateFromActivity(activity); const activityAt = Date.parse(activity.createdAt); if (!snapshot || Number.isNaN(activityAt)) continue; planStartedAt ??= activityAt; for (const { key, step } of keyedSteps(snapshot.steps)) { const timing = timings.get(key) ?? {}; if (step.status === "inProgress" && timing.startedAt === undefined) { timing.startedAt = activityAt; } if (step.status === "completed" && timing.completedAt === undefined) { timing.completedAt = activityAt; } timings.set(key, timing); } } const durationByKey = new Map<string, number>(); let previousCompletedAt = planStartedAt; for (const [key, timing] of [...timings.entries()].toSorted( (left, right) => (left[1].completedAt ?? Infinity) - (right[1].completedAt ?? Infinity), )) { const completedAt = timing.completedAt; const startedAt = timing.startedAt ?? previousCompletedAt; if (completedAt === undefined) continue; if (startedAt !== undefined && completedAt > startedAt) { durationByKey.set(key, completedAt - startedAt); } previousCompletedAt = completedAt; } return { ...plan, steps: keyedSteps(plan.steps).map(({ key, step }) => { if (step.status !== "completed") return step; const durationMs = durationByKey.get(key); return durationMs === undefined ? step : { ...step, durationMs }; }), };} export function deriveActivePlanState( activities: ReadonlyArray<OrchestrationThreadActivity>, latestTurnId: TurnId | undefined,): ActivePlanState | null { const ordered = [...activities].toSorted(compareActivitiesByOrder); const allPlanActivities = ordered.filter((activity) => activity.kind === "turn.plan.updated"); // Prefer plan from the current turn; fall back to the most recent plan from any turn // so that TodoWrite tasks persist across follow-up messages. const latest = Option.firstSomeOf([ ...(latestTurnId ? Arr.findLast(allPlanActivities, (activity) => activity.turnId === latestTurnId) : Option.none()), Arr.last(allPlanActivities), ]).pipe(Option.getOrNull); if (!latest) { return null; } const plan = planStateFromActivity(latest); if (!plan) return null; const matchingActivities = allPlanActivities.filter( (activity) => activity.turnId === latest.turnId, ); const latestClearIndex = matchingActivities.findLastIndex( (activity) => planStateFromActivity(activity) === null, ); return addPlanStepDurations(plan, matchingActivities.slice(latestClearIndex + 1));} export function findLatestProposedPlan( proposedPlans: ReadonlyArray<ProposedPlan>, latestTurnId: TurnId | string | null | undefined,): LatestProposedPlanState | null { if (latestTurnId) { const matchingTurnPlan = [...proposedPlans] .filter((proposedPlan) => proposedPlan.turnId === latestTurnId) .toSorted( (left, right) => left.updatedAt.localeCompare(right.updatedAt) || left.id.localeCompare(right.id), ) .at(-1); if (matchingTurnPlan) { return toLatestProposedPlanState(matchingTurnPlan); } } const latestPlan = [...proposedPlans] .toSorted( (left, right) => left.updatedAt.localeCompare(right.updatedAt) || left.id.localeCompare(right.id), ) .at(-1); if (!latestPlan) { return null; } return toLatestProposedPlanState(latestPlan);} export function hasActionableProposedPlan( proposedPlan: LatestProposedPlanState | Pick<ProposedPlan, "implementedAt"> | null,): boolean { return proposedPlan !== null && proposedPlan.implementedAt === null;} /** * Quiet-timeline guarantee: the work log carries the parent's narrative plus * at most one row per agent. Everything an agent does internally lives in the * Agents surface: * - timelineBypass rows (Codex children, workflow members) never render here; * - tool rows attributed to an owning agent (payload.agentId) are re-homed; * - task.progress ticks collapse into one row per taskId; * - task.updated is fold input only (status patches are not narrative). * Unattributed rows always stay: over-hiding loses the only terminal signal. *//** Agent (non-background) task.started rows seed spawn CTA batches. */function isAgentTaskStartedActivity(activity: OrchestrationThreadActivity): boolean { const payload = activity.payload && typeof activity.payload === "object" ? (activity.payload as Record<string, unknown>) : null; if (!payload || typeof payload.taskId !== "string") { return false; } return !isBackgroundTaskActivity(payload);} function isAgentInternalActivity(activity: OrchestrationThreadActivity): boolean { const payload = activity.payload && typeof activity.payload === "object" ? (activity.payload as Record<string, unknown>) : null; if (!payload) { return false; } const isTaskRow = activity.kind === "task.started" || activity.kind === "task.progress" || activity.kind === "task.updated" || activity.kind === "task.completed"; // Task rows classify by the server stamp: a subagent's own background // shell (agentId + "background") is agent-internal, but a nested AGENT // (agentId + "agent") stays visible so its rows can anchor a spawn CTA // (review finding: hiding on agentId alone removed nested agents and // their anchors). Bypassed agent lifecycle rows also pass — collapse // folds every such row into its batch's single CTA row, which is how // Codex children (whose rows are ALL bypassed) get an anchor at the // spawn point. if (isTaskRow) { const ownedByAgent = typeof payload.agentId === "string" && payload.agentId.trim().length > 0; if (ownedByAgent || payload.timelineBypass === true) { const isAgentTaskRow = activity.kind !== "task.updated" && typeof payload.taskId === "string" && !isBackgroundTaskActivity(payload); return !isAgentTaskRow; } return false; } if (payload.timelineBypass === true) { return true; } // Non-task rows (attributed tool activity) owned by an agent are internal. return typeof payload.agentId === "string" && payload.agentId.trim().length > 0;} export function deriveWorkLogEntries( activities: ReadonlyArray<OrchestrationThreadActivity>,): WorkLogEntry[] { const ordered = [...activities].toSorted(compareActivitiesByOrder); const entries: DerivedWorkLogEntry[] = []; for (const activity of foldUserInputActivities(ordered)) { if (activity.tone !== "error" && isWorktreeSetupActivity(activity.kind)) continue; if (activity.kind === "tool.started") continue; // Agent task.started rows are CTA seeds: they carry the true spawn turn, // which is the batch key (completions of background subagents arrive // under later synthetic turns and must not start new batches). They // collapse into the batch's single CTA row, never render standalone. if (activity.kind === "task.started" && !isAgentTaskStartedActivity(activity)) continue; if (activity.kind === "task.updated") continue; if (activity.kind === "tool.progress") continue; if (activity.kind === "context-window.updated") continue; if (activity.kind === "turn.plan.updated") continue; if (activity.summary === "Checkpoint captured") continue; if (isNoContentRuntimeWarning(activity)) continue; if (isPlanBoundaryToolActivity(activity)) continue; if (isAgentInternalActivity(activity)) continue; entries.push(toDerivedWorkLogEntry(activity)); } return collapseDerivedWorkLogEntries(entries);} /** Adapters forward unknown wire-only SDK messages (background_tasks_changed, * commands_changed, ...) as runtime warnings. The suffix comes from * describeUnknownSdkMessage in the Claude adapter; a row with no displayable * text carries nothing a user can act on, so it does not render. */function isNoContentRuntimeWarning(activity: OrchestrationThreadActivity): boolean { return ( activity.kind === "runtime.warning" && activity.summary.endsWith("(no displayable text content)") );} 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:");} const decodeQuestionAttachmentAnswer = Schema.decodeUnknownOption(UserInputAttachmentAnswerPayload); Lines 1–500 of 1706. Load more
import { requestKindFromRequestType, type PendingApproval, } from "@t3tools/client-runtime/pending-requests"; import { UserInputAttachmentAnswerPayload } from "@t3tools/contracts"; import { foldUserInputActivities } from "@t3tools/client-runtime/work-log/user-input"; import * as Option from "effect/Option"; import * as Schema from "effect/Schema"; import * as Arr from "effect/Array"; import { shallow } from "zustand/vanilla/shallow"; import { isBackgroundTaskActivity } from "@t3tools/client-runtime/state/subagentRuntime"; import { commandDetailRepeatsCommand, extractCommandOutputText, extractWorkLogToolLifecycleStatus, isWorktreeSetupActivity, workEntryIndicatesToolFailure, workEntryIndicatesToolSuccess, workLogEntryIsToolLike, type WorkLogToolLifecycleStatus, } from "@t3tools/client-runtime/work-log/presentation"; import { extractToolActivityPresentation } from "@t3tools/client-runtime/work-log/tool-presentation"; import { isToolLifecycleItemType, type AssetResource, type OrchestrationLatestTurn, type OrchestrationThreadActivity, type OrchestrationProposedPlanId, type ToolLifecycleItemType, type ThreadId, type TurnId, } from "@t3tools/contracts"; import { isImageAttachment, type ChatAttachment, type ChatMessage, type ProposedPlan, type SessionPhase, type Thread, type ThreadSession, type TurnDiffSummary, } from "./types"; export type { PendingApproval, PendingUserInput } from "@t3tools/client-runtime/pending-requests"; export { formatDuration } from "@t3tools/shared/orchestrationTiming"; export { workEntryDisplayIndicatesToolFailure, workEntryIndicatesToolSuccess, workLogEntryIsToolLike, type WorkLogToolLifecycleStatus, } from "@t3tools/client-runtime/work-log/presentation"; export interface WorkLogEntry { questionAnswer?: UserInputAttachmentAnswerPayload; id: string; createdAt: string; turnId?: TurnId | null; /** Stable provider identity across in-progress and completed lifecycle updates. */ toolCallId?: string; label: string; detail?: string; viewedImagePath?: string; command?: string; rawCommand?: string; changedFiles?: ReadonlyArray<string>; tone: "thinking" | "tool" | "info" | "error"; toolTitle?: string; toolSurface?: import("@t3tools/contracts").ToolActivitySurface; toolIcon?: import("@t3tools/contracts").ToolActivityIcon; toolSource?: import("@t3tools/contracts").ToolActivitySource; toolData?: unknown; itemType?: ToolLifecycleItemType; requestKind?: PendingApproval["requestKind"]; /** From runtime item / task payload `status` when present (e.g. tool.updated). */ toolLifecycleStatus?: WorkLogToolLifecycleStatus; /** Originating orchestration activity kind (e.g. `user-input.requested`) for row chrome. */ sourceActivityKind?: OrchestrationThreadActivity["kind"]; /** Grouping key for subagent lifecycle rows (one row per agent). */ taskId?: string; /** Agent role (subagent_type) for labeled timeline rows. */ agentRole?: string; /** * Present on agent-spawn CTA rows: one per workflow run or per-turn batch * of direct spawns. The row renders as a call-to-action ("Kicked off N * subagents") whose live status is derived from the agent panel model at * render time; clicking opens the Agents panel. */ agentSpawn?: { /** Workflow coordinator taskId, or null for a direct-spawn batch. */ workflowId: string | null; agentTaskIds: ReadonlyArray<string>; }; } const workLogCollapseKey = Symbol(); interface DerivedWorkLogEntry extends WorkLogEntry { sourceActivityKind: OrchestrationThreadActivity["kind"]; [workLogCollapseKey]?: string; toolCallId?: string; isWorkflowCoordinator?: boolean; /** Shell/monitor/plan tasks: ordinary work-log rows, never spawn CTAs. */ isBackgroundTask?: boolean; } const derivedWorkLogEntryByActivity = new WeakMap< OrchestrationThreadActivity, DerivedWorkLogEntry >(); export interface ActivePlanState { createdAt: string; turnId: TurnId | null; explanation?: string | null; steps: Array<{ durationMs?: number; step: string; status: "pending" | "inProgress" | "completed"; }>; } export interface LatestProposedPlanState { id: OrchestrationProposedPlanId; createdAt: string; updatedAt: string; turnId: TurnId | null; planMarkdown: string; implementedAt: string | null; implementationThreadId: ThreadId | null; } export type TimelineEntry = | { id: string; kind: "message"; createdAt: string; message: ChatMessage; } | { id: string; kind: "proposed-plan"; createdAt: string; proposedPlan: ProposedPlan; } | { id: string; kind: "work"; createdAt: string; entry: WorkLogEntry; }; export interface TimelineEntriesProjection { readonly messages: ReadonlyArray<ChatMessage>; readonly proposedPlans: ReadonlyArray<ProposedPlan>; readonly workEntries: ReadonlyArray<WorkLogEntry>; readonly entries: TimelineEntry[]; } /** Severe failures keep the red treatment ordinary tool failures lost: runtime * errors and orchestration `*.failed` activities (provider.turn.start.failed, * checkpoint.capture.failed, ...) mean the turn or a core side effect broke, * not that a command exited nonzero. */ export function workEntrySignalsSevereFailure(entry: WorkLogEntry): boolean { return ( entry.sourceActivityKind === "runtime.error" || entry.sourceActivityKind?.endsWith(".failed") === true ); } /** Tool-like row with neither clear success nor failure (empty, incomplete, in progress, etc.). */ export function workEntryIndicatesToolNeutralStatus(entry: WorkLogEntry): boolean { // Spawn CTA rows are never neutral-hidden: mid-run they derive from // task.progress (tone "thinking") and the neutral filter was swallowing // them exactly while the fleet ran — the one moment they matter most. if (entry.agentSpawn !== undefined) { return false; } if (!workLogEntryIsToolLike(entry)) { return false; } if (workEntryIndicatesToolFailure(entry)) { return false; } if (workEntryIndicatesToolSuccess(entry)) { return false; } return true; } type LatestTurnTiming = Pick<OrchestrationLatestTurn, "turnId" | "startedAt" | "completedAt">; type SessionActivityState = Pick<NonNullable<Thread["session"]>, "status" | "activeTurnId">; export function isLatestTurnSettled( latestTurn: LatestTurnTiming | null, session: SessionActivityState | null, ): boolean { if (!latestTurn?.startedAt) return false; if (!latestTurn.completedAt) return false; if (!session) return true; if (session.status === "running") return false; return true; } export function deriveActiveWorkStartedAt( latestTurn: LatestTurnTiming | null, session: SessionActivityState | null, sendStartedAt: string | null, latestUserMessageAt: string | null = null, ): string | null { const runningTurnId = session?.status === "running" ? session.activeTurnId : null; if (runningTurnId !== null) { if (latestTurn?.turnId === runningTurnId) { return latestTurn.startedAt ?? sendStartedAt ?? latestUserMessageAt; } return sendStartedAt ?? latestUserMessageAt; } if (!isLatestTurnSettled(latestTurn, session)) { return latestTurn?.startedAt ?? sendStartedAt; } return sendStartedAt; } function planStateFromActivity(activity: OrchestrationThreadActivity): ActivePlanState | null { const payload = activity.payload && typeof activity.payload === "object" ? (activity.payload as Record<string, unknown>) : null; const rawPlan = payload?.plan; if (!Array.isArray(rawPlan)) { return null; } const steps: Array<{ step: string; status: "pending" | "inProgress" | "completed"; }> = []; for (const entry of rawPlan) { if (!entry || typeof entry !== "object") { continue; } const record = entry as Record<string, unknown>; if (typeof record.step !== "string") { continue; } const status = record.status === "completed" || record.status === "inProgress" ? record.status : "pending"; steps.push({ step: record.step, status, }); } if (steps.length === 0) { return null; } return { createdAt: activity.createdAt, turnId: activity.turnId, ...(payload && "explanation" in payload ? { explanation: payload.explanation as string | null } : {}), steps, }; } function addPlanStepDurations( plan: ActivePlanState, activities: ReadonlyArray<OrchestrationThreadActivity>, ): ActivePlanState { const timings = new Map<string, { completedAt?: number; startedAt?: number }>(); let planStartedAt: number | undefined; const keyedSteps = (steps: ActivePlanState["steps"]) => { const occurrences = new Map<string, number>(); return steps.map((step) => { const occurrence = occurrences.get(step.step) ?? 0; occurrences.set(step.step, occurrence + 1); return { key: `${step.step}:${occurrence}`, step }; }); }; for (const activity of activities) { const snapshot = planStateFromActivity(activity); const activityAt = Date.parse(activity.createdAt); if (!snapshot || Number.isNaN(activityAt)) continue; planStartedAt ??= activityAt; for (const { key, step } of keyedSteps(snapshot.steps)) { const timing = timings.get(key) ?? {}; if (step.status === "inProgress" && timing.startedAt === undefined) { timing.startedAt = activityAt; } if (step.status === "completed" && timing.completedAt === undefined) { timing.completedAt = activityAt; } timings.set(key, timing); } } const durationByKey = new Map<string, number>(); let previousCompletedAt = planStartedAt; for (const [key, timing] of [...timings.entries()].toSorted( (left, right) => (left[1].completedAt ?? Infinity) - (right[1].completedAt ?? Infinity), )) { const completedAt = timing.completedAt; const startedAt = timing.startedAt ?? previousCompletedAt; if (completedAt === undefined) continue; if (startedAt !== undefined && completedAt > startedAt) { durationByKey.set(key, completedAt - startedAt); } previousCompletedAt = completedAt; } return { ...plan, steps: keyedSteps(plan.steps).map(({ key, step }) => { if (step.status !== "completed") return step; const durationMs = durationByKey.get(key); return durationMs === undefined ? step : { ...step, durationMs }; }), }; } export function deriveActivePlanState( activities: ReadonlyArray<OrchestrationThreadActivity>, latestTurnId: TurnId | undefined, ): ActivePlanState | null { const ordered = [...activities].toSorted(compareActivitiesByOrder); const allPlanActivities = ordered.filter((activity) => activity.kind === "turn.plan.updated"); // Prefer plan from the current turn; fall back to the most recent plan from any turn // so that TodoWrite tasks persist across follow-up messages. const latest = Option.firstSomeOf([ ...(latestTurnId ? Arr.findLast(allPlanActivities, (activity) => activity.turnId === latestTurnId) : Option.none()), Arr.last(allPlanActivities), ]).pipe(Option.getOrNull); if (!latest) { return null; } const plan = planStateFromActivity(latest); if (!plan) return null; const matchingActivities = allPlanActivities.filter( (activity) => activity.turnId === latest.turnId, ); const latestClearIndex = matchingActivities.findLastIndex( (activity) => planStateFromActivity(activity) === null, ); return addPlanStepDurations(plan, matchingActivities.slice(latestClearIndex + 1)); } export function findLatestProposedPlan( proposedPlans: ReadonlyArray<ProposedPlan>, latestTurnId: TurnId | string | null | undefined, ): LatestProposedPlanState | null { if (latestTurnId) { const matchingTurnPlan = [...proposedPlans] .filter((proposedPlan) => proposedPlan.turnId === latestTurnId) .toSorted( (left, right) => left.updatedAt.localeCompare(right.updatedAt) || left.id.localeCompare(right.id), ) .at(-1); if (matchingTurnPlan) { return toLatestProposedPlanState(matchingTurnPlan); } } const latestPlan = [...proposedPlans] .toSorted( (left, right) => left.updatedAt.localeCompare(right.updatedAt) || left.id.localeCompare(right.id), ) .at(-1); if (!latestPlan) { return null; } return toLatestProposedPlanState(latestPlan); } export function hasActionableProposedPlan( proposedPlan: LatestProposedPlanState | Pick<ProposedPlan, "implementedAt"> | null, ): boolean { return proposedPlan !== null && proposedPlan.implementedAt === null; } /** * Quiet-timeline guarantee: the work log carries the parent's narrative plus * at most one row per agent. Everything an agent does internally lives in the * Agents surface: * - timelineBypass rows (Codex children, workflow members) never render here; * - tool rows attributed to an owning agent (payload.agentId) are re-homed; * - task.progress ticks collapse into one row per taskId; * - task.updated is fold input only (status patches are not narrative). * Unattributed rows always stay: over-hiding loses the only terminal signal. */ /** Agent (non-background) task.started rows seed spawn CTA batches. */ function isAgentTaskStartedActivity(activity: OrchestrationThreadActivity): boolean { const payload = activity.payload && typeof activity.payload === "object" ? (activity.payload as Record<string, unknown>) : null; if (!payload || typeof payload.taskId !== "string") { return false; } return !isBackgroundTaskActivity(payload); } function isAgentInternalActivity(activity: OrchestrationThreadActivity): boolean { const payload = activity.payload && typeof activity.payload === "object" ? (activity.payload as Record<string, unknown>) : null; if (!payload) { return false; } const isTaskRow = activity.kind === "task.started" || activity.kind === "task.progress" || activity.kind === "task.updated" || activity.kind === "task.completed"; // Task rows classify by the server stamp: a subagent's own background // shell (agentId + "background") is agent-internal, but a nested AGENT // (agentId + "agent") stays visible so its rows can anchor a spawn CTA // (review finding: hiding on agentId alone removed nested agents and // their anchors). Bypassed agent lifecycle rows also pass — collapse // folds every such row into its batch's single CTA row, which is how // Codex children (whose rows are ALL bypassed) get an anchor at the // spawn point. if (isTaskRow) { const ownedByAgent = typeof payload.agentId === "string" && payload.agentId.trim().length > 0; if (ownedByAgent || payload.timelineBypass === true) { const isAgentTaskRow = activity.kind !== "task.updated" && typeof payload.taskId === "string" && !isBackgroundTaskActivity(payload); return !isAgentTaskRow; } return false; } if (payload.timelineBypass === true) { return true; } // Non-task rows (attributed tool activity) owned by an agent are internal. return typeof payload.agentId === "string" && payload.agentId.trim().length > 0; } export function deriveWorkLogEntries( activities: ReadonlyArray<OrchestrationThreadActivity>, ): WorkLogEntry[] { const ordered = [...activities].toSorted(compareActivitiesByOrder); const entries: DerivedWorkLogEntry[] = []; for (const activity of foldUserInputActivities(ordered)) { if (activity.tone !== "error" && isWorktreeSetupActivity(activity.kind)) continue; if (activity.kind === "tool.started") continue; // Agent task.started rows are CTA seeds: they carry the true spawn turn, // which is the batch key (completions of background subagents arrive // under later synthetic turns and must not start new batches). They // collapse into the batch's single CTA row, never render standalone. if (activity.kind === "task.started" && !isAgentTaskStartedActivity(activity)) continue; if (activity.kind === "task.updated") continue; if (activity.kind === "tool.progress") continue; if (activity.kind === "context-window.updated") continue; if (activity.kind === "turn.plan.updated") continue; if (activity.summary === "Checkpoint captured") continue; if (isNoContentRuntimeWarning(activity)) continue; if (isPlanBoundaryToolActivity(activity)) continue; if (isAgentInternalActivity(activity)) continue; entries.push(toDerivedWorkLogEntry(activity)); } return collapseDerivedWorkLogEntries(entries); } /** Adapters forward unknown wire-only SDK messages (background_tasks_changed, * commands_changed, ...) as runtime warnings. The suffix comes from * describeUnknownSdkMessage in the Claude adapter; a row with no displayable * text carries nothing a user can act on, so it does not render. */ function isNoContentRuntimeWarning(activity: OrchestrationThreadActivity): boolean { return ( activity.kind === "runtime.warning" && activity.summary.endsWith("(no displayable text content)") ); } 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:"); } const decodeQuestionAttachmentAnswer = Schema.decodeUnknownOption(UserInputAttachmentAnswerPayload);