diff --git a/src/agents/pi-embedded-runner/run.ts b/src/agents/pi-embedded-runner/run.ts index e1e1ac3aa67..3082f9638b7 100644 --- a/src/agents/pi-embedded-runner/run.ts +++ b/src/agents/pi-embedded-runner/run.ts @@ -1109,8 +1109,14 @@ export async function runEmbeddedPiAgent( if (params.currentMessageId !== undefined) { lastPersistedCurrentMessageId = params.currentMessageId; } + params.userTurnTranscriptRecorder?.markRuntimePersisted(message); params.onUserMessagePersisted?.(message); }; + const onUserMessagePersistencePending: RunEmbeddedPiAgentParams["onUserMessagePersistencePending"] = + (pending) => { + params.userTurnTranscriptRecorder?.markRuntimePersistencePending(pending); + params.onUserMessagePersistencePending?.(pending); + }; const continueFromCurrentTranscript = () => { nextAttemptPromptOverride = MID_TURN_PRECHECK_CONTINUATION_PROMPT; suppressNextUserMessagePersistence = true; @@ -1539,7 +1545,7 @@ export async function runEmbeddedPiAgent( suppressTranscriptOnlyAssistantPersistence: params.suppressTranscriptOnlyAssistantPersistence, suppressAssistantErrorPersistence: params.suppressAssistantErrorPersistence, - onUserMessagePersistencePending: params.onUserMessagePersistencePending, + onUserMessagePersistencePending, onUserMessagePersisted, onAssistantErrorMessagePersisted: params.onAssistantErrorMessagePersisted, }) diff --git a/src/agents/pi-embedded-runner/run/params.ts b/src/agents/pi-embedded-runner/run/params.ts index bf6306bb419..13ea430f79f 100644 --- a/src/agents/pi-embedded-runner/run/params.ts +++ b/src/agents/pi-embedded-runner/run/params.ts @@ -12,7 +12,10 @@ import type { OpenClawConfig } from "../../../config/types.openclaw.js"; import type { PromptImageOrderEntry } from "../../../media/prompt-image-order.js"; import type { CommandQueueEnqueueFn } from "../../../process/command-queue.types.js"; import type { InputProvenance } from "../../../sessions/input-provenance.js"; -import type { PersistedUserTurnMessage } from "../../../sessions/user-turn-transcript.js"; +import type { + PersistedUserTurnMessage, + UserTurnTranscriptRecorder, +} from "../../../sessions/user-turn-transcript.js"; import type { ExecElevatedDefaults, ExecToolDefaults } from "../../bash-tools.exec-types.js"; import type { AgentStreamParams, ClientToolDefinition } from "../../command/shared-types.js"; import type { AgentInternalEvent } from "../../internal-events.js"; @@ -232,6 +235,7 @@ export type RunEmbeddedPiAgentParams = { suppressNextUserMessagePersistence?: boolean; suppressTranscriptOnlyAssistantPersistence?: boolean; suppressAssistantErrorPersistence?: boolean; + userTurnTranscriptRecorder?: UserTurnTranscriptRecorder; onUserMessagePersistencePending?: (pending: Promise) => void; onUserMessagePersisted?: (message: Extract) => void; onAssistantErrorMessagePersisted?: ( diff --git a/src/auto-reply/reply/agent-runner-execution.ts b/src/auto-reply/reply/agent-runner-execution.ts index bf345b436c7..f9d348d8312 100644 --- a/src/auto-reply/reply/agent-runner-execution.ts +++ b/src/auto-reply/reply/agent-runner-execution.ts @@ -1865,6 +1865,11 @@ export async function runAgentTurnWithFallback(params: { const runLane = CommandLane.Main; let queuedUserMessagePersistedAcrossFallback = false; let assistantErrorPersistedAcrossFallback = false; + const userTurnTranscriptRecorder = + params.followupRun.userTurnTranscriptRecorder ?? params.opts?.userTurnTranscriptRecorder; + const notifyUserMessagePersisted = () => { + queuedUserMessagePersistedAcrossFallback = true; + }; // Profiler-only milestone: it separates fallback setup from the actual // model run without adding extra live logs/snapshots to normal turns. agentTurnTiming.logMilestoneIfSlow({ @@ -2044,6 +2049,9 @@ export async function runAgentTurnWithFallback(params: { config: runtimeConfig, prompt: params.commandBody, transcriptPrompt: params.transcriptCommandBody, + suppressNextUserMessagePersistence: suppressQueuedUserPersistenceForCandidate, + userTurnTranscriptRecorder, + onUserMessagePersisted: notifyUserMessagePersisted, currentInboundEventKind: params.followupRun.currentInboundEventKind, currentInboundContext: params.followupRun.currentInboundContext, inputProvenance: params.followupRun.run.inputProvenance, @@ -2166,6 +2174,7 @@ export async function runAgentTurnWithFallback(params: { sandboxSessionKey: params.runtimePolicySessionKey, prompt: params.commandBody, transcriptPrompt: params.transcriptCommandBody, + userTurnTranscriptRecorder, currentInboundEventKind: params.followupRun.currentInboundEventKind, currentInboundContext: params.followupRun.currentInboundContext, extraSystemPrompt: params.followupRun.run.extraSystemPrompt, @@ -2174,9 +2183,7 @@ export async function runAgentTurnWithFallback(params: { params.followupRun.run.sourceReplyDeliveryMode === "message_tool_only", silentReplyPromptMode: params.followupRun.run.silentReplyPromptMode, suppressNextUserMessagePersistence: suppressQueuedUserPersistenceForCandidate, - onUserMessagePersisted: () => { - queuedUserMessagePersistedAcrossFallback = true; - }, + onUserMessagePersisted: notifyUserMessagePersisted, suppressTranscriptOnlyAssistantPersistence: params.followupRun.run.suppressTranscriptOnlyAssistantPersistence, suppressAssistantErrorPersistence: diff --git a/src/auto-reply/reply/followup-runner.ts b/src/auto-reply/reply/followup-runner.ts index b558d5aca8c..dc51230e7b3 100644 --- a/src/auto-reply/reply/followup-runner.ts +++ b/src/auto-reply/reply/followup-runner.ts @@ -843,6 +843,7 @@ export function createFollowupRunner(params: { prompt: queued.prompt, transcriptPrompt: queued.transcriptPrompt, userMessageForPersistence: effectiveQueued.userMessageForPersistence, + userTurnTranscriptRecorder: opts?.userTurnTranscriptRecorder, currentInboundEventKind: queued.currentInboundEventKind, currentInboundContext: queued.currentInboundContext, extraSystemPrompt: run.extraSystemPrompt,