fix(stop-button): 修复REST轮询路径两个bug

1. lifecycle.ts handleTaskStopped: 移除'再次按下停止按钮以结束后台任务'弹窗。
   后台任务停止不再走停止按钮二次点击路径。

2. 主对话空闲+后台任务跑时输入栏依然为停止按钮:
   根因 - App.vue 传给 InputComposer 的 streaming-message 用的是
   composerStreamingForInput (= composerBusy && !displayLockEngaged),
   只要有后台任务 taskInProgress=true 就让 streamingMessage=true。
   改为传 streamingUi (= streamingMessage || hasPendingToolActions),
   只看主对话自身是否在流式输出,与后台任务无关。

3. 后端 chat_flow_task_main.py 用户主动停止时发的 task_stopped
   事件没带 has_running_* 字段,导致前端误判为完全空闲。
   补全字段(has_running_sub_agents/has_running_background_commands/
   has_running_multi_agent),前端用此信息决定是否保持对话运行态。
This commit is contained in:
JOJO 2026-07-14 19:46:31 +08:00
parent ae70e4902e
commit 0aa37b83ee
3 changed files with 44 additions and 16 deletions

View File

@ -1833,9 +1833,43 @@ async def handle_task_with_sender(
)
except Exception as exc:
debug_log(f"[Goal] 用户停止时停止目标失败: {exc}")
# 计算后台任务状态,前端用这个字段决定是否保持对话运行态、输入区是否释放
_stopped_has_bg = False
_stopped_has_bg_cmd = False
_stopped_has_ma = False
_manager = getattr(web_terminal, "sub_agent_manager", None)
if _manager:
try:
_manager.reconcile_task_states(conversation_id=conversation_id)
except Exception:
pass
if getattr(web_terminal, "multi_agent_mode", False):
_state = _manager.get_multi_agent_state(conversation_id)
if _state:
_stopped_has_ma = any(a.status == "running" for a in _state.list_all())
for _t in _manager.tasks.values():
if _t.get("conversation_id") != conversation_id:
continue
if _t.get("status") in TERMINAL_STATUSES.union({"terminated"}):
continue
if _t.get("multi_agent_mode"):
continue
_stopped_has_bg = True
break
_bg_mgr = getattr(web_terminal, "background_command_manager", None)
if _bg_mgr and conversation_id:
try:
_bg_mgr.reconcile_stale_records(conversation_id=conversation_id)
except Exception:
pass
if _bg_mgr.list_waiting_items(conversation_id):
_stopped_has_bg_cmd = True
sender('task_stopped', {
'message': '任务已停止',
'reason': 'user_requested'
'reason': 'user_requested',
'has_running_sub_agents': _stopped_has_bg,
'has_running_background_commands': _stopped_has_bg_cmd,
'has_running_multi_agent': _stopped_has_ma,
})
break
@ -2189,7 +2223,10 @@ async def handle_task_with_sender(
sender('task_stopped', {
'message': tool_loop_result.get("approval_message") or '操作被用户拒绝',
'reason': 'approval_rejected',
'conversation_id': conversation_id
'conversation_id': conversation_id,
'has_running_sub_agents': False,
'has_running_background_commands': False,
'has_running_multi_agent': False
})
finalize_user_work_timer()
finalize_run_versioning_checkpoint("approval_rejected")

View File

@ -279,7 +279,7 @@
:input-is-multiline="inputIsMultiline"
:input-is-focused="inputIsFocused"
:is-connected="isConnected"
:streaming-message="composerStreamingForInput"
:streaming-message="streamingUi"
:input-locked="displayLockEngaged"
:uploading="uploading"
:media-uploading="mediaUploading"

View File

@ -486,22 +486,13 @@ export const lifecycleMethods = {
this.stopRequested = false;
if (hasRunningBackground) {
// 智能体已停,但后台任务还在跑:保持停止按钮,等用户第二下清理
// 此时对话并未真正停止work_timer 保持运行,不提前标记完成
// 主智能体已停,后台任务仍在跑:保持 taskInProgress=true (对话列表显示运行中),
// 但输入栏不再锁定stopRequested 已重置),用户可发新消息触发下一轮。
// 后台任务的停止由独立的子智能体/后台指令按钮处理,不再走停止按钮二次点击。
this.taskInProgress = true;
this.waitingForSubAgent = hasRunningSubAgents;
this.waitingForBackgroundCommand = hasRunningBackgroundCommands;
debugLog('[TaskPolling] 任务已停止,仍有后台任务运行,保持停止态');
goalModeDebugLog('handleTaskStopped:show-toast', { hasRunningSubAgents, hasRunningBackgroundCommands });
try {
this.uiPushToast({
title: '智能体已停止',
message: '再次按下停止按钮以结束后台任务',
type: 'info'
});
} catch (err) {
console.warn('[TaskPolling] uiPushToast 调用失败:', err);
}
debugLog('[TaskPolling] 任务已停止,仍有后台任务运行,保持对话运行态但释放输入区');
} else {
// 对话真正停止:停止计时器并持久化
this.markLatestUserWorkCompleted();