fix(chat): 运行期间权限切换使用pending机制,避免来回切换插入多余消息

- update_permission_mode / update_execution_mode 运行期间改用 queue 机制
- pending 值可被覆盖,最终若与当前相同则不通知
- 返回值直接返回 target_mode,前端立即更新 UI
This commit is contained in:
JOJO 2026-06-09 12:13:15 +08:00
parent ff7108738e
commit ca4bf17639

View File

@ -689,6 +689,44 @@ def update_permission_mode(terminal: WebTerminal, workspace: UserWorkspace, user
"success": False,
"error": "无效权限模式,仅支持 readonly / approval / auto_approval / unrestricted"
}), 400
# 判断当前是否在对话运行期间
is_running = False
try:
from .tasks import task_manager
current_conv = getattr(getattr(terminal, "context_manager", None), "current_conversation_id", None)
running_tasks = [
r for r in task_manager.list_tasks(username) if r.status in {"pending", "running", "cancel_requested"}
]
if current_conv:
running_tasks.sort(key=lambda r: 0 if r.conversation_id == current_conv else 1)
is_running = bool(running_tasks)
except Exception:
pass
if is_running:
# 运行期间:使用 pending 机制延迟到工具循环中统一处理,
# 避免「A→B→A」来回切换时中间值被覆盖后仍插入多余消息。
try:
terminal.queue_permission_mode_change(target_mode)
except Exception as exc:
return jsonify({
"success": False,
"error": str(exc),
"message": "更新权限模式失败"
}), 500
status = terminal.get_status()
socketio.emit('status_update', status, room=f"user_{username}")
return jsonify({
"success": True,
"mode": target_mode,
"pending_mode": target_mode,
"options": PERMISSION_MODE_OPTIONS,
"conversation_id": getattr(terminal.context_manager, "current_conversation_id", None),
"message": "权限模式将在当前工具执行完成后生效",
})
# 空闲期间:直接生效
previous_mode = terminal.get_permission_mode() if hasattr(terminal, "get_permission_mode") else None
try:
applied_mode = terminal.set_permission_mode(target_mode)
@ -756,6 +794,42 @@ def update_execution_mode(terminal: WebTerminal, workspace: UserWorkspace, usern
target_mode = str(data.get("mode") or "").strip().lower()
if target_mode not in EXECUTION_MODE_OPTIONS:
return jsonify({"success": False, "error": "无效执行环境,仅支持 sandbox / direct"}), 400
# 判断当前是否在对话运行期间
is_running = False
try:
from .tasks import task_manager
current_conv = getattr(getattr(terminal, "context_manager", None), "current_conversation_id", None)
running_tasks = [
r for r in task_manager.list_tasks(username) if r.status in {"pending", "running", "cancel_requested"}
]
if current_conv:
running_tasks.sort(key=lambda r: 0 if r.conversation_id == current_conv else 1)
is_running = bool(running_tasks)
except Exception:
pass
if is_running:
# 运行期间:使用 pending 机制延迟到工具循环中统一处理,
# 避免「A→B→A」来回切换时中间值被覆盖后仍插入多余消息。
try:
terminal.queue_execution_mode_change(target_mode)
except Exception as exc:
return jsonify({"success": False, "error": str(exc), "message": "更新执行环境失败"}), 500
status = terminal.get_status()
socketio.emit('status_update', status, room=f"user_{username}")
return jsonify({
"success": True,
"state": {
**(terminal.get_execution_mode_state() if hasattr(terminal, "get_execution_mode_state") else {"mode": target_mode}),
"mode": target_mode,
},
"pending_mode": target_mode,
"options": EXECUTION_MODE_OPTIONS,
"message": "执行环境将在当前工具执行完成后生效",
})
# 空闲期间:直接生效
previous_mode = terminal.get_execution_mode() if hasattr(terminal, "get_execution_mode") else None
try:
state = terminal.set_execution_mode(target_mode)