From 757e1adaae2915cc787ed21097bcb7ef21eee8f2 Mon Sep 17 00:00:00 2001 From: JOJO <1498581755@qq.com> Date: Sun, 14 Dec 2025 17:35:34 +0800 Subject: [PATCH] fix: sync stop states with composer busy --- static/src/App.vue | 2 +- static/src/app.ts | 74 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/static/src/App.vue b/static/src/App.vue index 6742e3b..c438e2a 100644 --- a/static/src/App.vue +++ b/static/src/App.vue @@ -156,7 +156,7 @@ :input-is-multiline="inputIsMultiline" :input-is-focused="inputIsFocused" :is-connected="isConnected" - :streaming-message="streamingMessage" + :streaming-message="composerBusy" :input-locked="displayLockEngaged" :uploading="uploading" :thinking-mode="thinkingMode" diff --git a/static/src/app.ts b/static/src/app.ts index 2dcae8b..f6a6886 100644 --- a/static/src/app.ts +++ b/static/src/app.ts @@ -111,6 +111,7 @@ const appOptions = { return { // 路由相关 initialRouteResolved: false, + dropToolEvents: false, // 工具状态跟踪 preparingTools: new Map(), @@ -291,10 +292,16 @@ const appOptions = { }) , displayModeSwitchDisabled() { - return this.streamingMessage || this.monitorIsLocked; + return this.composerBusy; }, displayLockEngaged() { - return this.streamingMessage || this.monitorIsLocked; + return this.composerBusy; + }, + streamingUi() { + return this.streamingMessage || this.hasPendingToolActions(); + }, + composerBusy() { + return this.streamingUi || this.monitorIsLocked || this.stopRequested; } }, @@ -1022,13 +1029,15 @@ const appOptions = { this.monitorResetVisual({ preserveBubble: true, preservePointer: true, - preserveWindows: !!options?.preserveMonitorWindows + preserveWindows: !!options?.preserveMonitorWindows, + preserveQueue: !!options?.preserveMonitorWindows }); // 重置消息和流状态 this.streamingMessage = false; this.currentMessageIndex = -1; this.stopRequested = false; + this.dropToolEvents = false; // 清理工具状态 this.toolResetTracking(); @@ -1916,7 +1925,7 @@ const appOptions = { }, handleSendOrStop() { - if (this.streamingMessage) { + if (this.composerBusy) { this.stopTask(); } else { this.sendMessage(); @@ -1924,7 +1933,7 @@ const appOptions = { }, sendMessage() { - if (this.streamingMessage || !this.isConnected) { + if (this.streamingUi || !this.isConnected) { return; } @@ -1969,11 +1978,62 @@ const appOptions = { // 新增:停止任务方法 stopTask() { - if (this.streamingMessage && !this.stopRequested) { + const canStop = this.composerBusy && !this.stopRequested; + if (!canStop) { + return; + } + + const shouldDropToolEvents = this.streamingUi; + this.stopRequested = true; + this.dropToolEvents = shouldDropToolEvents; + if (this.socket) { this.socket.emit('stop_task'); - this.stopRequested = true; debugLog('发送停止请求'); } + + // 立即清理前端状态,避免出现“不可输入也不可停止”的卡死状态 + this.clearPendingTools('user_stop'); + this.streamingMessage = false; + this.forceUnlockMonitor('user_stop'); + }, + + forceUnlockMonitor(reason = 'unspecified') { + try { + this.monitorResetVisual({ + preserveBubble: true, + preservePointer: true, + preserveWindows: true, + preserveQueue: false, + preservePendingResults: false, + preserveAwaitingTools: false + }); + debugLog('Monitor unlocked', { reason }); + } catch (error) { + console.warn('强制解锁监控面板失败', error); + } + }, + clearPendingTools(reason = 'unspecified') { + debugLog('清理未完成工具', { reason }); + if (Array.isArray(this.messages)) { + this.messages.forEach(msg => { + if (!msg || msg.role !== 'assistant' || !Array.isArray(msg.actions)) { + return; + } + msg.actions.forEach(action => { + if (action && action.type === 'tool' && action.tool) { + action.tool.status = action.tool.status || 'cancelled'; + action.tool.awaiting_content = false; + action.streaming = false; + } + }); + }); + } + this.toolResetTracking(); + this.preparingTools.clear(); + this.activeTools.clear(); + this.toolActionIndex.clear(); + this.toolStacks.clear(); + this.stopRequested = false; }, async clearChat() {