diff --git a/frontend/app/app/assistant.tsx b/frontend/app/app/assistant.tsx index b9d0a23..86ce711 100644 --- a/frontend/app/app/assistant.tsx +++ b/frontend/app/app/assistant.tsx @@ -71,6 +71,11 @@ export const Assistant = () => { const replaySession = useCallback( (sessionId: string, repository: ExportedMessageRepository) => { writeActiveSessionId(sessionId); + // 后端已经落盘/结束后,用回放结果接管当前会话。 + // 先取消本地仍挂起的 assistant-ui run,避免 UI 残留“运行中”且无法停止。 + if (runtime.thread.getState().isRunning) { + runtime.thread.cancelRun(); + } runtime.thread.import(repository); }, [runtime], diff --git a/frontend/app/components/assistant-ui/thread.tsx b/frontend/app/components/assistant-ui/thread.tsx index 75efeaa..76fa85b 100644 --- a/frontend/app/components/assistant-ui/thread.tsx +++ b/frontend/app/components/assistant-ui/thread.tsx @@ -908,6 +908,7 @@ const ComposerWorkspaceStatus: FC<{ sessionId: string | null }> = ({ }; const ComposerAction: FC = () => { + const aui = useAui(); const runtimeRunning = useAuiState((s) => s.thread.isRunning); const replayedRun = useReplayedRunState(); const currentSessionId = useCurrentThreadSessionId({ @@ -955,6 +956,8 @@ const ComposerAction: FC = () => { void cancelLatestRun(cancelSessionId, replayedRun.runId) .catch(() => undefined) .finally(() => { + // 后端可能已经 idle;无论取消接口是否真的命中 run,都清理本地残留运行态。 + aui.thread().cancelRun(); window.setTimeout(() => setRuntimeCancelling(false), 1200); }); }}