diff --git a/frontend/app/components/assistant-ui/thread-list.tsx b/frontend/app/components/assistant-ui/thread-list.tsx index b8acba7..03aa413 100644 --- a/frontend/app/components/assistant-ui/thread-list.tsx +++ b/frontend/app/components/assistant-ui/thread-list.tsx @@ -481,6 +481,34 @@ export function toReplayRepository( messages.push({ message: threadMessage, parentId: previousId }); previousId = id; } + if (shouldShowTerminalPendingPrompt(replayMessages, runStatus)) { + const pendingPrompt = resolvePendingPrompt(replayMessages, runStatus); + if (pendingPrompt) { + const id = `${fallbackSessionId}-pending-${runStatus?.run_id ?? "terminal"}`; + const parts = [ + { type: "text", text: pendingPrompt }, + ] as UIMessage["parts"]; + const uiMessage: UIMessage = { + id, + role: "user", + parts, + metadata: { sessionId: session.session_id ?? fallbackSessionId }, + } as UIMessage; + const threadMessage = { + id, + role: "user", + createdAt: new Date(), + content: toThreadMessageContent(parts), + attachments: [], + metadata: { + custom: { sessionId: session.session_id ?? fallbackSessionId }, + }, + } as ThreadMessage; + bindExternalStoreMessage(threadMessage, uiMessage); + messages.push({ message: threadMessage, parentId: previousId }); + previousId = id; + } + } if (shouldShowInterruptedNotice(session.messages ?? [], runStatus)) { const id = `${fallbackSessionId}-interrupted`; const text = @@ -586,6 +614,19 @@ function isActiveRunStatus( return runStatus?.status === "queued" || runStatus?.status === "running"; } +function shouldShowTerminalPendingPrompt( + messages: readonly ClawStoredMessage[], + runStatus?: ClawRunStatus | null, +) { + return ( + !isActiveRunStatus(runStatus) && + Boolean(resolvePendingPrompt(messages, runStatus)) && + (runStatus?.status === "interrupted" || + runStatus?.status === "cancelled" || + runStatus?.status === "failed") + ); +} + function buildActiveRunParts(runStatus: ClawActiveRunStatus) { const eventLines = summarizeRunEvents(runStatus); const fallback = @@ -761,10 +802,10 @@ function isRunStatusMessage(message?: ClawStoredMessage) { function resolvePendingPrompt( messages: readonly ClawStoredMessage[], - runStatus: ClawRunStatus, + runStatus?: ClawRunStatus | null, ) { const pendingPrompt = - typeof runStatus.pending_prompt === "string" + typeof runStatus?.pending_prompt === "string" ? runStatus.pending_prompt.trim() : ""; if (!pendingPrompt) return null;