From 590b6623174e79fb641b6308e37a6b3a7c35c8a3 Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Thu, 25 Jun 2026 19:42:10 +0800 Subject: [PATCH] fix: preserve cancel prompt after event checkpoints (#2154) Co-authored-by: root --- .../cloud/workbench-projection-writer.test.ts | 14 +++++++++++ internal/cloud/workbench-projection-writer.ts | 24 ++++++++++++------- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/internal/cloud/workbench-projection-writer.test.ts b/internal/cloud/workbench-projection-writer.test.ts index f20d6c28..45eb96bc 100644 --- a/internal/cloud/workbench-projection-writer.test.ts +++ b/internal/cloud/workbench-projection-writer.test.ts @@ -715,6 +715,20 @@ test("workbench projection writer does not replace prior user prompt with cancel }, session: { sessionStatus: "running", lastTraceId: traceId } }); + await writeWorkbenchProjectionEvent({ + runtimeStore, + event: { + traceId, + sessionId: "ses_writer_canceled_prompt_preserved", + source: "agentrun", + sourceSeq: 1, + type: "backend", + eventType: "backend", + status: "running", + label: "agentrun:request:accepted", + createdAt: "2026-06-20T11:04:10.000Z" + } + }); await writeWorkbenchProjectionSession({ accessController, runtimeStore, diff --git a/internal/cloud/workbench-projection-writer.ts b/internal/cloud/workbench-projection-writer.ts index 452f8c12..020af106 100644 --- a/internal/cloud/workbench-projection-writer.ts +++ b/internal/cloud/workbench-projection-writer.ts @@ -677,17 +677,19 @@ function workbenchProjectionUserMessage({ payload = {}, params = {}, traceId = n } function preserveTerminalUserMessage(messages = [], { terminal = false, traceId = null, previousCheckpoint = null } = {}) { - if (!terminal || !traceId || !previousCheckpoint?.userMessage) return messages; - const previousUserMessage = previousCheckpoint.userMessage; - const previousText = textValue(previousUserMessage.text ?? previousUserMessage.content ?? previousUserMessage.message); - if (!previousText) return messages; - let replaced = false; + if (!terminal || !traceId) return messages; + const previousUserMessage = previousCheckpoint?.userMessage ?? null; + const previousText = textValue(previousUserMessage?.text ?? previousUserMessage?.content ?? previousUserMessage?.message); + let handledUser = false; const normalizedTraceId = safeTraceId(traceId) ?? traceId; const preserved = messages.map((message) => { const role = textValue(message?.role) || "agent"; const messageTraceId = safeTraceId(message?.traceId ?? message?.turnId ?? normalizedTraceId) ?? normalizedTraceId; if (role !== "user" || messageTraceId !== normalizedTraceId) return message; - replaced = true; + handledUser = true; + const messageText = textValue(message?.text ?? message?.content ?? message?.message); + if (!previousText && isSyntheticTerminalUserNotice(messageText)) return null; + if (!previousText) return message; return { ...message, ...previousUserMessage, @@ -700,11 +702,17 @@ function preserveTerminalUserMessage(messages = [], { terminal = false, traceId terminal: false, sealed: false }; - }); - if (replaced) return preserved; + }).filter(Boolean); + if (handledUser) return preserved; + if (!previousText) return preserved; return [previousUserMessage, ...messages]; } +function isSyntheticTerminalUserNotice(text) { + const value = textValue(text); + return /当前\s*AgentRun\s*请求已取消|请求已取消|hwlab-user-cancel/u.test(value); +} + function normalizeMessages(messages, context) { const normalized = Array.isArray(messages) ? messages.map((message, index) => normalizeMessageFact(message, index, context)).filter(Boolean) : []; if (context?.terminal && context?.finalText && context?.traceId && !normalized.some((message) => message.role !== "user" && message.traceId === context.traceId)) {