refactor(cleanup): 移除余额查询功能、清理前端调试日志、规整终端输出

This commit is contained in:
JOJO 2026-07-25 12:07:04 +08:00
parent bb420b0d04
commit cf51ab0555
59 changed files with 169 additions and 1051 deletions

View File

@ -147,11 +147,6 @@ docker build -f docker/terminal.Dockerfile -t my-agent-shell:latest .
}, },
"models": { "default_response_max_tokens": 32768 }, "models": { "default_response_max_tokens": 32768 },
"search": { "tavily_api_key": "", "tavily_api_key_2": "" }, "search": { "tavily_api_key": "", "tavily_api_key_2": "" },
"balance": {
"aliyun_access_key_id": "",
"aliyun_access_key_secret": "",
"usd_cny_rate": 7.1
},
"env_vars": { "env_vars": {
"API_BASE_KIMI": "https://api.moonshot.cn/v1", "API_BASE_KIMI": "https://api.moonshot.cn/v1",
"API_KEY_KIMI": "sk-..." "API_KEY_KIMI": "sk-..."
@ -174,7 +169,6 @@ docker build -f docker/terminal.Dockerfile -t my-agent-shell:latest .
| `secrets.api_token_secret` | `API_TOKEN_SECRET` | API Token 加密密钥(随机 hex | | `secrets.api_token_secret` | `API_TOKEN_SECRET` | API Token 加密密钥(随机 hex |
| `models.default_response_max_tokens` | `AGENT_DEFAULT_RESPONSE_MAX_TOKENS` | 单轮响应 token 全局上限 | | `models.default_response_max_tokens` | `AGENT_DEFAULT_RESPONSE_MAX_TOKENS` | 单轮响应 token 全局上限 |
| `search.tavily_api_key(_2)` | `AGENT_TAVILY_API_KEY(_2)` | Tavily 搜索 Key可选 | | `search.tavily_api_key(_2)` | `AGENT_TAVILY_API_KEY(_2)` | Tavily 搜索 Key可选 |
| `balance.aliyun_*` / `balance.usd_cny_rate` | `ALIYUN_ACCESS_KEY_ID` 等 | 可选:阿里云余额查询 |
| `env_vars.*` | 原样注入 | 任意环境变量API Key、沙箱参数等 | | `env_vars.*` | 原样注入 | 任意环境变量API Key、沙箱参数等 |
> ⚠️ **以下字段已弃用/无效**,存在于旧配置中可删除: > ⚠️ **以下字段已弃用/无效**,存在于旧配置中可删除:

View File

@ -74,9 +74,6 @@ def _load_dotenv():
"secrets.api_token_secret": "API_TOKEN_SECRET", "secrets.api_token_secret": "API_TOKEN_SECRET",
"search.tavily_api_key": "AGENT_TAVILY_API_KEY", "search.tavily_api_key": "AGENT_TAVILY_API_KEY",
"search.tavily_api_key_2": "AGENT_TAVILY_API_KEY_2", "search.tavily_api_key_2": "AGENT_TAVILY_API_KEY_2",
"balance.aliyun_access_key_id": "ALIYUN_ACCESS_KEY_ID",
"balance.aliyun_access_key_secret": "ALIYUN_ACCESS_KEY_SECRET",
"balance.usd_cny_rate": "USD_CNY_RATE",
"models.default_response_max_tokens": "AGENT_DEFAULT_RESPONSE_MAX_TOKENS", "models.default_response_max_tokens": "AGENT_DEFAULT_RESPONSE_MAX_TOKENS",
} }
for dotted_key, env_name in _LEGACY_MAP.items(): for dotted_key, env_name in _LEGACY_MAP.items():

View File

@ -823,7 +823,7 @@ class MainTerminalCommandMixin:
if not profile.get("fast_only"): if not profile.get("fast_only"):
self._mode_before_fast_only = None self._mode_before_fast_only = None
try: try:
logger.info( logger.debug(
"[ModelSwitch] model=%s run_mode=%s thinking=%s fast_only=%s thinking_only=%s", "[ModelSwitch] model=%s run_mode=%s thinking=%s fast_only=%s thinking_only=%s",
self.model_key, self.model_key,
self.run_mode, self.run_mode,

View File

@ -153,24 +153,13 @@ class ToolsDefinitionMainMixin:
if tool.get("function", {}).get("name") not in self.disabled_tools if tool.get("function", {}).get("name") not in self.disabled_tools
] ]
# 调试日志:记录工具列表 # 调试日志:记录工具列表DEBUG 级,不上终端)
tool_names = [t.get("function", {}).get("name") for t in tools] tool_names = [t.get("function", {}).get("name") for t in tools]
logger.info("[define_tools] 可用工具列表: %s", tool_names) logger.debug("[define_tools] 可用工具列表: %s", tool_names)
print(f"[DEBUG] define_tools: 工具数量={len(tools)}")
# 检查personalization分类状态
if hasattr(self, 'tool_categories_map') and 'personalization' in self.tool_categories_map:
cat = self.tool_categories_map['personalization']
state = self.tool_category_states.get('personalization', cat.default_enabled)
print(f"[DEBUG] personalization分类: default_enabled={cat.default_enabled}, current_state={state}")
else:
print(f"[DEBUG] personalization分类不在tool_categories_map中")
if "manage_personalization" in tool_names: if "manage_personalization" in tool_names:
logger.info("[define_tools] manage_personalization 工具已启用") logger.debug("[define_tools] manage_personalization 工具已启用")
print("[DEBUG] manage_personalization 在可用工具列表中")
else: else:
logger.warning("[define_tools] manage_personalization 工具未找到disabled_tools=%s", self.disabled_tools) logger.debug("[define_tools] manage_personalization 未启用: disabled_tools=%s", self.disabled_tools)
print(f"[DEBUG] manage_personalization 不在可用工具列表中disabled_tools={self.disabled_tools}")
return self._apply_intent_to_tools(tools) return self._apply_intent_to_tools(tools)

View File

@ -873,7 +873,7 @@ class MainTerminalToolsExecutionMixin:
async def handle_tool_call(self, tool_name: str, arguments: Dict) -> str: async def handle_tool_call(self, tool_name: str, arguments: Dict) -> str:
"""处理工具调用(添加参数预检查和改进错误处理)""" """处理工具调用(添加参数预检查和改进错误处理)"""
logger.info("[handle_tool_call] 工具调用开始: tool_name=%s, arguments=%s", tool_name, arguments) logger.debug("[handle_tool_call] 工具调用开始: tool_name=%s, arguments=%s", tool_name, arguments)
try: try:
if hasattr(self, "_apply_execution_mode_to_runtime"): if hasattr(self, "_apply_execution_mode_to_runtime"):
self._apply_execution_mode_to_runtime() self._apply_execution_mode_to_runtime()
@ -2176,13 +2176,12 @@ class MainTerminalToolsExecutionMixin:
logger.exception("[handle_tool_call] 工具执行异常详情") logger.exception("[handle_tool_call] 工具执行异常详情")
result = {"success": False, "error": f"工具执行异常: {str(e)}"} result = {"success": False, "error": f"工具执行异常: {str(e)}"}
logger.info("[handle_tool_call] 工具调用结束: tool_name=%s, result=%s", tool_name, result) logger.debug("[handle_tool_call] 工具调用结束: tool_name=%s, result=%s", tool_name, result)
return json.dumps(result, ensure_ascii=False) return json.dumps(result, ensure_ascii=False)
async def _execute_manage_personalization(self, arguments: Dict) -> Dict: async def _execute_manage_personalization(self, arguments: Dict) -> Dict:
"""执行个性化管理操作""" """执行个性化管理操作"""
print(f"[DEBUG] _execute_manage_personalization 被调用: {arguments}") logger.debug("[_execute_manage_personalization] 方法被调用: arguments=%s", arguments)
logger.info("[_execute_manage_personalization] 方法被调用: arguments=%s", arguments)
action = arguments.get("action") action = arguments.get("action")
logger.info("[_execute_manage_personalization] action=%s", action) logger.info("[_execute_manage_personalization] action=%s", action)
@ -2289,8 +2288,7 @@ class MainTerminalToolsExecutionMixin:
# 保存配置 # 保存配置
save_personalization_config(self.data_dir, config) save_personalization_config(self.data_dir, config)
print(f"[DEBUG] 配置已保存: field={field}, value={value}") logger.info("[_execute_manage_personalization] 配置已保存到文件: field=%s", field)
logger.info("[_execute_manage_personalization] 配置已保存到文件")
# 重新加载配置到当前终端 # 重新加载配置到当前终端
self.apply_personalization_preferences(config) self.apply_personalization_preferences(config)

View File

@ -6,6 +6,7 @@ from datetime import datetime
from typing import Any, Dict, List, Optional, Callable, TYPE_CHECKING from typing import Any, Dict, List, Optional, Callable, TYPE_CHECKING
import os import os
from core.main_terminal import MainTerminal from core.main_terminal import MainTerminal
from server.utils_common import debug_log
from utils.logger import setup_logger from utils.logger import setup_logger
from modules.personalization_manager import load_personalization_config from modules.personalization_manager import load_personalization_config
from modules.versioning_manager import ConversationVersioningManager, VersioningError from modules.versioning_manager import ConversationVersioningManager, VersioningError
@ -50,9 +51,9 @@ class WebTerminal(MainTerminal):
bound_id = f"conv_{bound_id}" bound_id = f"conv_{bound_id}"
result = self.load_conversation(bound_id, restore_model=True) result = self.load_conversation(bound_id, restore_model=True)
if result.get("success"): if result.get("success"):
print(f"[WebTerminal] 已加载绑定对话: {bound_id}") debug_log(f"[WebTerminal] 已加载绑定对话: {bound_id}")
else: else:
print(f"[WebTerminal] 警告:绑定对话 {bound_id} 加载失败: {result.get('message') or result.get('error')}") logger.warning("[WebTerminal] 绑定对话 %s 加载失败: %s", bound_id, result.get('message') or result.get('error'))
return return
latest_list = self.context_manager.get_conversation_list(limit=1, offset=0) latest_list = self.context_manager.get_conversation_list(limit=1, offset=0)
@ -64,14 +65,14 @@ class WebTerminal(MainTerminal):
if conv_id: if conv_id:
result = self.load_conversation(conv_id, restore_model=False) result = self.load_conversation(conv_id, restore_model=False)
if result.get("success"): if result.get("success"):
print(f"[WebTerminal] 已加载最近对话: {conv_id}") debug_log(f"[WebTerminal] 已加载最近对话: {conv_id}")
return return
conversation_id = self.context_manager.start_new_conversation( conversation_id = self.context_manager.start_new_conversation(
project_path=self.project_path, project_path=self.project_path,
thinking_mode=self.thinking_mode thinking_mode=self.thinking_mode
) )
print(f"[WebTerminal] 自动创建新对话: {conversation_id}") debug_log(f"[WebTerminal] 自动创建新对话: {conversation_id}")
def __init__( def __init__(
self, self,
@ -126,16 +127,16 @@ class WebTerminal(MainTerminal):
# 让 run_command 与实时终端共享同一容器环境 # 让 run_command 与实时终端共享同一容器环境
self.terminal_ops.attach_terminal_manager(self.terminal_manager) self.terminal_ops.attach_terminal_manager(self.terminal_manager)
print(f"[WebTerminal] 初始化完成,项目路径: {project_path}") debug_log(f"[WebTerminal] 初始化完成,项目路径: {project_path}")
print(f"[WebTerminal] 初始模式: {self.run_mode}") debug_log(f"[WebTerminal] 初始模式: {self.run_mode}")
print(f"[WebTerminal] 对话管理已就绪") debug_log(f"[WebTerminal] 对话管理已就绪")
# 设置token更新回调 # 设置token更新回调
if message_callback is not None: if message_callback is not None:
self.context_manager._web_terminal_callback = message_callback self.context_manager._web_terminal_callback = message_callback
print(f"[WebTerminal] 实时token统计已启用") debug_log(f"[WebTerminal] 实时token统计已启用")
else: else:
print(f"[WebTerminal] 警告:message_callback为None无法启用实时token统计") logger.warning("[WebTerminal] message_callback为None无法启用实时token统计")
# =========================================== # ===========================================
# 新增对话管理相关方法Web版本 # 新增对话管理相关方法Web版本
# =========================================== # ===========================================

15
main.py
View File

@ -27,7 +27,7 @@ class AgentSystem:
async def initialize(self): async def initialize(self):
"""初始化系统""" """初始化系统"""
print("\n" + "="*50) print("\n" + "="*50)
print("🤖 Astrion 启动") print("🤖 Astrion 启动")
print("="*50) print("="*50)
# 1. 获取项目路径 # 1. 获取项目路径
@ -123,25 +123,23 @@ class AgentSystem:
project_path = Path(path_input).resolve() project_path = Path(path_input).resolve()
if self.is_unsafe_path(str(project_path)): if self.is_unsafe_path(str(project_path)):
raise RuntimeError(f"默认项目路径不安全: {project_path}") raise RuntimeError(f"默认工作区路径不安全: {project_path}")
project_path.mkdir(parents=True, exist_ok=True) project_path.mkdir(parents=True, exist_ok=True)
if not os.access(project_path, os.R_OK | os.W_OK): if not os.access(project_path, os.R_OK | os.W_OK):
print(f"{OUTPUT_FORMATS['warning']} 对默认项目路径缺少读写权限: {project_path}") print(f"{OUTPUT_FORMATS['warning']} 对默认工作区路径缺少读写权限: {project_path}")
self.project_path = str(project_path) self.project_path = str(project_path)
print(f"{OUTPUT_FORMATS['success']} 已选择项目路径: {self.project_path}") print(f"{OUTPUT_FORMATS['info']} 默认工作区路径: {self.project_path}")
async def setup_run_mode(self): async def setup_run_mode(self):
"""选择运行模式""" """设置运行模式(当前统一入口默认 Web"""
self.web_mode = True self.web_mode = True
print(f"{OUTPUT_FORMATS['info']} 运行模式: Web默认")
async def setup_thinking_mode(self): async def setup_thinking_mode(self):
"""选择思考模式""" """设置默认思考模式(对话中可随时切换)"""
self.thinking_mode = True self.thinking_mode = True
print(f"{OUTPUT_FORMATS['info']} 思考模式: {'开启' if self.thinking_mode else '关闭'}(默认)")
async def init_system(self): async def init_system(self):
"""初始化系统文件""" """初始化系统文件"""
@ -194,7 +192,6 @@ class AgentSystem:
from web_server import run_server from web_server import run_server
print(f"\n{OUTPUT_FORMATS['success']} 正在启动Web服务器...") print(f"\n{OUTPUT_FORMATS['success']} 正在启动Web服务器...")
print(f"{OUTPUT_FORMATS['info']} 项目路径: {self.project_path}")
port = WEB_SERVER_PORT port = WEB_SERVER_PORT
# 运行服务器(这会阻塞) # 运行服务器(这会阻塞)

View File

@ -1,175 +0,0 @@
"""
Admin balance fetchers for Kimi (Moonshot), DeepSeek, and Qwen (Aliyun BSS).
Credentials (优先读取仓库根目录 .env其次环境变量):
- MOONSHOT_API_KEY : Bearer token for Kimi
- DEEPSEEK_API_KEY : Bearer token for DeepSeek
- ALIYUN_ACCESS_KEY_ID : AccessKey ID for Aliyun (Qwen billing)
- ALIYUN_ACCESS_KEY_SECRET : AccessKey Secret for Aliyun (Qwen billing)
- USD_CNY_RATE : Override USD->CNY rate (default 7.1)
"""
from __future__ import annotations
import base64
import hashlib
import hmac
import json
import os
import time
import uuid
from pathlib import Path
from typing import Any, Dict, Tuple
from urllib import parse, request
# -------- .env 读取助手(简化版,已由 config/__init__.py 统一注入) --------
def _env(key: str, default: str | None = None) -> str | None:
"""从环境变量获取配置。"""
if key in os.environ:
return os.environ[key]
return default
USD_CNY_RATE = float(_env("USD_CNY_RATE", "7.1") or "7.1")
def _http_get(url: str, headers: Dict[str, str] | None = None, timeout: int = 8) -> Tuple[Dict[str, Any] | None, str | None]:
"""Perform a simple GET request, return (json, error_message)."""
req = request.Request(url, headers=headers or {})
try:
with request.urlopen(req, timeout=timeout) as resp:
data = resp.read()
return json.loads(data.decode("utf-8")), None
except Exception as exc: # broad: network/parsing errors
return None, str(exc)
# -------- Kimi (Moonshot) --------
def fetch_kimi_balance() -> Dict[str, Any]:
api_key = _env("MOONSHOT_API_KEY") or _env("API_KEY_KIMI") or _env("AGENT_API_KEY")
if not api_key:
return {"success": False, "error": "Kimi 密钥未设置MOONSHOT_API_KEY / API_KEY_KIMI / AGENT_API_KEY"}
base = (
_env("API_BASE_KIMI")
or _env("MOONSHOT_BASE_URL")
or _env("AGENT_API_BASE_URL")
or "https://api.moonshot.ai/v1"
).rstrip("/")
url = f"{base}/users/me/balance"
payload, err = _http_get(url, headers={"Authorization": f"Bearer {api_key}"})
if err:
return {"success": False, "error": err}
try:
data = payload.get("data") or {}
available = float(data.get("available_balance", 0))
voucher = float(data.get("voucher_balance", 0))
cash = float(data.get("cash_balance", 0))
return {
"success": True,
"currency": payload.get("currency") or "CNY",
"available": available,
"voucher": voucher,
"cash": cash,
"raw": payload,
}
except Exception as exc: # pragma: no cover
return {"success": False, "error": f"解析失败: {exc}", "raw": payload}
# -------- DeepSeek --------
def fetch_deepseek_balance() -> Dict[str, Any]:
api_key = _env("DEEPSEEK_API_KEY") or _env("API_KEY_DEEPSEEK")
if not api_key:
return {"success": False, "error": "DeepSeek 密钥未设置DEEPSEEK_API_KEY / API_KEY_DEEPSEEK"}
url = "https://api.deepseek.com/user/balance"
payload, err = _http_get(url, headers={"Authorization": f"Bearer {api_key}"})
if err:
return {"success": False, "error": err}
try:
infos = payload.get("balance_infos") or []
primary = infos[0] if infos else {}
total = float(primary.get("total_balance") or 0)
granted = float(primary.get("granted_balance") or 0)
topped_up = float(primary.get("topped_up_balance") or 0)
return {
"success": True,
"currency": primary.get("currency", "CNY"),
"available": total,
"granted": granted,
"topped_up": topped_up,
"raw": payload,
}
except Exception as exc: # pragma: no cover
return {"success": False, "error": f"解析失败: {exc}", "raw": payload}
# -------- Qwen (Aliyun BSS QueryAccountBalance) --------
def _percent_encode(val: str) -> str:
res = parse.quote(str(val), safe="~")
return res.replace("+", "%20").replace("*", "%2A").replace("%7E", "~")
def _sign(params: Dict[str, Any], secret: str) -> str:
sorted_params = sorted(params.items(), key=lambda x: x[0])
canonicalized = "&".join(f"{_percent_encode(k)}={_percent_encode(v)}" for k, v in sorted_params)
string_to_sign = f"GET&%2F&{_percent_encode(canonicalized)}"
h = hmac.new((secret + "&").encode("utf-8"), string_to_sign.encode("utf-8"), hashlib.sha1)
return base64.b64encode(h.digest()).decode("utf-8")
def fetch_qwen_balance() -> Dict[str, Any]:
ak = _env("ALIYUN_ACCESS_KEY_ID")
sk = _env("ALIYUN_ACCESS_KEY_SECRET")
if not ak or not sk:
return {"success": False, "error": "缺少 ALIYUN_ACCESS_KEY_ID / ALIYUN_ACCESS_KEY_SECRET"}
params: Dict[str, Any] = {
"Format": "JSON",
"Version": "2017-12-14",
"AccessKeyId": ak,
"SignatureMethod": "HMAC-SHA1",
"Timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
"SignatureVersion": "1.0",
"SignatureNonce": str(uuid.uuid4()),
"Action": "QueryAccountBalance",
"RegionId": "cn-hangzhou",
}
signature = _sign(params, sk)
params["Signature"] = signature
# 按阿里云规范组装最终查询字符串(不可用 urlencode 的 quote_plus
query = "&".join(f"{_percent_encode(k)}={_percent_encode(v)}" for k, v in params.items())
url = "https://business.aliyuncs.com/?" + query
payload, err = _http_get(url)
if err:
return {"success": False, "error": err}
try:
data = payload.get("Data") or {}
amount = float(data.get("AvailableAmount") or 0)
currency = data.get("Currency", "CNY")
return {
"success": True,
"currency": currency,
"available": amount,
"cash": float(data.get("AvailableCashAmount") or 0),
"raw": payload,
}
except Exception as exc: # pragma: no cover
return {"success": False, "error": f"解析失败: {exc}", "raw": payload}
def fetch_all_balances() -> Dict[str, Any]:
return {
"rate_usd_cny": USD_CNY_RATE,
"kimi": fetch_kimi_balance(),
"deepseek": fetch_deepseek_balance(),
"qwen": fetch_qwen_balance(),
}

View File

@ -1,4 +1,15 @@
"""Web server package entry.""" """Web server package entry.
from .app import app, socketio, run_server, parse_arguments, initialize_system, resource_busy_page
使用 PEP 562 惰性导入避免 `python -m server.app` 时因包级提前 import
导致 'server.app' 被加载两次runpy RuntimeWarning
"""
import importlib
__all__ = ["app", "socketio", "run_server", "parse_arguments", "initialize_system", "resource_busy_page"] __all__ = ["app", "socketio", "run_server", "parse_arguments", "initialize_system", "resource_busy_page"]
def __getattr__(name):
if name in __all__:
module = importlib.import_module(".app", __name__)
return getattr(module, name)
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

View File

@ -28,7 +28,7 @@ from .conversation import (
summarize_upload_events, summarize_upload_events,
) )
from .conversation_stats import summarize_invite_codes from .conversation_stats import summarize_invite_codes
from modules import admin_policy_manager, balance_client from modules import admin_policy_manager
from collections import Counter from collections import Counter
from config import ADMIN_SECONDARY_PASSWORD_HASH, ADMIN_SECONDARY_PASSWORD, ADMIN_SECONDARY_TTL_SECONDS from config import ADMIN_SECONDARY_PASSWORD_HASH, ADMIN_SECONDARY_PASSWORD, ADMIN_SECONDARY_TTL_SECONDS
@ -126,18 +126,6 @@ def admin_secondary_verify():
return jsonify({"success": True, "ttl": ADMIN_SECONDARY_TTL_SECONDS}) return jsonify({"success": True, "ttl": ADMIN_SECONDARY_TTL_SECONDS})
@admin_bp.route('/api/admin/balance', methods=['GET'])
@login_required
@admin_required
def admin_balance_api():
"""查询第三方账户余额Kimi/DeepSeek/Qwen"""
guard = _secondary_required()
if guard:
return guard
data = balance_client.fetch_all_balances()
return jsonify({"success": True, "data": data})
@admin_bp.route('/admin/assets/<path:filename>') @admin_bp.route('/admin/assets/<path:filename>')
@login_required @login_required
@admin_required @admin_required

View File

@ -1,5 +1,8 @@
# web_server.py - Web服务器修复版 - 确保text_end事件正确发送 + 停止功能) # web_server.py - Web服务器修复版 - 确保text_end事件正确发送 + 停止功能)
import os as _os_early
_os_early.environ.setdefault('FLASK_SKIP_DOTENV', '1') # 抑制 Flask 的 python-dotenv 提示(项目自带 .env 解析)
import asyncio import asyncio
import json import json
import os import os
@ -21,7 +24,7 @@ import time
from datetime import datetime from datetime import datetime
from collections import defaultdict, deque, Counter from collections import defaultdict, deque, Counter
from config.model_profiles import get_default_model_key, get_model_profile, get_registered_model_keys from config.model_profiles import get_default_model_key, get_model_profile, get_registered_model_keys
from modules import admin_policy_manager, balance_client from modules import admin_policy_manager
from modules.custom_tool_registry import CustomToolRegistry from modules.custom_tool_registry import CustomToolRegistry
import server.state as state # 共享单例 import server.state as state # 共享单例
from server.auth import auth_bp from server.auth import auth_bp
@ -221,6 +224,7 @@ from config import (
DEFAULT_CONVERSATIONS_LIMIT, DEFAULT_CONVERSATIONS_LIMIT,
MAX_CONVERSATIONS_LIMIT, MAX_CONVERSATIONS_LIMIT,
CONVERSATIONS_DIR, CONVERSATIONS_DIR,
DATA_DIR,
DEFAULT_RESPONSE_MAX_TOKENS, DEFAULT_RESPONSE_MAX_TOKENS,
DEFAULT_PROJECT_PATH, DEFAULT_PROJECT_PATH,
LOGS_DIR, LOGS_DIR,
@ -231,6 +235,7 @@ from config import (
UPLOAD_SCAN_LOG_SUBDIR, UPLOAD_SCAN_LOG_SUBDIR,
WEB_SERVER_PORT, WEB_SERVER_PORT,
WEB_SERVER_HOST, WEB_SERVER_HOST,
TERMINAL_SANDBOX_MODE,
) )
from modules.user_manager import UserManager, UserWorkspace from modules.user_manager import UserManager, UserWorkspace
from modules.gui_file_manager import GuiFileManager from modules.gui_file_manager import GuiFileManager
@ -251,7 +256,7 @@ app.config['MAX_CONTENT_LENGTH'] = MAX_UPLOAD_SIZE
_secret_key = os.environ.get("WEB_SECRET_KEY") or os.environ.get("SECRET_KEY") _secret_key = os.environ.get("WEB_SECRET_KEY") or os.environ.get("SECRET_KEY")
if not _secret_key: if not _secret_key:
_secret_key = secrets.token_hex(32) _secret_key = secrets.token_hex(32)
print("[security] WEB_SECRET_KEY 未设置,已生成临时密钥(重启后失效)。") print(f"{OUTPUT_FORMATS['warning']} WEB_SECRET_KEY 未设置,已生成临时密钥(重启后所有会话将失效)。")
app.config['SECRET_KEY'] = _secret_key app.config['SECRET_KEY'] = _secret_key
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=12) app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=12)
_cookie_secure_env = (os.environ.get("WEB_COOKIE_SECURE") or "").strip().lower() _cookie_secure_env = (os.environ.get("WEB_COOKIE_SECURE") or "").strip().lower()
@ -1229,17 +1234,15 @@ def initialize_system(path: str, thinking_mode: bool = False):
DEBUG_LOG_FILE.parent.mkdir(parents=True, exist_ok=True) DEBUG_LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
with DEBUG_LOG_FILE.open('w', encoding='utf-8') as f: with DEBUG_LOG_FILE.open('w', encoding='utf-8') as f:
f.write(f"调试日志开始 - {datetime.now()}\n") f.write(f"调试日志开始 - {datetime.now()}\n")
f.write(f"项目路径: {path}\n") f.write(f"默认工作区路径: {path}\n")
f.write(f"思考模式: {'思考模式' if thinking_mode else '快速模式'}\n") f.write(f"默认思考模式: {'思考' if thinking_mode else '快速'}(对话中可切换)\n")
f.write(f"自动修复: {'开启' if AUTO_FIX_TOOL_CALL else '关闭'}\n") f.write(f"自动修复: {'开启' if AUTO_FIX_TOOL_CALL else '关闭'}\n")
f.write(f"最大迭代: {MAX_ITERATIONS_PER_TASK}\n") f.write(f"最大迭代: {MAX_ITERATIONS_PER_TASK}\n")
f.write(f"最大工具调用: {MAX_TOTAL_TOOL_CALLS}\n") f.write(f"最大工具调用: {MAX_TOTAL_TOOL_CALLS}\n")
f.write("="*80 + "\n") f.write("="*80 + "\n")
print(f"[Init] 初始化Web系统...") print(f"{OUTPUT_FORMATS['info']} 初始化 Web 系统...")
print(f"[Init] 项目路径: {path}") print(f"{OUTPUT_FORMATS['info']} 数据目录: {DATA_DIR}")
print(f"[Init] 运行模式: {'思考模式(首次思考,后续快速)' if thinking_mode else '快速模式(无思考)'}") print(f"{OUTPUT_FORMATS['info']} 调试日志: {DEBUG_LOG_FILE}")
print(f"[Init] 自动修复: {'开启' if AUTO_FIX_TOOL_CALL else '关闭'}")
print(f"[Init] 调试日志: {DEBUG_LOG_FILE}")
app.config['DEFAULT_THINKING_MODE'] = thinking_mode app.config['DEFAULT_THINKING_MODE'] = thinking_mode
app.config['DEFAULT_RUN_MODE'] = "thinking" if thinking_mode else "fast" app.config['DEFAULT_RUN_MODE'] = "thinking" if thinking_mode else "fast"
# 同步预设子智能体角色到运行态目录 # 同步预设子智能体角色到运行态目录
@ -1249,7 +1252,8 @@ def initialize_system(path: str, thinking_mode: bool = False):
print(f"{OUTPUT_FORMATS['success']} 预设子智能体角色同步完成") print(f"{OUTPUT_FORMATS['success']} 预设子智能体角色同步完成")
except Exception as _e: except Exception as _e:
print(f"{OUTPUT_FORMATS['warning']} 预设子智能体角色同步失败: {_e}") print(f"{OUTPUT_FORMATS['warning']} 预设子智能体角色同步失败: {_e}")
print(f"{OUTPUT_FORMATS['success']} Web系统初始化完成多用户模式") _mode_label = "宿主机模式(单用户)" if TERMINAL_SANDBOX_MODE == "host" else "多用户模式Web"
print(f"{OUTPUT_FORMATS['success']} Web 系统初始化完成({_mode_label}")
def run_server(path: str, thinking_mode: bool = False, port: int = DEFAULT_PORT, debug: bool = False): def run_server(path: str, thinking_mode: bool = False, port: int = DEFAULT_PORT, debug: bool = False):
@ -1276,7 +1280,7 @@ def parse_arguments():
parser.add_argument( parser.add_argument(
"--path", "--path",
default=str(Path(DEFAULT_PROJECT_PATH).resolve()), default=str(Path(DEFAULT_PROJECT_PATH).resolve()),
help="项目工作目录(默认使用 config.DEFAULT_PROJECT_PATH" help="默认工作区路径(仅作兜底,工作区可在界面中管理"
) )
parser.add_argument( parser.add_argument(
"--port", "--port",
@ -1292,7 +1296,7 @@ def parse_arguments():
parser.add_argument( parser.add_argument(
"--thinking-mode", "--thinking-mode",
action="store_true", action="store_true",
help="启用思考模式(首次请求使用 reasoning" help="新对话默认使用思考模式(对话中可随时切换"
) )
return parser.parse_args() return parser.parse_args()

View File

@ -1,6 +1,6 @@
from __future__ import annotations from __future__ import annotations
from server.chat import chat_bp from server.chat import chat_bp
import json, time import json, logging, time
from datetime import datetime from datetime import datetime
from typing import Dict, Any, Optional from typing import Dict, Any, Optional
from pathlib import Path from pathlib import Path
@ -8,6 +8,8 @@ from io import BytesIO
import zipfile import zipfile
import os import os
logger = logging.getLogger(__name__)
from flask import Blueprint, jsonify, request, session, send_file from flask import Blueprint, jsonify, request, session, send_file
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from werkzeug.exceptions import RequestEntityTooLarge from werkzeug.exceptions import RequestEntityTooLarge
@ -111,7 +113,7 @@ def update_thinking_mode(terminal: WebTerminal, workspace: UserWorkspace, userna
has_videos=getattr(ctx, "has_videos", False) has_videos=getattr(ctx, "has_videos", False)
) )
except Exception as exc: except Exception as exc:
print(f"[API] 保存思考模式到对话失败: {exc}") logger.error(f"[API] 保存思考模式到对话失败: {exc}")
status = terminal.get_status() status = terminal.get_status()
socketio.emit('status_update', status, room=f"user_{username}") socketio.emit('status_update', status, room=f"user_{username}")
@ -124,7 +126,7 @@ def update_thinking_mode(terminal: WebTerminal, workspace: UserWorkspace, userna
} }
}) })
except Exception as exc: except Exception as exc:
print(f"[API] 切换思考模式失败: {exc}") logger.error(f"[API] 切换思考模式失败: {exc}")
code = 400 if isinstance(exc, ValueError) else 500 code = 400 if isinstance(exc, ValueError) else 500
return jsonify({ return jsonify({
"success": False, "success": False,
@ -178,7 +180,7 @@ def update_reasoning_effort(terminal: WebTerminal, workspace: UserWorkspace, use
reasoning_effort=effort, reasoning_effort=effort,
) )
except Exception as exc: except Exception as exc:
print(f"[API] 保存推理强度到对话失败: {exc}") logger.error(f"[API] 保存推理强度到对话失败: {exc}")
status = terminal.get_status() status = terminal.get_status()
socketio.emit('status_update', status, room=f"user_{username}") socketio.emit('status_update', status, room=f"user_{username}")
@ -190,7 +192,7 @@ def update_reasoning_effort(terminal: WebTerminal, workspace: UserWorkspace, use
} }
}) })
except Exception as exc: except Exception as exc:
print(f"[API] 设置推理强度失败: {exc}") logger.error(f"[API] 设置推理强度失败: {exc}")
code = 400 if isinstance(exc, ValueError) else 500 code = 400 if isinstance(exc, ValueError) else 500
return jsonify({ return jsonify({
"success": False, "success": False,
@ -253,7 +255,7 @@ def update_model(terminal: WebTerminal, workspace: UserWorkspace, username: str)
has_videos=getattr(ctx, "has_videos", False) has_videos=getattr(ctx, "has_videos", False)
) )
except Exception as exc: except Exception as exc:
print(f"[API] 保存模型到对话失败: {exc}") logger.error(f"[API] 保存模型到对话失败: {exc}")
else: else:
print( print(
f"[API] 跳过模型保存:请求对话 {requested_cid} " f"[API] 跳过模型保存:请求对话 {requested_cid} "
@ -272,7 +274,7 @@ def update_model(terminal: WebTerminal, workspace: UserWorkspace, username: str)
} }
}) })
except Exception as exc: except Exception as exc:
print(f"[API] 切换模型失败: {exc}") logger.error(f"[API] 切换模型失败: {exc}")
code = 400 if isinstance(exc, ValueError) else 500 code = 400 if isinstance(exc, ValueError) else 500
return jsonify({"success": False, "error": str(exc), "message": str(exc)}), code return jsonify({"success": False, "error": str(exc), "message": str(exc)}), code

View File

@ -220,7 +220,6 @@ def process_message_task(terminal: WebTerminal, message: str, images, sender, cl
debug_log(f"错误恢复:保存对话状态失败: {save_error}") debug_log(f"错误恢复:保存对话状态失败: {save_error}")
# 原有的错误处理逻辑 # 原有的错误处理逻辑
print(f"[Task] 错误: {e}")
debug_log(f"任务处理错误: {e}") debug_log(f"任务处理错误: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()

View File

@ -9,7 +9,7 @@ from config.model_profiles import get_model_profile
from utils.token_usage import extract_usage_payload from utils.token_usage import extract_usage_payload
from .utils_common import debug_log, brief_log, log_backend_chunk from .utils_common import debug_log, log_backend_chunk
from .chat_flow_runner_helpers import extract_intent_from_partial from .chat_flow_runner_helpers import extract_intent_from_partial
from .chat_flow_task_support import wait_retry_delay, cancel_pending_tools from .chat_flow_task_support import wait_retry_delay, cancel_pending_tools
from .state import get_stop_flag, clear_stop_flag from .state import get_stop_flag, clear_stop_flag
@ -158,7 +158,7 @@ async def run_streaming_attempts(*, web_terminal, messages, tools, sender, clien
and detected_tool_intent.get(tool_id) != intent_value and detected_tool_intent.get(tool_id) != intent_value
): ):
detected_tool_intent[tool_id] = intent_value detected_tool_intent[tool_id] = intent_value
brief_log(f"[intent] 增量提取 {tool_name}: {intent_value}") debug_log(f"[intent] 增量提取 {tool_name}: {intent_value}")
sender('tool_intent', { sender('tool_intent', {
'id': tool_id, 'id': tool_id,
'name': tool_name, 'name': tool_name,
@ -185,10 +185,10 @@ async def run_streaming_attempts(*, web_terminal, messages, tools, sender, clien
intent_value = extract_intent_from_partial(arguments_str) intent_value = extract_intent_from_partial(arguments_str)
if intent_value: if intent_value:
detected_tool_intent[tool_id] = intent_value detected_tool_intent[tool_id] = intent_value
brief_log(f"[intent] 预提取 {tool_name}: {intent_value}") debug_log(f"[intent] 预提取 {tool_name}: {intent_value}")
# 立即发送工具准备中事件 # 立即发送工具准备中事件
brief_log(f"[tool] 准备调用 {tool_name} (id={tool_id}) intent={intent_value or '-'}") debug_log(f"[tool] 准备调用 {tool_name} (id={tool_id}) intent={intent_value or '-'}")
sender('tool_preparing', { sender('tool_preparing', {
'id': tool_id, 'id': tool_id,
'name': tool_name, 'name': tool_name,
@ -249,7 +249,7 @@ async def run_streaming_attempts(*, web_terminal, messages, tools, sender, clien
text_started = True text_started = True
text_streaming = True text_streaming = True
sender('text_start', {}) sender('text_start', {})
brief_log("模型输出了内容") debug_log("模型输出了内容")
await asyncio.sleep(0.05) await asyncio.sleep(0.05)
full_response += content full_response += content

View File

@ -1915,7 +1915,7 @@ async def handle_task_with_sender(
return return
tool_call_limit_label = MAX_TOTAL_TOOL_CALLS if MAX_TOTAL_TOOL_CALLS is not None else "" tool_call_limit_label = MAX_TOTAL_TOOL_CALLS if MAX_TOTAL_TOOL_CALLS is not None else ""
print(f"[API] 第{current_iteration}次调用 (总工具调用: {total_tool_calls}/{tool_call_limit_label})") debug_log(f"[API] 第{current_iteration}次调用 (总工具调用: {total_tool_calls}/{tool_call_limit_label})")
stream_result = await run_streaming_attempts( stream_result = await run_streaming_attempts(
web_terminal=web_terminal, web_terminal=web_terminal,

View File

@ -7,7 +7,7 @@ import uuid
from pathlib import Path from pathlib import Path
from typing import Optional, Dict, Any, List from typing import Optional, Dict, Any, List
from .utils_common import debug_log, brief_log from .utils_common import debug_log
from .state import MONITOR_FILE_TOOLS, MONITOR_MEMORY_TOOLS, MONITOR_SNAPSHOT_CHAR_LIMIT, MONITOR_MEMORY_ENTRY_LIMIT from .state import MONITOR_FILE_TOOLS, MONITOR_MEMORY_TOOLS, MONITOR_SNAPSHOT_CHAR_LIMIT, MONITOR_MEMORY_ENTRY_LIMIT
from .state import tool_approval_manager, user_question_manager from .state import tool_approval_manager, user_question_manager
from .monitor import cache_monitor_snapshot from .monitor import cache_monitor_snapshot
@ -726,7 +726,7 @@ async def execute_tool_calls(*, web_terminal, tool_calls, sender, messages, clie
'monitor_snapshot': monitor_snapshot, 'monitor_snapshot': monitor_snapshot,
'conversation_id': conversation_id 'conversation_id': conversation_id
}) })
brief_log(f"调用了工具: {function_name}") debug_log(f"调用了工具: {function_name}")
await asyncio.sleep(0.3) await asyncio.sleep(0.3)
start_time = time.time() start_time = time.time()

View File

@ -1,9 +1,12 @@
from __future__ import annotations from __future__ import annotations
import logging
import sys, os import sys, os
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
if PROJECT_ROOT not in sys.path: if PROJECT_ROOT not in sys.path:
sys.path.insert(0, PROJECT_ROOT) sys.path.insert(0, PROJECT_ROOT)
logger = logging.getLogger(__name__)
import asyncio, json, time, re, os, shutil import asyncio, json, time, re, os, shutil
from datetime import datetime, timedelta from datetime import datetime, timedelta
from pathlib import Path from pathlib import Path
@ -579,7 +582,7 @@ def get_conversations(terminal: WebTerminal, workspace: UserWorkspace, username:
}), 500 }), 500
except Exception as e: except Exception as e:
print(f"[API] 获取对话列表错误: {e}") logger.error(f"[API] 获取对话列表错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e), "error": str(e),
@ -754,7 +757,7 @@ def create_conversation(terminal: WebTerminal, workspace: UserWorkspace, usernam
return jsonify(result), 500 return jsonify(result), 500
except Exception as e: except Exception as e:
print(f"[API] 创建对话错误: {e}") logger.error(f"[API] 创建对话错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e), "error": str(e),
@ -793,7 +796,7 @@ def get_conversation_info(terminal: WebTerminal, workspace: UserWorkspace, usern
}), 404 }), 404
except Exception as e: except Exception as e:
print(f"[API] 获取对话信息错误: {e}") logger.error(f"[API] 获取对话信息错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e), "error": str(e),
@ -903,7 +906,7 @@ def load_conversation(conversation_id, terminal: WebTerminal, workspace: UserWor
except Exception as e: except Exception as e:
import traceback import traceback
print(f"[API] 加载对话错误: {e}") logger.error(f"[API] 加载对话错误: {e}")
traceback.print_exc() traceback.print_exc()
return jsonify({ return jsonify({
"success": False, "success": False,
@ -957,7 +960,7 @@ def delete_conversation(conversation_id, terminal: WebTerminal, workspace: UserW
return jsonify(result), 404 if "不存在" in result.get("message", "") else 500 return jsonify(result), 404 if "不存在" in result.get("message", "") else 500
except Exception as e: except Exception as e:
print(f"[API] 删除对话错误: {e}") logger.error(f"[API] 删除对话错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e), "error": str(e),
@ -1033,12 +1036,12 @@ def search_conversations(terminal: WebTerminal, workspace: UserWorkspace, userna
username, ws_id, terminal, workspace username, ws_id, terminal, workspace
) )
except (ValueError, RuntimeError) as resolve_err: except (ValueError, RuntimeError) as resolve_err:
print(f"[API] 搜索跳过工作区 {ws_id}: {resolve_err}") logger.error(f"[API] 搜索跳过工作区 {ws_id}: {resolve_err}")
continue continue
try: try:
result = target_terminal.search_conversations(query, limit, multi_agent_mode=multi_agent_filter) result = target_terminal.search_conversations(query, limit, multi_agent_mode=multi_agent_filter)
except Exception as search_err: except Exception as search_err:
print(f"[API] 搜索工作区对话失败 {ws_id}: {search_err}") logger.error(f"[API] 搜索工作区对话失败 {ws_id}: {search_err}")
continue continue
results = result.get("results") or [] results = result.get("results") or []
if not results: if not results:
@ -1061,7 +1064,7 @@ def search_conversations(terminal: WebTerminal, workspace: UserWorkspace, userna
}) })
except Exception as e: except Exception as e:
print(f"[API] 搜索对话错误: {e}") logger.error(f"[API] 搜索对话错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e), "error": str(e),
@ -1124,7 +1127,7 @@ def get_conversation_messages(conversation_id, terminal: WebTerminal, workspace:
}), 404 }), 404
except Exception as e: except Exception as e:
print(f"[API] 获取对话消息错误: {e}") logger.error(f"[API] 获取对话消息错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e), "error": str(e),
@ -1763,7 +1766,7 @@ def compress_conversation(conversation_id, terminal: WebTerminal, workspace: Use
return jsonify(response_payload) return jsonify(response_payload)
except Exception as e: except Exception as e:
print(f"[API] 压缩对话错误: {e}") logger.error(f"[API] 压缩对话错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e), "error": str(e),
@ -2208,7 +2211,7 @@ def duplicate_conversation(conversation_id, terminal: WebTerminal, workspace: Us
return jsonify(response_payload) return jsonify(response_payload)
except Exception as e: except Exception as e:
print(f"[API] 复制对话错误: {e}") logger.error(f"[API] 复制对话错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e), "error": str(e),
@ -2251,7 +2254,7 @@ def review_conversation_preview(conversation_id, terminal: WebTerminal, workspac
} }
}) })
except Exception as e: except Exception as e:
print(f"[API] 对话回顾预览错误: {e}") logger.error(f"[API] 对话回顾预览错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e), "error": str(e),
@ -2307,7 +2310,7 @@ def review_conversation(conversation_id, terminal: WebTerminal, workspace: UserW
} }
}) })
except Exception as e: except Exception as e:
print(f"[API] 对话回顾生成错误: {e}") logger.error(f"[API] 对话回顾生成错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e), "error": str(e),
@ -2328,7 +2331,7 @@ def get_conversations_statistics(terminal: WebTerminal, workspace: UserWorkspace
}) })
except Exception as e: except Exception as e:
print(f"[API] 获取对话统计错误: {e}") logger.error(f"[API] 获取对话统计错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e), "error": str(e),
@ -2377,7 +2380,7 @@ def get_current_conversation(terminal: WebTerminal, workspace: UserWorkspace, us
}), 404 }), 404
except Exception as e: except Exception as e:
print(f"[API] 获取当前对话错误: {e}") logger.error(f"[API] 获取当前对话错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e) "error": str(e)
@ -2490,7 +2493,7 @@ def get_conversation_token_statistics(conversation_id, terminal: WebTerminal, wo
}), 404 }), 404
except Exception as e: except Exception as e:
print(f"[API] 获取token统计错误: {e}") logger.error(f"[API] 获取token统计错误: {e}")
return jsonify({ return jsonify({
"success": False, "success": False,
"error": str(e), "error": str(e),

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
import json import json
import logging
import os import os
import time import time
from collections import Counter, deque from collections import Counter, deque
@ -8,6 +9,8 @@ from datetime import datetime, timedelta
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional
logger = logging.getLogger(__name__)
from modules.user_manager import UserWorkspace from modules.user_manager import UserWorkspace
from modules.usage_tracker import QUOTA_DEFAULTS from modules.usage_tracker import QUOTA_DEFAULTS
from utils.conversation_manager import ConversationManager from utils.conversation_manager import ConversationManager
@ -131,7 +134,7 @@ def _read_token_totals_file(workspace: UserWorkspace) -> Dict[str, int]:
"total_tokens": total_tokens, "total_tokens": total_tokens,
} }
except (OSError, json.JSONDecodeError, ValueError) as exc: except (OSError, json.JSONDecodeError, ValueError) as exc:
print(f"[admin] 解析 token_totals.json 失败 ({workspace.username}): {exc}") logger.error(f"[admin] 解析 token_totals.json 失败 ({workspace.username}): {exc}")
return {"input_tokens": 0, "output_tokens": 0, "total_tokens": 0} return {"input_tokens": 0, "output_tokens": 0, "total_tokens": 0}
def _collect_conversation_token_totals(workspace: UserWorkspace) -> Dict[str, int]: def _collect_conversation_token_totals(workspace: UserWorkspace) -> Dict[str, int]:
@ -148,7 +151,7 @@ def _collect_conversation_token_totals(workspace: UserWorkspace) -> Dict[str, in
"total_tokens": total_tokens, "total_tokens": total_tokens,
} }
except Exception as exc: except Exception as exc:
print(f"[admin] 读取 legacy token 统计失败 ({workspace.username}): {exc}") logger.error(f"[admin] 读取 legacy token 统计失败 ({workspace.username}): {exc}")
return {"input_tokens": 0, "output_tokens": 0, "total_tokens": 0} return {"input_tokens": 0, "output_tokens": 0, "total_tokens": 0}
def collect_user_token_statistics(workspace: UserWorkspace) -> Dict[str, int]: def collect_user_token_statistics(workspace: UserWorkspace) -> Dict[str, int]:

View File

@ -23,7 +23,7 @@ from config.model_profiles import model_supports_image, model_supports_video
@socketio.on('connect') @socketio.on('connect')
def handle_connect(auth): def handle_connect(auth):
"""客户端连接""" """客户端连接"""
print(f"[WebSocket] 客户端连接: {request.sid}") debug_log(f"[WebSocket] 客户端连接: {request.sid}")
username = get_current_username() username = get_current_username()
token_value = (auth or {}).get('socket_token') if isinstance(auth, dict) else None token_value = (auth or {}).get('socket_token') if isinstance(auth, dict) else None
if not username or not consume_socket_token(token_value, username): if not username or not consume_socket_token(token_value, username):
@ -75,7 +75,7 @@ def handle_connect(auth):
@socketio.on('disconnect') @socketio.on('disconnect')
def handle_disconnect(): def handle_disconnect():
"""客户端断开""" """客户端断开"""
print(f"[WebSocket] 客户端断开: {request.sid}") debug_log(f"[WebSocket] 客户端断开: {request.sid}")
username = connection_users.pop(request.sid, None) username = connection_users.pop(request.sid, None)
# 若同一用户仍有其他活跃连接,不因断开而停止任务 # 若同一用户仍有其他活跃连接,不因断开而停止任务
has_other_connection = False has_other_connection = False
@ -127,7 +127,7 @@ def handle_disconnect():
@socketio.on('stop_task') @socketio.on('stop_task')
def handle_stop_task(): def handle_stop_task():
"""处理停止任务请求""" """处理停止任务请求"""
print(f"[停止] 收到停止请求: {request.sid}") debug_log(f"[停止] 收到停止请求: {request.sid}")
username = connection_users.get(request.sid) username = connection_users.get(request.sid)
task_info = get_stop_flag(request.sid, username) task_info = get_stop_flag(request.sid, username)
if not isinstance(task_info, dict): if not isinstance(task_info, dict):
@ -172,7 +172,7 @@ def handle_terminal_subscribe(data):
room_name = f"user_{username}_terminal" room_name = f"user_{username}_terminal"
join_room(room_name) join_room(room_name)
terminal_rooms[request.sid].add(room_name) terminal_rooms[request.sid].add(room_name)
print(f"[Terminal] {request.sid} 订阅所有终端事件") debug_log(f"[Terminal] {request.sid} 订阅所有终端事件")
# 发送当前终端状态 # 发送当前终端状态
emit('terminal_subscribed', { emit('terminal_subscribed', {
@ -184,7 +184,7 @@ def handle_terminal_subscribe(data):
room_name = f'user_{username}_terminal_{session_name}' room_name = f'user_{username}_terminal_{session_name}'
join_room(room_name) join_room(room_name)
terminal_rooms[request.sid].add(room_name) terminal_rooms[request.sid].add(room_name)
print(f"[Terminal] {request.sid} 订阅终端: {session_name}") debug_log(f"[Terminal] {request.sid} 订阅终端: {session_name}")
# 发送该终端的当前输出 # 发送该终端的当前输出
output_result = terminal.terminal_manager.get_terminal_output(session_name, 100) output_result = terminal.terminal_manager.get_terminal_output(session_name, 100)
@ -205,7 +205,7 @@ def handle_terminal_unsubscribe(data):
leave_room(room_name) leave_room(room_name)
if request.sid in terminal_rooms: if request.sid in terminal_rooms:
terminal_rooms[request.sid].discard(room_name) terminal_rooms[request.sid].discard(room_name)
print(f"[Terminal] {request.sid} 取消订阅终端: {session_name}") debug_log(f"[Terminal] {request.sid} 取消订阅终端: {session_name}")
@socketio.on('get_terminal_output') @socketio.on('get_terminal_output')
def handle_get_terminal_output(data): def handle_get_terminal_output(data):
@ -279,7 +279,7 @@ def handle_message(data):
emit('error', {'message': '图片和视频请分开发送'}) emit('error', {'message': '图片和视频请分开发送'})
return return
print(f"[WebSocket] 收到消息: {message}") debug_log(f"[WebSocket] 收到消息: {message}")
debug_log(f"\n{'='*80}\n新任务开始: {message}\n{'='*80}") debug_log(f"\n{'='*80}\n新任务开始: {message}\n{'='*80}")
record_user_activity(username) record_user_activity(username)

View File

@ -272,55 +272,6 @@
</li> </li>
</ul> </ul>
</section> </section>
<section v-else-if="activeSection === 'balance'" key="balance" class="panel">
<div class="balance-header">
<div>
<h2>余额查询</h2>
<p class="muted">手动刷新查看 Kimi / DeepSeek / Qwen 余额</p>
</div>
<div class="balance-actions">
<span class="muted" v-if="balanceUpdatedAt"
>上次刷新{{ timeAgo(balanceUpdatedAt) }}</span
>
<button type="button" :disabled="balanceLoading" @click="fetchBalance">
{{ balanceLoading ? '查询中...' : '手动刷新' }}
</button>
</div>
</div>
<section v-if="balanceError" class="banner-error">
<strong>查询失败</strong>
<span>{{ balanceError }}</span>
</section>
<div class="balance-grid">
<div
v-for="card in balanceCards"
:key="card.key"
class="balance-card"
:class="{ error: !card.success }"
>
<div class="balance-card-head">
<h3>{{ card.label }}</h3>
<span v-if="card.success" class="status-badge online">正常</span>
<span v-else class="status-badge danger">失败</span>
</div>
<div class="balance-amount">
<strong v-if="card.amount !== null">{{ card.amount }} {{ card.currency }}</strong>
<strong v-else></strong>
<span v-if="card.amountCny !== null" class="sub"> ¥{{ card.amountCny }}</span>
</div>
<ul class="balance-meta" v-if="card.success">
<li v-if="card.extras.voucher !== undefined">{{ card.extras.voucher }}</li>
<li v-if="card.extras.cash !== undefined">现金{{ card.extras.cash }}</li>
<li v-if="card.extras.granted !== undefined">赠送{{ card.extras.granted }}</li>
<li v-if="card.extras.topped_up !== undefined">
充值{{ card.extras.topped_up }}
</li>
<li v-if="card.extras.rate">汇率 USDCNY{{ card.extras.rate }}</li>
</ul>
<p v-else class="muted small">{{ card.error || '未知错误' }}</p>
</div>
</div>
</section>
<section v-else-if="activeSection === 'invites'" key="invites" class="panel"> <section v-else-if="activeSection === 'invites'" key="invites" class="panel">
<h2>邀请码</h2> <h2>邀请码</h2>
<div class="stats-row"> <div class="stats-row">
@ -478,7 +429,7 @@ import { useSecondaryPass } from './useSecondaryPass';
type Snapshot = Record<string, any> | null; type Snapshot = Record<string, any> | null;
type SectionId = 'overview' | 'usage' | 'users' | 'containers' | 'uploads' | 'balance' | 'invites' | 'passwords'; type SectionId = 'overview' | 'usage' | 'users' | 'containers' | 'uploads' | 'invites' | 'passwords';
const { const {
verified: secondaryVerified, verified: secondaryVerified,
@ -497,10 +448,6 @@ const bannerError = ref<string | null>(null);
const autoRefresh = ref(true); const autoRefresh = ref(true);
const activeSection = ref<SectionId>('overview'); const activeSection = ref<SectionId>('overview');
let timer: number | undefined; let timer: number | undefined;
const balanceLoading = ref(false);
const balanceError = ref<string | null>(null);
const balanceData = ref<Record<string, any> | null>(null);
const balanceUpdatedAt = ref<number | null>(null);
const inviteSubmitting = ref(false); const inviteSubmitting = ref(false);
const inviteError = ref<string | null>(null); const inviteError = ref<string | null>(null);
const newInviteCode = ref(''); const newInviteCode = ref('');
@ -522,7 +469,6 @@ const sectionTabs: Array<{ id: SectionId; label: string }> = [
{ id: 'users', label: '用户' }, { id: 'users', label: '用户' },
{ id: 'containers', label: '容器' }, { id: 'containers', label: '容器' },
{ id: 'uploads', label: '上传审计' }, { id: 'uploads', label: '上传审计' },
{ id: 'balance', label: '余额查询' },
{ id: 'invites', label: '邀请码' }, { id: 'invites', label: '邀请码' },
{ id: 'passwords', label: '密码管理' } { id: 'passwords', label: '密码管理' }
]; ];
@ -789,23 +735,6 @@ const removeInvite = async (code: string) => {
} }
}; };
const fetchBalance = async () => {
balanceLoading.value = true;
balanceError.value = null;
try {
const resp = await fetch('/api/admin/balance', { credentials: 'same-origin' });
if (!resp.ok) throw new Error(`请求失败:${resp.status}`);
const payload = await resp.json();
if (!payload.success) throw new Error(payload.error || '未知错误');
balanceData.value = payload.data || {};
balanceUpdatedAt.value = Date.now();
} catch (error) {
balanceError.value = error instanceof Error ? error.message : String(error);
} finally {
balanceLoading.value = false;
}
};
const handleVerifySecondary = async () => { const handleVerifySecondary = async () => {
await verifySecondary(secondaryPassword.value); await verifySecondary(secondaryPassword.value);
if (secondaryVerified.value) { if (secondaryVerified.value) {
@ -819,15 +748,6 @@ watch(autoRefresh, () => {
scheduleAutoRefresh(); scheduleAutoRefresh();
}); });
watch(
() => activeSection.value,
(val) => {
if (val === 'balance' && !balanceData.value && !balanceLoading.value) {
fetchBalance();
}
}
);
onMounted(async () => { onMounted(async () => {
document.addEventListener('click', handleClickOutside); document.addEventListener('click', handleClickOutside);
await checkSecondary(); await checkSecondary();
@ -891,36 +811,6 @@ const tokenBreakdown = computed(() => {
return list.sort((a, b) => b.total - a.total); return list.sort((a, b) => b.total - a.total);
}); });
const usdToCnyRate = computed(() => balanceData.value?.rate_usd_cny ?? null);
const balanceCards = computed(() => {
const makeCard = (key: string, label: string) => {
const data = (balanceData.value as any)?.[key] || {};
const success = data.success === true;
const currency = data.currency || '—';
const amount = data.available ?? data.total ?? null;
return {
key,
label,
success,
currency,
amount,
amountCny:
data.available_cny ??
(currency === 'USD' && usdToCnyRate.value && amount != null
? Math.round(amount * usdToCnyRate.value * 100) / 100
: null),
extras: data,
error: success ? null : data.error
};
};
return [
makeCard('kimi', 'Kimi'),
makeCard('deepseek', 'DeepSeek'),
makeCard('qwen', 'Qwen / Aliyun')
];
});
const metricCards = computed(() => [ const metricCards = computed(() => [
{ {
title: '注册用户', title: '注册用户',
@ -1593,70 +1483,6 @@ th {
box-shadow: none; box-shadow: none;
} }
.balance-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
}
.balance-actions {
display: flex;
align-items: center;
gap: 10px;
}
.balance-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 12px;
margin-top: 12px;
}
.balance-card {
border: 1px solid rgba(118, 103, 84, 0.2);
border-radius: 14px;
padding: 12px;
background: rgba(255, 255, 255, 0.9);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
.balance-card.error {
border-color: rgba(189, 93, 58, 0.4);
background: rgba(189, 93, 58, 0.08);
}
.balance-card-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
margin-bottom: 6px;
}
.balance-amount {
display: flex;
align-items: baseline;
gap: 8px;
margin-bottom: 8px;
}
.balance-amount .sub {
color: #6a5d4c;
font-size: 13px;
}
.balance-meta {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 4px;
color: #6a5d4c;
}
.small { .small {
font-size: 13px; font-size: 13px;
} }

View File

@ -229,35 +229,6 @@
</div> </div>
</section> </section>
<section class="panel">
<div class="balance-header">
<div>
<h3>余额查询</h3>
<p class="muted">Kimi / DeepSeek / Qwen</p>
</div>
<button type="button" :disabled="balanceLoading" @click="fetchBalance">
{{ balanceLoading ? '查询中...' : '刷新余额' }}
</button>
</div>
<div class="balance-grid">
<div
v-for="card in balanceCards"
:key="card.key"
class="balance-card"
:class="{ error: !card.success }"
>
<div class="balance-card-head">
<h4>{{ card.label }}</h4>
<span :class="['status-badge', card.success ? 'online' : 'danger']">
{{ card.success ? '正常' : '失败' }}
</span>
</div>
<strong>{{ card.amount ?? '—' }} {{ card.currency }}</strong>
<span class="muted small" v-if="card.amountCny"> ¥{{ card.amountCny }}</span>
<p class="muted small" v-else-if="card.error">{{ card.error }}</p>
</div>
</div>
</section>
</div> </div>
</template> </template>
@ -287,9 +258,6 @@ const creating = ref(false);
const createForm = ref({ username: '', note: '' }); const createForm = ref({ username: '', note: '' });
const createError = ref(''); const createError = ref('');
const balanceData = ref<Record<string, any> | null>(null);
const balanceLoading = ref(false);
const overview = computed(() => snapshot.value?.overview || {}); const overview = computed(() => snapshot.value?.overview || {});
const uploads = computed(() => snapshot.value?.uploads || {}); const uploads = computed(() => snapshot.value?.uploads || {});
const containerItems = computed(() => { const containerItems = computed(() => {
@ -303,22 +271,6 @@ const totalRequests = computed(() =>
) )
); );
const balanceCards = computed(() => {
const keys = ['kimi', 'deepseek', 'qwen'];
return keys.map((k) => {
const data = (balanceData.value as any)?.[k] || {};
return {
key: k,
label: k.toUpperCase(),
success: data.success === true,
amount: data.available ?? data.total ?? null,
amountCny: data.amount_cny ?? data.amountCny ?? null,
currency: data.currency || '',
error: data.error
};
});
});
const formatNumber = (val: any) => { const formatNumber = (val: any) => {
const num = Number(val || 0); const num = Number(val || 0);
return Number.isFinite(num) ? num.toLocaleString('zh-CN') : '0'; return Number.isFinite(num) ? num.toLocaleString('zh-CN') : '0';
@ -501,21 +453,6 @@ const copyToken = async (username: string) => {
} }
}; };
const fetchBalance = async () => {
if (!secondaryVerified.value) return;
balanceLoading.value = true;
try {
const resp = await fetch('/api/admin/balance', { credentials: 'same-origin' });
const data = await resp.json();
if (!resp.ok || !data.success) throw new Error(data.error || '查询失败');
balanceData.value = data.data;
} catch (err) {
console.error(err);
} finally {
balanceLoading.value = false;
}
};
const handleVerifySecondary = async () => { const handleVerifySecondary = async () => {
await verifySecondary(secondaryPassword.value); await verifySecondary(secondaryPassword.value);
if (secondaryVerified.value) { if (secondaryVerified.value) {
@ -754,37 +691,6 @@ td {
gap: 14px; gap: 14px;
} }
.balance-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-bottom: 12px;
}
.balance-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 10px;
}
.balance-card {
background: rgba(255, 255, 255, 0.92);
border: 1px solid rgba(44, 32, 19, 0.12);
border-radius: 14px;
padding: 12px;
}
.balance-card.error {
border-color: rgba(181, 71, 61, 0.35);
}
.balance-card-head {
display: flex;
align-items: center;
justify-content: space-between;
}
.error-text { .error-text {
color: #b5473d; color: #b5473d;
margin-top: 8px; margin-top: 8px;

View File

@ -62,17 +62,16 @@ function debugShowImageLog(event: string, payload: Record<string, any> = {}) {
} }
function isShowHtmlDebugEnabled() { function isShowHtmlDebugEnabled() {
if (typeof window === 'undefined') return true; if (typeof window === 'undefined') return false;
try { try {
const explicitFlag = (window as any).__SHOW_HTML_DEBUG__; const explicitFlag = (window as any).__SHOW_HTML_DEBUG__;
if (explicitFlag === false || explicitFlag === '0') return false;
if (explicitFlag === true || explicitFlag === '1') return true; if (explicitFlag === true || explicitFlag === '1') return true;
if (explicitFlag === false || explicitFlag === '0') return false;
const localFlag = window.localStorage?.getItem('showHtmlDebug'); const localFlag = window.localStorage?.getItem('showHtmlDebug');
if (localFlag === '0' || localFlag === 'false') return false;
if (localFlag === '1' || localFlag === 'true') return true; if (localFlag === '1' || localFlag === 'true') return true;
return true; return false;
} catch { } catch {
return true; return false;
} }
} }
@ -1042,7 +1041,8 @@ function getShowTagContainer() {
} }
function isLayoutDebugEnabled() { function isLayoutDebugEnabled() {
if (typeof window === 'undefined') return true; // 默认关闭:排障时通过 window.__LAYOUT_DEBUG__ = true 或 localStorage.layoutDebug = '1' 显式打开
if (typeof window === 'undefined') return false;
try { try {
const explicitFlag = (window as any).__LAYOUT_DEBUG__; const explicitFlag = (window as any).__LAYOUT_DEBUG__;
if (explicitFlag === false || explicitFlag === '0') return false; if (explicitFlag === false || explicitFlag === '0') return false;
@ -1050,9 +1050,9 @@ function isLayoutDebugEnabled() {
const localFlag = window.localStorage?.getItem('layoutDebug'); const localFlag = window.localStorage?.getItem('layoutDebug');
if (localFlag === '0' || localFlag === 'false') return false; if (localFlag === '0' || localFlag === 'false') return false;
if (localFlag === '1' || localFlag === 'true') return true; if (localFlag === '1' || localFlag === 'true') return true;
return true; return false;
} catch { } catch {
return true; return false;
} }
} }

View File

@ -23,7 +23,6 @@ export function created() {
export async function mounted() { export async function mounted() {
debugLog('Vue应用已挂载'); debugLog('Vue应用已挂载');
console.log('[DEBUG_SYSTEM][boot] 前端调试版本已加载 2026-04-05');
if (window.ensureCsrfToken) { if (window.ensureCsrfToken) {
window.ensureCsrfToken().catch((err) => { window.ensureCsrfToken().catch((err) => {
console.warn('CSRF token 初始化失败:', err); console.warn('CSRF token 初始化失败:', err);

View File

@ -25,8 +25,6 @@ export const traceLog = (...args) => {
function isGoalModeDebugEnabled() { function isGoalModeDebugEnabled() {
if (typeof window === 'undefined') return false; if (typeof window === 'undefined') return false;
try { try {
// 临时强制开启,用于调试多智能体消息轮询问题
return true;
const explicit = (window as any).__GOAL_MODE_DEBUG__; const explicit = (window as any).__GOAL_MODE_DEBUG__;
if (explicit === true || explicit === '1') return true; if (explicit === true || explicit === '1') return true;
if (explicit === false || explicit === '0') return false; if (explicit === false || explicit === '0') return false;

View File

@ -17,7 +17,6 @@ export const actionMethods = {
} }
}, },
async createNewConversation() { async createNewConversation() {
console.log('[DEBUG_AWAITING] ===== createNewConversation =====');
if (this.compressionInProgress || this.compressing) { if (this.compressionInProgress || this.compressing) {
const confirmed = await this.confirmAction({ const confirmed = await this.confirmAction({
title: '压缩进行中', title: '压缩进行中',

View File

@ -7,7 +7,6 @@ import {
export const stateMethods = { export const stateMethods = {
resetAllStates(reason = 'unspecified', options: { preserveMonitorWindows?: boolean } = {}) { resetAllStates(reason = 'unspecified', options: { preserveMonitorWindows?: boolean } = {}) {
console.log('[DEBUG_AWAITING] ===== resetAllStates =====', { reason });
// 如果正在等待子智能体完成,不重置任务状态 // 如果正在等待子智能体完成,不重置任务状态
if (this.waitingForSubAgent) { if (this.waitingForSubAgent) {
@ -74,11 +73,6 @@ export const stateMethods = {
generatingLabel: m.generatingLabel generatingLabel: m.generatingLabel
})); }));
console.log('[DEBUG_AWAITING] resetAllStates 清理完成', {
before: assistantMsgsBefore,
after: assistantMsgsAfter
});
// 清理Markdown缓存 // 清理Markdown缓存
if (this.markdownCache) { if (this.markdownCache) {
this.markdownCache.clear(); this.markdownCache.clear();

View File

@ -2,7 +2,6 @@
import { debugLog } from './common'; import { debugLog } from './common';
import { useQuickDockStore } from '../../stores/quickDock'; import { useQuickDockStore } from '../../stores/quickDock';
const jsonDebug = (...args: any[]) => { const jsonDebug = (...args: any[]) => {
console.log('[JSONDEBUG]', ...args);
}; };
const RESTORE_DEBUG_PREFIX = '[RESTORE_DEBUG]'; const RESTORE_DEBUG_PREFIX = '[RESTORE_DEBUG]';
const RESTORE_DEBUG_EVENTS = new Set([ const RESTORE_DEBUG_EVENTS = new Set([
@ -12,17 +11,16 @@ const RESTORE_DEBUG_EVENTS = new Set([
]); ]);
function isRestoreDebugEnabled() { function isRestoreDebugEnabled() {
if (typeof window === 'undefined') return true; if (typeof window === 'undefined') return false;
try { try {
const explicit = (window as any).__RESTORE_DEBUG__; const explicit = (window as any).__RESTORE_DEBUG__;
if (explicit === false || explicit === '0') return false;
if (explicit === true || explicit === '1') return true; if (explicit === true || explicit === '1') return true;
if (explicit === false || explicit === '0') return false;
const localFlag = window.localStorage?.getItem('restoreDebug'); const localFlag = window.localStorage?.getItem('restoreDebug');
if (localFlag === '0' || localFlag === 'false') return false;
if (localFlag === '1' || localFlag === 'true') return true; if (localFlag === '1' || localFlag === 'true') return true;
return true; return false;
} catch { } catch {
return true; return false;
} }
} }
@ -459,10 +457,6 @@ export const historyMethods = {
if (message.role === 'system') { if (message.role === 'system') {
const rawContent = message.content || ''; const rawContent = message.content || '';
const label = parseSystemNoticeLabel(rawContent); const label = parseSystemNoticeLabel(rawContent);
console.log('[DEBUG_SYSTEM][history] 命中 role=system 历史消息', {
rawContent,
matchedDoneNotice: !!label
});
if (label) { if (label) {
// 历史中的 system 通知转换为 assistant system action避免被 role=system 过滤掉 // 历史中的 system 通知转换为 assistant system action避免被 role=system 过滤掉
this.messages.push({ this.messages.push({
@ -485,9 +479,6 @@ export const historyMethods = {
generatingLabel: '' generatingLabel: ''
}); });
} else { } else {
console.log('[DEBUG_SYSTEM][history] role=system 被历史加载拦截(非子智能体完成)', {
rawContent
});
} }
return; return;
} }

View File

@ -97,7 +97,6 @@ export const sendMethods = {
} }
}, },
async sendMessage(options = {}) { async sendMessage(options = {}) {
console.log('[DEBUG_AWAITING] ===== sendMessage =====');
const presetText = typeof options?.presetText === 'string' ? options.presetText : null; const presetText = typeof options?.presetText === 'string' ? options.presetText : null;
const usePresetText = presetText !== null; const usePresetText = presetText !== null;
@ -417,7 +416,6 @@ export const sendMethods = {
return true; return true;
}, },
async stopTask() { async stopTask() {
console.log('[DEBUG_AWAITING] ===== stopTask =====');
if (this._stopTaskRunning) { if (this._stopTaskRunning) {
goalModeDebugLog('stopTask:debounce-rejected', { stopRequested: this.stopRequested }); goalModeDebugLog('stopTask:debounce-rejected', { stopRequested: this.stopRequested });
return; return;

View File

@ -21,22 +21,8 @@ import {
export const aiStreamMethods = { export const aiStreamMethods = {
handleAiMessageStart(data: any, eventIdx: number) { handleAiMessageStart(data: any, eventIdx: number) {
const lastMessage = this.messages[this.messages.length - 1]; const lastMessage = this.messages[this.messages.length - 1];
console.log('[DEBUG_AWAITING] ===== handleAiMessageStart =====', {
eventIdx,
lastMessageRole: lastMessage?.role,
lastMessageAwaitingFirstContent: lastMessage?.awaitingFirstContent,
lastMessageGeneratingLabel: lastMessage?.generatingLabel
});
debugLog('[TaskPolling] AI消息开始, idx:', eventIdx); debugLog('[TaskPolling] AI消息开始, idx:', eventIdx);
console.log('[AiMessageStart] 开始处理', {
eventIdx,
messagesLength: this.messages.length,
lastMessageRole: this.messages[this.messages.length - 1]?.role,
streamingMessage: this.streamingMessage,
taskInProgress: this.taskInProgress,
currentConversationId: this.currentConversationId
});
if (this.waitingForSubAgent) { if (this.waitingForSubAgent) {
this.waitingForSubAgent = false; this.waitingForSubAgent = false;
@ -45,13 +31,6 @@ export const aiStreamMethods = {
// 检查是否已经有 assistant 消息 // 检查是否已经有 assistant 消息
const hasAssistantMessage = lastMessage && lastMessage.role === 'assistant'; const hasAssistantMessage = lastMessage && lastMessage.role === 'assistant';
console.log('[AiMessageStart] 最后一条消息状态', {
hasAssistantMessage,
lastMessageActionsLength: lastMessage?.actions?.length || 0,
lastMessageAwaitingFirstContent: lastMessage?.awaitingFirstContent,
lastMessageGeneratingLabel: lastMessage?.generatingLabel
});
// 判断是否是刷新恢复的情况: // 判断是否是刷新恢复的情况:
// 1. 有assistant消息 // 1. 有assistant消息
// 2. 且最后一条 assistant 仍处于“未完成流式状态”(而不是普通已完成消息) // 2. 且最后一条 assistant 仍处于“未完成流式状态”(而不是普通已完成消息)
@ -83,16 +62,7 @@ export const aiStreamMethods = {
isRefreshRestore isRefreshRestore
}); });
console.log('[AiMessageStart] 场景判断', {
isRefreshRestore,
streamingMessage: this.streamingMessage,
hasActions: !!(lastMessage?.actions && lastMessage.actions.length > 0),
awaitingFirstContent: lastMessage?.awaitingFirstContent,
taskInProgress: this.taskInProgress
});
if (isRefreshRestore) { if (isRefreshRestore) {
console.log('[AiMessageStart] 场景=刷新恢复复用现有assistant消息');
debugLog('[TaskPolling] 刷新恢复场景,复用现有 assistant 消息'); debugLog('[TaskPolling] 刷新恢复场景,复用现有 assistant 消息');
// 只更新状态,不创建新消息 // 只更新状态,不创建新消息
this.taskInProgress = true; this.taskInProgress = true;
@ -105,25 +75,18 @@ export const aiStreamMethods = {
// 从头重建时restoreTaskState 已根据事件流分析hasAssistantContentEvent // 从头重建时restoreTaskState 已根据事件流分析hasAssistantContentEvent
// 正确设置了 awaitingFirstContent此处不覆盖。 // 正确设置了 awaitingFirstContent此处不覆盖。
// actions 被清空不代表没有内容,事件重放会恢复。 // actions 被清空不代表没有内容,事件重放会恢复。
console.log('[AiMessageStart] 从头重建,保留 awaitingFirstContent:', lastMessage.awaitingFirstContent);
} else if (!hasContent) { } else if (!hasContent) {
lastMessage.awaitingFirstContent = true; lastMessage.awaitingFirstContent = true;
lastMessage.generatingLabel = lastMessage.generatingLabel || '思考中...'; lastMessage.generatingLabel = lastMessage.generatingLabel || '思考中...';
console.log('[AiMessageStart] 设置等待动画', {
awaitingFirstContent: true,
generatingLabel: lastMessage.generatingLabel
});
} else { } else {
// 如果已有内容,确保等待动画不显示 // 如果已有内容,确保等待动画不显示
lastMessage.awaitingFirstContent = false; lastMessage.awaitingFirstContent = false;
lastMessage.generatingLabel = ''; lastMessage.generatingLabel = '';
console.log('[AiMessageStart] 关闭等待动画(已有内容)');
} }
return; return;
} }
// 其他情况:创建新的 assistant 消息 // 其他情况:创建新的 assistant 消息
console.log('[AiMessageStart] 场景=创建新消息');
debugLog('[TaskPolling] 创建新的 assistant 消息'); debugLog('[TaskPolling] 创建新的 assistant 消息');
this.monitorResetSpeech(); this.monitorResetSpeech();
this.cleanupStaleToolActions(); this.cleanupStaleToolActions();
@ -133,13 +96,6 @@ export const aiStreamMethods = {
this.streamingMessage = true; this.streamingMessage = true;
const newMessage = this.messages[this.messages.length - 1]; const newMessage = this.messages[this.messages.length - 1];
console.log('[AiMessageStart] 新消息创建完成', {
role: newMessage?.role,
awaitingFirstContent: newMessage?.awaitingFirstContent,
generatingLabel: newMessage?.generatingLabel,
actionsLength: newMessage?.actions?.length || 0,
messagesLength: this.messages.length
});
// 如果是从头重建,标记消息为静默恢复 // 如果是从头重建,标记消息为静默恢复
if (this._rebuildingFromScratch) { if (this._rebuildingFromScratch) {
@ -147,33 +103,27 @@ export const aiStreamMethods = {
debugLog('[TaskPolling] 标记消息为静默恢复(从头重建)'); debugLog('[TaskPolling] 标记消息为静默恢复(从头重建)');
newMessage.awaitingFirstContent = false; newMessage.awaitingFirstContent = false;
newMessage.generatingLabel = ''; newMessage.generatingLabel = '';
console.log('[AiMessageStart] 从头重建,关闭等待动画');
} }
} }
// 强制触发Vue响应式更新 // 强制触发Vue响应式更新
this.$forceUpdate(); this.$forceUpdate();
console.log('[AiMessageStart] 已调用$forceUpdate');
this.$nextTick(() => { this.$nextTick(() => {
console.log('[AiMessageStart] nextTick回调执行');
this.conditionalScrollToBottom(); this.conditionalScrollToBottom();
}); });
}, },
handleThinkingStart(data: any, eventIdx: number) { handleThinkingStart(data: any, eventIdx: number) {
console.log('[ThinkingStart] 开始处理', { eventIdx });
debugLog('[TaskPolling] 思考开始, idx:', eventIdx); debugLog('[TaskPolling] 思考开始, idx:', eventIdx);
const ignoreThinking = this.runMode === 'fast' || this.thinkingMode === false; const ignoreThinking = this.runMode === 'fast' || this.thinkingMode === false;
if (ignoreThinking) { if (ignoreThinking) {
this.monitorEndModelOutput(); this.monitorEndModelOutput();
console.log('[ThinkingStart] 忽略思考fast模式或关闭思考');
return; return;
} }
// 防御性检查如果没有assistant消息先创建一个 // 防御性检查如果没有assistant消息先创建一个
const lastMessage = this.messages[this.messages.length - 1]; const lastMessage = this.messages[this.messages.length - 1];
if (!lastMessage || lastMessage.role !== 'assistant') { if (!lastMessage || lastMessage.role !== 'assistant') {
console.log('[DEBUG_AWAITING] ThinkingStart 检测到缺少assistant消息自动创建');
this.chatStartAssistantMessage(); this.chatStartAssistantMessage();
} }
@ -188,10 +138,6 @@ export const aiStreamMethods = {
// 有内容了,关闭等待动画 // 有内容了,关闭等待动画
if (lastMessage && lastMessage.role === 'assistant') { if (lastMessage && lastMessage.role === 'assistant') {
console.log('[ThinkingStart] 关闭等待动画', {
beforeAwaitingFirstContent: lastMessage.awaitingFirstContent,
beforeGeneratingLabel: lastMessage.generatingLabel
});
lastMessage.awaitingFirstContent = false; lastMessage.awaitingFirstContent = false;
lastMessage.generatingLabel = ''; lastMessage.generatingLabel = '';
} }
@ -267,13 +213,11 @@ export const aiStreamMethods = {
this.monitorEndModelOutput(); this.monitorEndModelOutput();
}, },
handleTextStart() { handleTextStart() {
console.log('[TextStart] 开始处理');
debugLog('[TaskPolling] 文本开始'); debugLog('[TaskPolling] 文本开始');
// 防御性检查如果没有assistant消息先创建一个 // 防御性检查如果没有assistant消息先创建一个
const lastMessage = this.messages[this.messages.length - 1]; const lastMessage = this.messages[this.messages.length - 1];
if (!lastMessage || lastMessage.role !== 'assistant') { if (!lastMessage || lastMessage.role !== 'assistant') {
console.log('[DEBUG_AWAITING] TextStart 检测到缺少assistant消息自动创建');
this.chatStartAssistantMessage(); this.chatStartAssistantMessage();
} }
@ -282,10 +226,6 @@ export const aiStreamMethods = {
// 有内容了,关闭等待动画 // 有内容了,关闭等待动画
const currentMessage = this.messages[this.messages.length - 1]; const currentMessage = this.messages[this.messages.length - 1];
if (currentMessage && currentMessage.role === 'assistant') { if (currentMessage && currentMessage.role === 'assistant') {
console.log('[TextStart] 关闭等待动画', {
beforeAwaitingFirstContent: currentMessage.awaitingFirstContent,
beforeGeneratingLabel: currentMessage.generatingLabel
});
currentMessage.awaitingFirstContent = false; currentMessage.awaitingFirstContent = false;
currentMessage.generatingLabel = ''; currentMessage.generatingLabel = '';
} }

View File

@ -94,12 +94,6 @@ export const lifecycleMethods = {
currentConversationId: this.currentConversationId currentConversationId: this.currentConversationId
}); });
} }
console.log(`[DEBUG_AWAITING] 忽略不匹配的事件`, {
eventType,
eventIdx,
eventConversationId: eventData.conversation_id,
currentConversationId: this.currentConversationId
});
debugLog( debugLog(
`[TaskPolling] 忽略不匹配的事件 #${eventIdx}: ${eventType}, 事件对话=${eventData.conversation_id}, 当前对话=${this.currentConversationId}` `[TaskPolling] 忽略不匹配的事件 #${eventIdx}: ${eventType}, 事件对话=${eventData.conversation_id}, 当前对话=${this.currentConversationId}`
); );
@ -176,13 +170,6 @@ export const lifecycleMethods = {
debugLog(`[TaskPolling] 处理事件 #${eventIdx}: ${eventType}`, eventData); debugLog(`[TaskPolling] 处理事件 #${eventIdx}: ${eventType}`, eventData);
console.log(`[DEBUG_AWAITING] 处理事件`, {
eventType,
eventIdx,
eventConversationId: eventData.conversation_id,
currentConversationId: this.currentConversationId
});
// 根据事件类型调用对应的处理方法 // 根据事件类型调用对应的处理方法
switch (eventType) { switch (eventType) {
case 'ai_message_start': case 'ai_message_start':

View File

@ -8,13 +8,10 @@ export const debugNotifyLog = (...args: any[]) => {
void args; void args;
}; };
export const keyNotifyLog = (...args: any[]) => { export const keyNotifyLog = (...args: any[]) => {
console.log(...args);
}; };
export const jsonDebug = (...args: any[]) => { export const jsonDebug = (...args: any[]) => {
console.log('[JSONDEBUG]', ...args);
}; };
export const userMDebug = (...args: any[]) => { export const userMDebug = (...args: any[]) => {
console.log('[USERMDEBUG]', ...args);
}; };
export const RESTORE_DEBUG_PREFIX = '[RESTORE_DEBUG]'; export const RESTORE_DEBUG_PREFIX = '[RESTORE_DEBUG]';
export let restoreDebugCount = 0; export let restoreDebugCount = 0;
@ -35,17 +32,16 @@ export const RESTORE_DEBUG_EVENTS = new Set([
]); ]);
export function isRestoreDebugEnabled() { export function isRestoreDebugEnabled() {
if (typeof window === 'undefined') return true; if (typeof window === 'undefined') return false;
try { try {
const explicit = (window as any).__RESTORE_DEBUG__; const explicit = (window as any).__RESTORE_DEBUG__;
if (explicit === false || explicit === '0') return false;
if (explicit === true || explicit === '1') return true; if (explicit === true || explicit === '1') return true;
if (explicit === false || explicit === '0') return false;
const localFlag = window.localStorage?.getItem('restoreDebug'); const localFlag = window.localStorage?.getItem('restoreDebug');
if (localFlag === '0' || localFlag === 'false') return false;
if (localFlag === '1' || localFlag === 'true') return true; if (localFlag === '1' || localFlag === 'true') return true;
return true; return false;
} catch { } catch {
return true; return false;
} }
} }

View File

@ -21,25 +21,18 @@ import {
export const toolMethods = { export const toolMethods = {
handleToolPreparing(data: any) { handleToolPreparing(data: any) {
console.log('[ToolPreparing] 开始处理', { name: data.name, id: data.id });
debugLog('[TaskPolling] 工具准备中:', data.name); debugLog('[TaskPolling] 工具准备中:', data.name);
if (this.dropToolEvents) { if (this.dropToolEvents) {
console.log('[ToolPreparing] dropToolEvents=true跳过');
return; return;
} }
const msg = this.chatEnsureAssistantMessage(); const msg = this.chatEnsureAssistantMessage();
if (!msg) { if (!msg) {
console.log('[ToolPreparing] 无法获取assistant消息');
return; return;
} }
if (msg.awaitingFirstContent) { if (msg.awaitingFirstContent) {
console.log('[ToolPreparing] 关闭等待动画', {
beforeAwaitingFirstContent: msg.awaitingFirstContent,
beforeGeneratingLabel: msg.generatingLabel
});
msg.awaitingFirstContent = false; msg.awaitingFirstContent = false;
msg.generatingLabel = ''; msg.generatingLabel = '';
} }
@ -105,10 +98,6 @@ export const toolMethods = {
// 但从头重建等场景可能跳过 tool_preparing 直接收到 tool_start // 但从头重建等场景可能跳过 tool_preparing 直接收到 tool_start
const msgForAwaiting = this.chatEnsureAssistantMessage(); const msgForAwaiting = this.chatEnsureAssistantMessage();
if (msgForAwaiting && msgForAwaiting.awaitingFirstContent) { if (msgForAwaiting && msgForAwaiting.awaitingFirstContent) {
console.log('[ToolStart] 关闭等待动画', {
beforeAwaitingFirstContent: msgForAwaiting.awaitingFirstContent,
toolName: data.name
});
msgForAwaiting.awaitingFirstContent = false; msgForAwaiting.awaitingFirstContent = false;
msgForAwaiting.generatingLabel = ''; msgForAwaiting.generatingLabel = '';
} }
@ -294,7 +283,6 @@ export const toolMethods = {
await personalizationStore.fetchPersonalization(); await personalizationStore.fetchPersonalization();
} catch (e) { } catch (e) {
// 静默处理,不影响主流程 // 静默处理,不影响主流程
console.debug('[TaskPolling] 刷新个人空间数据失败:', e);
} }
})(); })();
} }

View File

@ -336,19 +336,10 @@ export const hostWorkspaceMethods = {
}, },
async handleSelectWorkspaceConversation(payload: { conversationId: string; workspaceId: string }) { async handleSelectWorkspaceConversation(payload: { conversationId: string; workspaceId: string }) {
const { conversationId, workspaceId } = payload || {}; const { conversationId, workspaceId } = payload || {};
console.log('[sidebar-debug] handleSelectWorkspaceConversation', {
conversationId,
workspaceId,
currentHostWorkspaceId: this.currentHostWorkspaceId,
versioningHostMode: this.versioningHostMode,
dockerProjectMode: this.dockerProjectMode
});
if (!conversationId || !workspaceId) return; if (!conversationId || !workspaceId) return;
if ((this.versioningHostMode || this.dockerProjectMode) && workspaceId !== this.currentHostWorkspaceId) { if ((this.versioningHostMode || this.dockerProjectMode) && workspaceId !== this.currentHostWorkspaceId) {
console.log('[sidebar-debug] switching workspace', { from: this.currentHostWorkspaceId, to: workspaceId });
await this.handleHostWorkspaceSwitch(workspaceId); await this.handleHostWorkspaceSwitch(workspaceId);
} }
console.log('[sidebar-debug] loading conversation', { conversationId, currentHostWorkspaceIdAfterSwitch: this.currentHostWorkspaceId });
await this.loadConversation(conversationId, { force: true, workspaceId }); await this.loadConversation(conversationId, { force: true, workspaceId });
}, },
async handleRenameWorkspaceFromSidebar(payload: { workspaceId: string; label: string }) { async handleRenameWorkspaceFromSidebar(payload: { workspaceId: string; label: string }) {

View File

@ -67,23 +67,13 @@ export const mobileMethods = {
this.uiToggleMobileOverlayMenu(); this.uiToggleMobileOverlayMenu();
}, },
openMobileOverlay(target) { openMobileOverlay(target) {
console.log(
'[UI_DEBUG] openMobileOverlay called, target:',
target,
'isMobileViewport:',
this.isMobileViewport,
'activeMobileOverlay:',
this.activeMobileOverlay
);
if (!this.isMobileViewport) { if (!this.isMobileViewport) {
console.log('[UI_DEBUG] openMobileOverlay: blocked - not mobile viewport');
return; return;
} }
if (target === 'approval') { if (target === 'approval') {
this.fetchPendingToolApprovals(); this.fetchPendingToolApprovals();
} }
if (this.activeMobileOverlay === target) { if (this.activeMobileOverlay === target) {
console.log('[UI_DEBUG] openMobileOverlay: target already active, closing');
this.closeMobileOverlay('same-target-click'); this.closeMobileOverlay('same-target-click');
return; return;
} }
@ -93,17 +83,10 @@ export const mobileMethods = {
if (target === 'conversation') { if (target === 'conversation') {
this.uiSetSidebarCollapsed(false); this.uiSetSidebarCollapsed(false);
} }
console.log('[UI_DEBUG] openMobileOverlay: opening target:', target);
this.uiSetActiveMobileOverlay(target); this.uiSetActiveMobileOverlay(target);
this.uiSetMobileOverlayMenuOpen(false); this.uiSetMobileOverlayMenuOpen(false);
}, },
closeMobileOverlay(source = 'unknown') { closeMobileOverlay(source = 'unknown') {
console.log(
'[UI_DEBUG] closeMobileOverlay called from:',
source,
'activeMobileOverlay:',
this.activeMobileOverlay
);
if (!this.activeMobileOverlay) { if (!this.activeMobileOverlay) {
this.uiCloseMobileOverlay(); this.uiCloseMobileOverlay();
return; return;

View File

@ -38,12 +38,6 @@ export const panelMethods = {
} }
}, },
toggleApprovalPanel() { toggleApprovalPanel() {
console.log(
'[UI_DEBUG] toggleApprovalPanel called, current rightCollapsed:',
this.rightCollapsed,
'new state:',
!this.rightCollapsed
);
this.rightCollapsed = !this.rightCollapsed; this.rightCollapsed = !this.rightCollapsed;
if (!this.rightCollapsed && this.rightWidth < this.minPanelWidth) { if (!this.rightCollapsed && this.rightWidth < this.minPanelWidth) {
this.rightWidth = this.minPanelWidth; this.rightWidth = this.minPanelWidth;
@ -71,53 +65,28 @@ export const panelMethods = {
this.toggleFocusPanel(); this.toggleFocusPanel();
}, },
handleApprovalPanelToggleClick() { handleApprovalPanelToggleClick() {
console.log(
'[UI_DEBUG] handleApprovalPanelToggleClick called, isMobileViewport:',
this.isMobileViewport,
'currentConversationId:',
this.currentConversationId,
'activeMobileOverlay:',
this.activeMobileOverlay
);
if (!this.currentConversationId) { if (!this.currentConversationId) {
console.log('[UI_DEBUG] handleApprovalPanelToggleClick: blocked - no conversation');
return; return;
} }
if (this.isMobileViewport) { if (this.isMobileViewport) {
console.log('[UI_DEBUG] handleApprovalPanelToggleClick: mobile path, toggling overlay');
// 手机端:获取审批列表(不自动关闭),然后切换遮罩 // 手机端:获取审批列表(不自动关闭),然后切换遮罩
this.fetchPendingToolApprovals(); this.fetchPendingToolApprovals();
this.openMobileOverlay('approval'); this.openMobileOverlay('approval');
return; return;
} }
console.log('[UI_DEBUG] handleApprovalPanelToggleClick: desktop path, toggling panel');
this.toggleApprovalPanel(); this.toggleApprovalPanel();
}, },
handleTokenPanelToggleClick(fromSettingsMenu = false) { handleTokenPanelToggleClick(fromSettingsMenu = false) {
console.log(
'[UI_DEBUG] handleTokenPanelToggleClick called, fromSettingsMenu:',
fromSettingsMenu,
'isMobileViewport:',
this.isMobileViewport,
'tokenPanelCollapsed:',
this.tokenPanelCollapsed,
'currentConversationId:',
this.currentConversationId
);
if (!this.currentConversationId) { if (!this.currentConversationId) {
console.log('[UI_DEBUG] handleTokenPanelToggleClick: blocked - no conversation');
return; return;
} }
if (this.isPolicyBlocked('block_token_panel', '用量统计已被管理员禁用')) { if (this.isPolicyBlocked('block_token_panel', '用量统计已被管理员禁用')) {
console.log('[UI_DEBUG] handleTokenPanelToggleClick: blocked - policy');
return; return;
} }
// 移动端禁用“点击展开顶部用量面板”,仅允许在已展开时点击收起 // 移动端禁用“点击展开顶部用量面板”,仅允许在已展开时点击收起
if (this.isMobileViewport && this.tokenPanelCollapsed && !fromSettingsMenu) { if (this.isMobileViewport && this.tokenPanelCollapsed && !fromSettingsMenu) {
console.log('[UI_DEBUG] handleTokenPanelToggleClick: blocked - mobile viewport restriction');
return; return;
} }
console.log('[UI_DEBUG] handleTokenPanelToggleClick: calling toggleTokenPanel');
this.toggleTokenPanel(); this.toggleTokenPanel();
}, },
getMessagesAreaElement() { getMessagesAreaElement() {

View File

@ -20,14 +20,14 @@ import { debugLog } from '../common';
export const SUB_AGENT_DONE_PREFIX_RE = /^(?:✅\s*)?子智能体\s*#?\s*(\d+)\s*任务摘要[:]/; export const SUB_AGENT_DONE_PREFIX_RE = /^(?:✅\s*)?子智能体\s*#?\s*(\d+)\s*任务摘要[:]/;
export const BG_RUN_COMMAND_DONE_PREFIX_RE = /^\[后台\s*run_command\s*完成\]/; export const BG_RUN_COMMAND_DONE_PREFIX_RE = /^\[后台\s*run_command\s*完成\]/;
export const userMDebug = (...args: any[]) => { export const userMDebug = (...args: any[]) => {
console.log('[USERMDEBUG]', ...args);
}; };
export let uiBounceTraceCount = 0; export let uiBounceTraceCount = 0;
export const UI_BOUNCE_TRACE_MAX = 140; export const UI_BOUNCE_TRACE_MAX = 140;
export const uiBounceTraceLastTsByKey = new Map<string, number>(); export const uiBounceTraceLastTsByKey = new Map<string, number>();
export function isUiBounceTraceEnabled() { export function isUiBounceTraceEnabled() {
if (typeof window === 'undefined') return true; // 默认关闭:排障时通过 window.__SCROLL_BOUNCE_TRACE__ = true 或 localStorage.scrollBounceTrace = '1' 显式打开
if (typeof window === 'undefined') return false;
try { try {
const explicit = (window as any).__SCROLL_BOUNCE_TRACE__; const explicit = (window as any).__SCROLL_BOUNCE_TRACE__;
if (explicit === false || explicit === '0') return false; if (explicit === false || explicit === '0') return false;
@ -35,9 +35,9 @@ export function isUiBounceTraceEnabled() {
const localFlag = window.localStorage?.getItem('scrollBounceTrace'); const localFlag = window.localStorage?.getItem('scrollBounceTrace');
if (localFlag === '0' || localFlag === 'false') return false; if (localFlag === '0' || localFlag === 'false') return false;
if (localFlag === '1' || localFlag === 'true') return true; if (localFlag === '1' || localFlag === 'true') return true;
return true; return false;
} catch { } catch {
return true; return false;
} }
} }
@ -62,7 +62,8 @@ export function uiBounceTrace(
} }
export function isConnectionDiagEnabled() { export function isConnectionDiagEnabled() {
if (typeof window === 'undefined') return true; // 默认关闭:排障时通过 window.__CONN_DIAG__ = true 或 localStorage.connDiag = '1' 显式打开
if (typeof window === 'undefined') return false;
try { try {
const explicit = (window as any).__CONN_DIAG__; const explicit = (window as any).__CONN_DIAG__;
if (explicit === false || explicit === '0') return false; if (explicit === false || explicit === '0') return false;
@ -70,10 +71,9 @@ export function isConnectionDiagEnabled() {
const localFlag = window.localStorage?.getItem('connDiag'); const localFlag = window.localStorage?.getItem('connDiag');
if (localFlag === '0' || localFlag === 'false') return false; if (localFlag === '0' || localFlag === 'false') return false;
if (localFlag === '1' || localFlag === 'true') return true; if (localFlag === '1' || localFlag === 'true') return true;
// 默认常开:无需手动启动 return false;
return true;
} catch { } catch {
return true; return false;
} }
} }
@ -118,18 +118,10 @@ export function connectionDiag(
export function parseSubAgentDoneLabel(rawContent: any): string | null { export function parseSubAgentDoneLabel(rawContent: any): string | null {
const content = (rawContent || '').toString().trim(); const content = (rawContent || '').toString().trim();
if (!content) { if (!content) {
console.log('[DEBUG_SYSTEM][ui] parseSubAgentDoneLabel: 空内容');
return null; return null;
} }
const match = content.match(SUB_AGENT_DONE_PREFIX_RE); const match = content.match(SUB_AGENT_DONE_PREFIX_RE);
const isCompleted = /已完成/.test(content); const isCompleted = /已完成/.test(content);
console.log('[DEBUG_SYSTEM][ui] parseSubAgentDoneLabel', {
content,
regex: SUB_AGENT_DONE_PREFIX_RE.toString(),
matched: !!match,
matchAgentId: match?.[1],
isCompleted
});
if (!match || !isCompleted) { if (!match || !isCompleted) {
return null; return null;
} }

View File

@ -91,8 +91,7 @@ export const socketMethods = {
streamingMessage: !!this.streamingMessage, streamingMessage: !!this.streamingMessage,
visibility: document?.visibilityState || 'unknown', visibility: document?.visibilityState || 'unknown',
online: typeof navigator !== 'undefined' ? navigator.onLine : null online: typeof navigator !== 'undefined' ? navigator.onLine : null
}, }
{ force: true }
); );
} else if ( } else if (
isConnectionDiagEnabled() && isConnectionDiagEnabled() &&
@ -177,8 +176,7 @@ export const socketMethods = {
{ {
connectedIntervalMs: this.connectionHeartbeatIntervalMs, connectedIntervalMs: this.connectionHeartbeatIntervalMs,
disconnectedIntervalMs: this.connectionHeartbeatDisconnectedIntervalMs disconnectedIntervalMs: this.connectionHeartbeatDisconnectedIntervalMs
}, }
{ force: true }
); );
const runHeartbeat = async () => { const runHeartbeat = async () => {
if (!this.connectionHeartbeatActive) { if (!this.connectionHeartbeatActive) {
@ -224,7 +222,7 @@ export const socketMethods = {
clearTimeout(this.connectionHeartbeatTimer); clearTimeout(this.connectionHeartbeatTimer);
this.connectionHeartbeatTimer = null; this.connectionHeartbeatTimer = null;
} }
connectionDiag('log', 'heartbeat-stop', {}, { force: true }); connectionDiag('log', 'heartbeat-stop', {});
}, },
async loadInitialData() { async loadInitialData() {
try { try {

View File

@ -30,11 +30,6 @@ export const tutorialMethods = {
try { try {
const resp = await fetch('/api/tutorial-status', { credentials: 'same-origin' }); const resp = await fetch('/api/tutorial-status', { credentials: 'same-origin' });
const data = await resp.json().catch(() => ({})); const data = await resp.json().catch(() => ({}));
console.info('[tutorial-prompt] status response:', {
ok: resp.ok,
status: resp.status,
data
});
if (!resp.ok || !data?.success) { if (!resp.ok || !data?.success) {
return; return;
} }

View File

@ -159,17 +159,13 @@ export const versioningMethods = {
throw new Error(`详情响应解析失败: ${parseErr?.message || '未知错误'}`); throw new Error(`详情响应解析失败: ${parseErr?.message || '未知错误'}`);
} }
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log('[VersioningDetail] raw response:', data);
if (!resp.ok || !data?.success) { if (!resp.ok || !data?.success) {
throw new Error(data?.error || '加载详情失败'); throw new Error(data?.error || '加载详情失败');
} }
this.versioningSelectedDetail = data.data || null; this.versioningSelectedDetail = data.data || null;
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log('[VersioningDetail] detail set:', this.versioningSelectedDetail);
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log('[VersioningDetail] files:', this.versioningSelectedDetail?.files);
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log('[VersioningDetail] first file patch_lines:', this.versioningSelectedDetail?.files?.[0]?.patch_lines);
} catch (error: any) { } catch (error: any) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error('[VersioningDetail] error:', error); console.error('[VersioningDetail] error:', error);

View File

@ -147,7 +147,6 @@ onMounted(async () => {
try { try {
const resp = await fetch('/api/session-status', { credentials: 'same-origin' }); const resp = await fetch('/api/session-status', { credentials: 'same-origin' });
const data = await resp.json(); const data = await resp.json();
console.info('[auth-debug] login page session-status:', data);
} catch (err) { } catch (err) {
console.warn('[auth-debug] login page session-status failed:', err); console.warn('[auth-debug] login page session-status failed:', err);
} }

View File

@ -125,7 +125,6 @@ onMounted(async () => {
try { try {
const resp = await fetch('/api/session-status', { credentials: 'same-origin' }); const resp = await fetch('/api/session-status', { credentials: 'same-origin' });
const data = await resp.json(); const data = await resp.json();
console.info('[auth-debug] register page session-status:', data);
} catch (err) { } catch (err) {
console.warn('[auth-debug] register page session-status failed:', err); console.warn('[auth-debug] register page session-status failed:', err);
} }

View File

@ -916,7 +916,6 @@ const copyUserMessage = async (msg: any, index: number) => {
const branchUserMessage = (_msg: any) => { const branchUserMessage = (_msg: any) => {
// TODO: // TODO:
void _msg; void _msg;
console.log('[ChatArea] 分支功能待实现');
}; };
const observeUserBubbles = () => { const observeUserBubbles = () => {
@ -1083,10 +1082,6 @@ const filteredMessages = computed(() => {
const source = props.messages || []; const source = props.messages || [];
const droppedRoleSystem = source.filter((m) => m && m.role === 'system'); const droppedRoleSystem = source.filter((m) => m && m.role === 'system');
if (droppedRoleSystem.length > 0) { if (droppedRoleSystem.length > 0) {
console.log('[DEBUG_SYSTEM][render] filteredMessages 过滤了 role=system 消息', {
count: droppedRoleSystem.length,
samples: droppedRoleSystem.slice(0, 3)
});
} }
const result = source.filter((m) => { const result = source.filter((m) => {
if (m && m.metadata && m.metadata.system_injected_image) { if (m && m.metadata && m.metadata.system_injected_image) {
@ -1762,7 +1757,6 @@ function getSubAgentSystemNoticeLabel(action: any): string | null {
const key = action?.id || `no-id-${content.slice(0, 32)}`; const key = action?.id || `no-id-${content.slice(0, 32)}`;
if (!content) { if (!content) {
if (!debugLoggedSystemActionKeys.has(`${key}-empty`)) { if (!debugLoggedSystemActionKeys.has(`${key}-empty`)) {
console.log('[DEBUG_SYSTEM][render] system action 内容为空', { action });
debugLoggedSystemActionKeys.add(`${key}-empty`); debugLoggedSystemActionKeys.add(`${key}-empty`);
} }
return null; return null;
@ -1773,7 +1767,6 @@ function getSubAgentSystemNoticeLabel(action: any): string | null {
BG_RUN_COMMAND_DONE_LABEL_RE.test(content)) BG_RUN_COMMAND_DONE_LABEL_RE.test(content))
) { ) {
if (!debugLoggedSystemActionKeys.has(`${key}-variant-pass`)) { if (!debugLoggedSystemActionKeys.has(`${key}-variant-pass`)) {
console.log('[DEBUG_SYSTEM][render] 命中 variant 渲染', { action, label: content });
debugLoggedSystemActionKeys.add(`${key}-variant-pass`); debugLoggedSystemActionKeys.add(`${key}-variant-pass`);
} }
return content; return content;
@ -1781,20 +1774,11 @@ function getSubAgentSystemNoticeLabel(action: any): string | null {
const m = content.match(SUB_AGENT_DONE_PREFIX_RE); const m = content.match(SUB_AGENT_DONE_PREFIX_RE);
if (m && /已完成/.test(content)) { if (m && /已完成/.test(content)) {
if (!debugLoggedSystemActionKeys.has(`${key}-regex-pass`)) { if (!debugLoggedSystemActionKeys.has(`${key}-regex-pass`)) {
console.log('[DEBUG_SYSTEM][render] 命中 regex 渲染', {
action,
normalized: `子智能体${m[1]} 任务完成`
});
debugLoggedSystemActionKeys.add(`${key}-regex-pass`); debugLoggedSystemActionKeys.add(`${key}-regex-pass`);
} }
return `子智能体${m[1]} 任务完成`; return `子智能体${m[1]} 任务完成`;
} }
if (!debugLoggedSystemActionKeys.has(`${key}-blocked`)) { if (!debugLoggedSystemActionKeys.has(`${key}-blocked`)) {
console.log('[DEBUG_SYSTEM][render] system action 被渲染层拦截', {
action,
regex: SUB_AGENT_DONE_PREFIX_RE.toString(),
completed: /已完成/.test(content)
});
debugLoggedSystemActionKeys.add(`${key}-blocked`); debugLoggedSystemActionKeys.add(`${key}-blocked`);
} }
return null; return null;
@ -1808,10 +1792,6 @@ function isActionVisible(action: any): boolean {
if (!RENDERABLE_ACTION_TYPES.has(actionType)) { if (!RENDERABLE_ACTION_TYPES.has(actionType)) {
const key = action?.id || `unknown-${actionType || 'none'}`; const key = action?.id || `unknown-${actionType || 'none'}`;
if (!debugLoggedUnknownActionKeys.has(key)) { if (!debugLoggedUnknownActionKeys.has(key)) {
console.log('[DEBUG_SYSTEM][render] 未知 action.type已跳过渲染', {
actionType,
action
});
debugLoggedUnknownActionKeys.add(key); debugLoggedUnknownActionKeys.add(key);
} }
return false; return false;
@ -2099,11 +2079,6 @@ const splitActionGroups = (actions: any[] = [], messageIndex = 0) => {
// //
if (CHAT_DEBUG_LOGS && actions.length > 0) { if (CHAT_DEBUG_LOGS && actions.length > 0) {
console.log(`[splitActionGroups] 消息 ${messageIndex}:`, {
totalActions: actions.length,
actionTypes: actions.map((a) => a.type),
stackedBlocksEnabled: props.stackedBlocksEnabled
});
} }
const flushBuffer = () => { const flushBuffer = () => {
@ -2140,14 +2115,6 @@ const splitActionGroups = (actions: any[] = [], messageIndex = 0) => {
// //
if (CHAT_DEBUG_LOGS && actions.length > 0) { if (CHAT_DEBUG_LOGS && actions.length > 0) {
console.log(`[splitActionGroups] 消息 ${messageIndex} 结果:`, {
totalGroups: result.length,
groups: result.map((g) => ({
kind: g.kind,
actionsCount: g.kind === 'stack' ? g.actions.length : 1,
actionType: g.kind === 'stack' ? g.actions[0]?.type : g.action?.type
}))
});
} }
return result; return result;

View File

@ -98,7 +98,7 @@ const RENAME_TYPE_INTERVAL = 32;
const MONITOR_EDITOR_DEBUG = false; const MONITOR_EDITOR_DEBUG = false;
const MONITOR_READER_DEBUG = false; const MONITOR_READER_DEBUG = false;
const MONITOR_RENAME_DEBUG = true; const MONITOR_RENAME_DEBUG = false;
const readerDebug = (...args: any[]) => { const readerDebug = (...args: any[]) => {
if (!MONITOR_READER_DEBUG) { if (!MONITOR_READER_DEBUG) {
return; return;
@ -117,14 +117,14 @@ const editorDebug = (...args: any[]) => {
} }
console.log('[MonitorEditor]', ...args); console.log('[MonitorEditor]', ...args);
}; };
const MONITOR_PROGRESS_DEBUG = true; const MONITOR_PROGRESS_DEBUG = false;
const progressDebug = (...args: any[]) => { const progressDebug = (...args: any[]) => {
if (!MONITOR_PROGRESS_DEBUG) { if (!MONITOR_PROGRESS_DEBUG) {
return; return;
} }
console.debug('[MonitorProgress]', ...args); console.debug('[MonitorProgress]', ...args);
}; };
const MONITOR_LIFECYCLE_DEBUG = true; const MONITOR_LIFECYCLE_DEBUG = false;
const monitorLifecycleDebug = (...args: any[]) => { const monitorLifecycleDebug = (...args: any[]) => {
if (!MONITOR_LIFECYCLE_DEBUG) { if (!MONITOR_LIFECYCLE_DEBUG) {
return; return;

View File

@ -62,7 +62,6 @@ const filePadding = computed(() => ({
function toggle() { function toggle() {
if (props.node.type === 'folder') { if (props.node.type === 'folder') {
console.log('[FileTree] click folder header', props.node.path);
fileStore.toggleFolder(props.node.path); fileStore.toggleFolder(props.node.path);
} }
} }

View File

@ -1911,7 +1911,6 @@ const voiceButtonTitle = computed(() => {
const setupVoiceBridgeCallbacks = () => { const setupVoiceBridgeCallbacks = () => {
if (typeof window === 'undefined') return; if (typeof window === 'undefined') return;
(window as any).__onVoiceResult = (text: string) => { (window as any).__onVoiceResult = (text: string) => {
console.log('[VoiceInput] Android 识别结果:', text);
const bridge = (window as any).AndroidVoiceBridge; const bridge = (window as any).AndroidVoiceBridge;
bridge?.debugLog('__onVoiceResult 被调用, text=' + JSON.stringify(text)); bridge?.debugLog('__onVoiceResult 被调用, text=' + JSON.stringify(text));
if (!text) { if (!text) {
@ -1959,7 +1958,6 @@ const setupVoiceBridgeCallbacks = () => {
} }
}; };
(window as any).__onVoiceStatus = (status: string) => { (window as any).__onVoiceStatus = (status: string) => {
console.log('[VoiceInput] 状态:', status);
if (status === 'listening' || status === 'processing' || status === 'initializing') { if (status === 'listening' || status === 'processing' || status === 'initializing') {
// initializing startListening // initializing startListening
isRecording.value = true; isRecording.value = true;
@ -2008,23 +2006,19 @@ const isWebSpeechSupported = computed(() => {
if (typeof window === 'undefined') return false; if (typeof window === 'undefined') return false;
const hasSR = 'SpeechRecognition' in window; const hasSR = 'SpeechRecognition' in window;
const hasWebkit = 'webkitSpeechRecognition' in window; const hasWebkit = 'webkitSpeechRecognition' in window;
console.log('[VoiceInput] 检测支持:', { hasSR, hasWebkit, supported: hasSR || hasWebkit });
return hasSR || hasWebkit; return hasSR || hasWebkit;
}); });
const getSpeechRecognitionConstructor = (): typeof SpeechRecognition | null => { const getSpeechRecognitionConstructor = (): typeof SpeechRecognition | null => {
if (typeof window === 'undefined') return null; if (typeof window === 'undefined') return null;
const Ctor = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition || null; const Ctor = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition || null;
console.log('[VoiceInput] 构造函数:', Ctor ? Ctor.name || 'webkitSpeechRecognition' : 'null');
return Ctor; return Ctor;
}; };
const stopVoiceRecording = () => { const stopVoiceRecording = () => {
console.log('[VoiceInput] stopVoiceRecording called, isRecording:', isRecording.value);
if (recognitionInstance.value) { if (recognitionInstance.value) {
try { try {
recognitionInstance.value.stop(); recognitionInstance.value.stop();
console.log('[VoiceInput] recognition.stop() called');
} catch (e) { } catch (e) {
console.warn('[VoiceInput] recognition.stop() error:', e); console.warn('[VoiceInput] recognition.stop() error:', e);
} }
@ -2053,27 +2047,15 @@ const initSpeechRecognition = () => {
voiceAnchorPos = 0; voiceAnchorPos = 0;
} }
lastVoiceTextLength = 0; lastVoiceTextLength = 0;
console.log('[VoiceInput] init: anchorPos=', voiceAnchorPos);
recognition.onresult = (event: SpeechRecognitionEvent) => { recognition.onresult = (event: SpeechRecognitionEvent) => {
console.log('[VoiceInput] onresult fired:', {
resultLength: event.results.length,
resultIndex: (event as any).resultIndex
});
let fullText = ''; let fullText = '';
for (let i = 0; i < event.results.length; i++) { for (let i = 0; i < event.results.length; i++) {
const r = event.results[i]; const r = event.results[i];
console.log(`[VoiceInput] result[${i}]:`, {
transcript: r[0]?.transcript,
isFinal: r.isFinal,
confidence: r[0]?.confidence
});
fullText += r[0].transcript; fullText += r[0].transcript;
} }
console.log('[VoiceInput] fullText:', JSON.stringify(fullText));
if (!fullText) { if (!fullText) {
console.log('[VoiceInput] fullText empty, skip');
return; return;
} }
@ -2102,7 +2084,6 @@ const initSpeechRecognition = () => {
view.focus(); view.focus();
lastVoiceTextLength = fullText.length; lastVoiceTextLength = fullText.length;
console.log('[VoiceInput] inserted ok, lastVoiceTextLength=', lastVoiceTextLength);
emit('update:input-message', getEditorPlainText()); emit('update:input-message', getEditorPlainText());
emit('input-change'); emit('input-change');
@ -2114,7 +2095,6 @@ const initSpeechRecognition = () => {
recognition.onerror = (event: SpeechRecognitionErrorEvent) => { recognition.onerror = (event: SpeechRecognitionErrorEvent) => {
console.warn('[VoiceInput] onerror:', { error: event.error, message: (event as any).message }); console.warn('[VoiceInput] onerror:', { error: event.error, message: (event as any).message });
if (event.error === 'aborted') { if (event.error === 'aborted') {
console.log('[VoiceInput] aborted (user stop), ignore');
return; return;
} }
// no-speech / network / not-allowed / service-not-allowed // no-speech / network / not-allowed / service-not-allowed
@ -2123,35 +2103,27 @@ const initSpeechRecognition = () => {
}; };
recognition.onstart = () => { recognition.onstart = () => {
console.log('[VoiceInput] onstart: 录音已开始');
}; };
recognition.onaudiostart = () => { recognition.onaudiostart = () => {
console.log('[VoiceInput] onaudiostart: 音频捕获开始');
}; };
recognition.onsoundstart = () => { recognition.onsoundstart = () => {
console.log('[VoiceInput] onsoundstart: 检测到声音');
}; };
recognition.onspeechstart = () => { recognition.onspeechstart = () => {
console.log('[VoiceInput] onspeechstart: 检测到语音');
}; };
recognition.onspeechend = () => { recognition.onspeechend = () => {
console.log('[VoiceInput] onspeechend: 语音结束');
}; };
recognition.onsoundend = () => { recognition.onsoundend = () => {
console.log('[VoiceInput] onsoundend: 声音结束');
}; };
recognition.onaudioend = () => { recognition.onaudioend = () => {
console.log('[VoiceInput] onaudioend: 音频捕获结束');
}; };
recognition.onend = () => { recognition.onend = () => {
console.log('[VoiceInput] onend: 录音结束, isRecording=', isRecording.value);
isRecording.value = false; isRecording.value = false;
recognitionInstance.value = null; recognitionInstance.value = null;
voiceAnchorPos = 0; voiceAnchorPos = 0;
@ -2162,7 +2134,6 @@ const initSpeechRecognition = () => {
}; };
const toggleVoiceRecording = () => { const toggleVoiceRecording = () => {
console.log('[VoiceInput] toggleVoiceRecording, isRecording=', isRecording.value);
// Android Bridge // Android Bridge
const bridge = (window as any).AndroidVoiceBridge; const bridge = (window as any).AndroidVoiceBridge;
@ -2193,7 +2164,6 @@ const toggleVoiceRecording = () => {
try { try {
recognition.start(); recognition.start();
console.log('[VoiceInput] recognition.start() called');
recognitionInstance.value = recognition; recognitionInstance.value = recognition;
isRecording.value = true; isRecording.value = true;
} catch (error) { } catch (error) {

View File

@ -208,7 +208,6 @@ function appendToTerm(data: string) {
function renderSessionLog() { function renderSessionLog() {
if (!term || !activeSession.value) return; if (!term || !activeSession.value) return;
const log = sessionLogs.value[activeSession.value] || ''; const log = sessionLogs.value[activeSession.value] || '';
console.log('[TerminalPanel] renderSessionLog:', activeSession.value, 'len:', log.length, 'ready:', _historyReady.value[activeSession.value], 'hydrated:', sessionHydrated.value[activeSession.value]);
term.clear(); term.clear();
if (log) { if (log) {
term.write(log, () => { term.write(log, () => {
@ -218,7 +217,6 @@ function renderSessionLog() {
} }
function switchToSession(name: string) { function switchToSession(name: string) {
console.log('[TerminalPanel] switchToSession:', name);
if (!name) return; if (!name) return;
activeSession.value = name; activeSession.value = name;
if (!sessionHydrated.value[name]) { if (!sessionHydrated.value[name]) {
@ -227,7 +225,6 @@ function switchToSession(name: string) {
delete updatedTimes[name]; delete updatedTimes[name];
_historyLastEventTime.value = updatedTimes; _historyLastEventTime.value = updatedTimes;
if (socket?.connected) { if (socket?.connected) {
console.log('[TerminalPanel] requesting history for:', name);
socket.emit('get_terminal_output', { session: name, lines: 0, conversation_id: props.conversationId }); socket.emit('get_terminal_output', { session: name, lines: 0, conversation_id: props.conversationId });
} }
} }
@ -236,12 +233,10 @@ function switchToSession(name: string) {
// ---- watchers ---- // ---- watchers ----
watch(activeSession, (val) => { watch(activeSession, (val) => {
console.log('[TerminalPanel] activeSession:', val);
if (term) renderSessionLog(); if (term) renderSessionLog();
}); });
watch(sessionKeys, (keys) => { watch(sessionKeys, (keys) => {
console.log('[TERMINAL_DEBUG] sessionKeys:', keys);
if (keys.length > 0 && term && !activeSession.value) { if (keys.length > 0 && term && !activeSession.value) {
switchToSession(keys[0]); switchToSession(keys[0]);
} }
@ -250,7 +245,6 @@ watch(sessionKeys, (keys) => {
// //
watch(() => props.workspaceId, (newId, oldId) => { watch(() => props.workspaceId, (newId, oldId) => {
if (newId && oldId && newId !== oldId) { if (newId && oldId && newId !== oldId) {
console.log('[TerminalPanel] workspace changed:', oldId, '->', newId);
// //
if (socket) { if (socket) {
socket.disconnect(); socket.disconnect();
@ -270,7 +264,6 @@ watch(() => props.workspaceId, (newId, oldId) => {
// terminal shell // terminal shell
watch(() => props.conversationId, (newId, oldId) => { watch(() => props.conversationId, (newId, oldId) => {
if (newId !== oldId) { if (newId !== oldId) {
console.log('[TerminalPanel] conversation changed:', oldId, '->', newId);
sessions.value = {}; sessions.value = {};
activeSession.value = ''; activeSession.value = '';
sessionLogs.value = {}; sessionLogs.value = {};
@ -286,7 +279,6 @@ watch(() => props.conversationId, (newId, oldId) => {
// ---- socket ---- // ---- socket ----
async function initSocket() { async function initSocket() {
console.log('[TerminalPanel] initSocket start');
socket = createSocketClient('/', { socket = createSocketClient('/', {
transports: ['websocket', 'polling'], transports: ['websocket', 'polling'],
@ -319,16 +311,13 @@ async function initSocket() {
} }
socket.on('connect', () => { socket.on('connect', () => {
console.log('[TerminalPanel] socket connected');
socket!.emit('terminal_subscribe', { all: true, conversation_id: props.conversationId }); socket!.emit('terminal_subscribe', { all: true, conversation_id: props.conversationId });
}); });
socket.on('disconnect', () => { socket.on('disconnect', () => {
console.log('[TerminalPanel] socket disconnected');
}); });
socket.on('terminal_subscribed', (data: any) => { socket.on('terminal_subscribed', (data: any) => {
console.log('[TerminalPanel] terminal_subscribed:', data);
if (data?.terminals) { if (data?.terminals) {
const map: Record<string, { working_dir?: string; shell?: string }> = {}; const map: Record<string, { working_dir?: string; shell?: string }> = {};
for (const t of data.terminals) { for (const t of data.terminals) {
@ -343,7 +332,6 @@ async function initSocket() {
socket.on('terminal_started', (data: any) => { socket.on('terminal_started', (data: any) => {
if (!acceptTerminalBroadcast(data)) return; if (!acceptTerminalBroadcast(data)) return;
console.log('[TerminalPanel] terminal_started:', data);
sessions.value = { sessions.value = {
...sessions.value, ...sessions.value,
[data.session]: { working_dir: data.working_dir, shell: 'bash' } [data.session]: { working_dir: data.working_dir, shell: 'bash' }
@ -353,7 +341,6 @@ async function initSocket() {
socket.on('terminal_list_update', (data: any) => { socket.on('terminal_list_update', (data: any) => {
if (!acceptTerminalBroadcast(data)) return; if (!acceptTerminalBroadcast(data)) return;
console.log('[TerminalPanel] terminal_list_update:', data);
if (data?.terminals) { if (data?.terminals) {
const map: Record<string, { working_dir?: string; shell?: string }> = {}; const map: Record<string, { working_dir?: string; shell?: string }> = {};
for (const t of data.terminals) { for (const t of data.terminals) {
@ -376,7 +363,6 @@ async function initSocket() {
const historyTime = _historyLastEventTime.value[s] || 0; const historyTime = _historyLastEventTime.value[s] || 0;
const eventTime = typeof data.timestamp === 'number' ? data.timestamp : 0; const eventTime = typeof data.timestamp === 'number' ? data.timestamp : 0;
if (historyTime > 0 && eventTime > 0 && eventTime <= historyTime) { if (historyTime > 0 && eventTime > 0 && eventTime <= historyTime) {
console.log('[TerminalPanel] terminal_output DEDUP skip:', s, 'eventTime:', eventTime, '<= historyTime:', historyTime);
return; return;
} }
@ -384,17 +370,14 @@ async function initSocket() {
// _historyReady false // _historyReady false
sessionLogs.value[s] = (sessionLogs.value[s] || '') + delta; sessionLogs.value[s] = (sessionLogs.value[s] || '') + delta;
if (s === activeSession.value && term && _historyReady.value[s]) { if (s === activeSession.value && term && _historyReady.value[s]) {
console.log('[TerminalPanel] terminal_output WRITE:', s, 'len:', delta.length);
term.write(delta); term.write(delta);
} else { } else {
console.log('[TerminalPanel] terminal_output SKIP:', s, 'len:', delta.length, 'isActive:', s === activeSession.value, 'ready:', _historyReady.value[s]);
} }
if (!activeSession.value) switchToSession(s); if (!activeSession.value) switchToSession(s);
}); });
socket.on('terminal_input', (data: any) => { socket.on('terminal_input', (data: any) => {
if (!acceptTerminalBroadcast(data)) return; if (!acceptTerminalBroadcast(data)) return;
console.log('[TerminalPanel] terminal_input:', data.session);
// //
// //
if (!activeSession.value && data.session) switchToSession(data.session); if (!activeSession.value && data.session) switchToSession(data.session);
@ -402,7 +385,6 @@ async function initSocket() {
socket.on('terminal_closed', (data: any) => { socket.on('terminal_closed', (data: any) => {
if (!acceptTerminalBroadcast(data)) return; if (!acceptTerminalBroadcast(data)) return;
console.log('[TerminalPanel] terminal_closed:', data);
const updated = { ...sessions.value }; const updated = { ...sessions.value };
delete updated[data.session]; delete updated[data.session];
sessions.value = updated; sessions.value = updated;
@ -414,7 +396,6 @@ async function initSocket() {
socket.on('terminal_reset', (data: any) => { socket.on('terminal_reset', (data: any) => {
if (!acceptTerminalBroadcast(data)) return; if (!acceptTerminalBroadcast(data)) return;
console.log('[TerminalPanel] terminal_reset:', data);
const target = data.session || activeSession.value; const target = data.session || activeSession.value;
if (target) { if (target) {
sessionLogs.value = { ...sessionLogs.value, [target]: '' }; sessionLogs.value = { ...sessionLogs.value, [target]: '' };
@ -428,12 +409,10 @@ async function initSocket() {
socket.on('terminal_switched', (data: any) => { socket.on('terminal_switched', (data: any) => {
if (!acceptTerminalBroadcast(data)) return; if (!acceptTerminalBroadcast(data)) return;
console.log('[TerminalPanel] terminal_switched:', data);
if (data.current) switchToSession(data.current); if (data.current) switchToSession(data.current);
}); });
const handleHistory = (data: any) => { const handleHistory = (data: any) => {
console.log('[TerminalPanel] handleHistory FIRED, event session:', data.session, 'data keys:', Object.keys(data).join(','));
const s = data.session || data.active; const s = data.session || data.active;
if (!s) return; if (!s) return;
const raw = data.output || data.data || ''; const raw = data.output || data.data || '';
@ -443,7 +422,6 @@ async function initSocket() {
} else if (Array.isArray(raw)) { } else if (Array.isArray(raw)) {
payload = raw.join('\n'); payload = raw.join('\n');
} }
console.log('[TerminalPanel] handleHistory:', s, 'rawLen:', raw.length, 'payloadLen:', payload.length, 'isActive:', s === activeSession.value);
if (payload) { if (payload) {
sessionLogs.value[s] = payload; sessionLogs.value[s] = payload;
} }
@ -454,7 +432,6 @@ async function initSocket() {
// terminal_output // terminal_output
const lastEventTime = typeof data.last_event_time === 'number' ? data.last_event_time : 0; const lastEventTime = typeof data.last_event_time === 'number' ? data.last_event_time : 0;
_historyLastEventTime.value = { ..._historyLastEventTime.value, [s]: lastEventTime }; _historyLastEventTime.value = { ..._historyLastEventTime.value, [s]: lastEventTime };
console.log('[TerminalPanel] handleHistory SAVED:', s, 'finalLen:', payload.length, 'calling render:', s === activeSession.value);
if (s === activeSession.value) { if (s === activeSession.value) {
renderSessionLog(); renderSessionLog();
} }
@ -464,7 +441,6 @@ async function initSocket() {
socket.on('terminal_history', handleHistory); socket.on('terminal_history', handleHistory);
socket.connect(); socket.connect();
console.log('[TerminalPanel] socket connecting...');
} }
// ---- ---- // ---- ----

View File

@ -158,30 +158,22 @@ const emit = defineEmits<{
}>(); }>();
const handleCloseClick = () => { const handleCloseClick = () => {
console.log('[sidebarDEBUG] ToolApprovalPanel close button clicked');
emit('close'); emit('close');
}; };
// - 使 // - 使
const isMobileViewport = computed(() => { const isMobileViewport = computed(() => {
const isMobile = typeof window !== 'undefined' && window.innerWidth <= 768; const isMobile = typeof window !== 'undefined' && window.innerWidth <= 768;
console.log('[sidebarDEBUG] isMobileViewport computed:', isMobile, 'windowWidth:', window?.innerWidth);
return isMobile; return isMobile;
}); });
onMounted(() => { onMounted(() => {
console.log('[sidebarDEBUG] ToolApprovalPanel mounted');
console.log('[sidebarDEBUG] window.innerWidth:', window.innerWidth);
console.log('[sidebarDEBUG] isMobileViewport:', isMobileViewport.value);
console.log('[sidebarDEBUG] body[data-theme]:', document.body.getAttribute('data-theme'));
// //
const aside = document.querySelector('.tool-approval-panel'); const aside = document.querySelector('.tool-approval-panel');
const sidebarHeader = document.querySelector('.tool-approval-panel .sidebar-header'); const sidebarHeader = document.querySelector('.tool-approval-panel .sidebar-header');
if (sidebarHeader) { if (sidebarHeader) {
const computedStyle = window.getComputedStyle(sidebarHeader); const computedStyle = window.getComputedStyle(sidebarHeader);
console.log('[sidebarDEBUG] sidebar-header computed background:', computedStyle.backgroundColor);
console.log('[sidebarDEBUG] sidebar-header computed padding:', computedStyle.paddingTop, computedStyle.paddingBottom);
} }
}); });

View File

@ -865,10 +865,6 @@ const persistPinnedWorkspaces = () => {
const next = Array.from(pinnedWorkspaceIds.value); const next = Array.from(pinnedWorkspaceIds.value);
const current = personalizationStore.form.sidebar_pinned_workspaces || []; const current = personalizationStore.form.sidebar_pinned_workspaces || [];
if (JSON.stringify(next) === JSON.stringify(current)) return; if (JSON.stringify(next) === JSON.stringify(current)) return;
console.log('[sidebar-debug] persistPinnedWorkspaces', {
next: JSON.parse(JSON.stringify(next)),
current: JSON.parse(JSON.stringify(current))
});
personalizationStore.updateField({ personalizationStore.updateField({
key: 'sidebar_pinned_workspaces', key: 'sidebar_pinned_workspaces',
value: next value: next
@ -880,10 +876,6 @@ const persistWorkspaceOrder = () => {
const next = Array.from(workspaceOrder.value); const next = Array.from(workspaceOrder.value);
const current = personalizationStore.form.sidebar_workspace_order || []; const current = personalizationStore.form.sidebar_workspace_order || [];
if (JSON.stringify(next) === JSON.stringify(current)) return; if (JSON.stringify(next) === JSON.stringify(current)) return;
console.log('[sidebar-debug] persistWorkspaceOrder', {
next: JSON.parse(JSON.stringify(next)),
current: JSON.parse(JSON.stringify(current))
});
personalizationStore.updateField({ personalizationStore.updateField({
key: 'sidebar_workspace_order', key: 'sidebar_workspace_order',
value: next value: next
@ -893,19 +885,12 @@ const persistWorkspaceOrder = () => {
const bumpCurrentWorkspaceToTop = () => { const bumpCurrentWorkspaceToTop = () => {
if (!sidebarSortLoaded.value) return; if (!sidebarSortLoaded.value) return;
const currentId = String(props.currentWorkspaceId || ''); const currentId = String(props.currentWorkspaceId || '');
console.log('[sidebar-debug] bumpCurrentWorkspaceToTop', {
currentId,
orderBefore: JSON.parse(JSON.stringify(workspaceOrder.value))
});
if (!currentId || pinnedWorkspaceIds.value.has(currentId)) return; if (!currentId || pinnedWorkspaceIds.value.has(currentId)) return;
if (workspaceOrder.value[0] === currentId) return; if (workspaceOrder.value[0] === currentId) return;
const order = workspaceOrder.value.filter((item) => item !== currentId); const order = workspaceOrder.value.filter((item) => item !== currentId);
order.unshift(currentId); order.unshift(currentId);
workspaceOrder.value = order; workspaceOrder.value = order;
persistWorkspaceOrder(); persistWorkspaceOrder();
console.log('[sidebar-debug] bumpCurrentWorkspaceToTop after', {
orderAfter: JSON.parse(JSON.stringify(workspaceOrder.value))
});
}; };
const syncWorkspaceOrderWithWorkspaces = (workspaces: any[]) => { const syncWorkspaceOrderWithWorkspaces = (workspaces: any[]) => {
@ -921,12 +906,6 @@ const syncWorkspaceOrderWithWorkspaces = (workspaces: any[]) => {
const removedIds = new Set( const removedIds = new Set(
workspaceOrder.value.filter((id) => !ids.includes(id)) workspaceOrder.value.filter((id) => !ids.includes(id))
); );
console.log('[sidebar-debug] syncWorkspaceOrderWithWorkspaces', {
ids,
newIds,
removedIds: Array.from(removedIds),
orderBefore: JSON.parse(JSON.stringify(workspaceOrder.value))
});
if (newIds.length || removedIds.size) { if (newIds.length || removedIds.size) {
workspaceOrder.value = workspaceOrder.value workspaceOrder.value = workspaceOrder.value
.filter((id) => !removedIds.has(id)) .filter((id) => !removedIds.has(id))
@ -937,10 +916,6 @@ const syncWorkspaceOrderWithWorkspaces = (workspaces: any[]) => {
const loadSidebarSortFromStore = () => { const loadSidebarSortFromStore = () => {
if (!personalizationStore.loaded || sidebarSortLoaded.value) return; if (!personalizationStore.loaded || sidebarSortLoaded.value) return;
console.log('[sidebar-debug] loadSidebarSortFromStore start', {
pinned: JSON.parse(JSON.stringify(personalizationStore.form.sidebar_pinned_workspaces)),
order: JSON.parse(JSON.stringify(personalizationStore.form.sidebar_workspace_order))
});
syncPinnedFromStore(); syncPinnedFromStore();
syncOrderFromStore(); syncOrderFromStore();
sidebarSortLoaded.value = true; sidebarSortLoaded.value = true;
@ -948,10 +923,6 @@ const loadSidebarSortFromStore = () => {
syncWorkspaceOrderWithWorkspaces(props.workspaces); syncWorkspaceOrderWithWorkspaces(props.workspaces);
} }
bumpCurrentWorkspaceToTop(); bumpCurrentWorkspaceToTop();
console.log('[sidebar-debug] loadSidebarSortFromStore end', {
pinned: Array.from(pinnedWorkspaceIds.value),
order: JSON.parse(JSON.stringify(workspaceOrder.value))
});
}; };
watch( watch(
@ -1165,7 +1136,6 @@ watch(
); );
const handleWorkspaceConversationClick = (conversationId: string, workspaceId: string) => { const handleWorkspaceConversationClick = (conversationId: string, workspaceId: string) => {
console.log('[sidebar-debug] handleWorkspaceConversationClick', { conversationId, workspaceId });
openWorkspaceMenuId.value = null; openWorkspaceMenuId.value = null;
emit('select-workspace-conversation', { conversationId, workspaceId }); emit('select-workspace-conversation', { conversationId, workspaceId });
}; };

View File

@ -120,7 +120,6 @@ export function useEasterEgg() {
}, durationSeconds * 1000); }, durationSeconds * 1000);
uiStore.setEasterEggState({ cleanupTimer: timer }); uiStore.setEasterEggState({ cleanupTimer: timer });
if (payload?.message) { if (payload?.message) {
console.info(`[彩蛋] ${payload.display_name || effectName}: ${payload.message}`);
} }
}; };

View File

@ -24,7 +24,7 @@ import { useQuickDockStore } from '../stores/quickDock';
export async function initializeLegacySocket(ctx: any) { export async function initializeLegacySocket(ctx: any) {
try { try {
const SOCKET_DEBUG_LOGS_ENABLED = true; const SOCKET_DEBUG_LOGS_ENABLED = false;
const socketLog = (...args: any[]) => { const socketLog = (...args: any[]) => {
if (!SOCKET_DEBUG_LOGS_ENABLED) { if (!SOCKET_DEBUG_LOGS_ENABLED) {
return; return;
@ -74,20 +74,10 @@ export async function initializeLegacySocket(ctx: any) {
} }
if (action.tool.intent_full === text) { if (action.tool.intent_full === text) {
if (console && console.debug) { if (console && console.debug) {
console.debug('[tool_intent] skip (same text)', {
id: action?.id || action?.tool?.id,
name: action?.tool?.name,
text
});
} }
return; return;
} }
if (typeof console !== 'undefined' && console.debug) { if (typeof console !== 'undefined' && console.debug) {
console.debug('[tool_intent] typing start', {
id: action?.id || action?.tool?.id,
name: action?.tool?.name,
text
});
} }
if (action.tool.intent_full === text && action.tool.intent_rendered === text) { if (action.tool.intent_full === text && action.tool.intent_rendered === text) {
return; return;
@ -105,11 +95,6 @@ export async function initializeLegacySocket(ctx: any) {
action.tool.intent_typing_timer = window.setInterval(() => { action.tool.intent_typing_timer = window.setInterval(() => {
action.tool.intent_rendered = text.slice(0, index + 1); action.tool.intent_rendered = text.slice(0, index + 1);
if (index === 0 && console && console.debug) { if (index === 0 && console && console.debug) {
console.debug('[tool_intent] typing tick', {
id: action?.id || action?.tool?.id,
name: action?.tool?.name,
next: action.tool.intent_rendered
});
} }
index += 1; index += 1;
if (index >= text.length) { if (index >= text.length) {
@ -117,11 +102,6 @@ export async function initializeLegacySocket(ctx: any) {
action.tool.intent_typing_timer = null; action.tool.intent_typing_timer = null;
action.tool.intent_rendered = text; action.tool.intent_rendered = text;
if (console && console.debug) { if (console && console.debug) {
console.debug('[tool_intent] typing done', {
id: action?.id || action?.tool?.id,
name: action?.tool?.name,
full: text
});
} }
} }
if (typeof ctx?.$forceUpdate === 'function') { if (typeof ctx?.$forceUpdate === 'function') {
@ -789,7 +769,6 @@ export async function initializeLegacySocket(ctx: any) {
// 监听对话变更事件 // 监听对话变更事件
ctx.socket.on('conversation_changed', (data) => { ctx.socket.on('conversation_changed', (data) => {
socketLog('对话已切换:', data); socketLog('对话已切换:', data);
console.log('[conv-trace] socket:conversation_changed', data);
// 初始化期间不修改 currentConversationId避免与 bootstrapRoute 冲突 // 初始化期间不修改 currentConversationId避免与 bootstrapRoute 冲突
if (ctx.initialRouteResolved) { if (ctx.initialRouteResolved) {
@ -1177,11 +1156,6 @@ export async function initializeLegacySocket(ctx: any) {
socketLog('文本开始 (轮询模式,跳过)'); socketLog('文本开始 (轮询模式,跳过)');
return; return;
} }
console.log('[DEBUG] 收到 text_start 事件:', {
currentConversationId: ctx.currentConversationId,
messagesCount: ctx.messages.length,
currentMessageIndex: ctx.currentMessageIndex
});
socketLog('文本开始'); socketLog('文本开始');
logStreamingDebug('socket:text_start'); logStreamingDebug('socket:text_start');
finalizeStreamingText({ force: true }); finalizeStreamingText({ force: true });
@ -1192,7 +1166,6 @@ export async function initializeLegacySocket(ctx: any) {
streamingState.activeTextAction = action || ensureActiveTextAction(); streamingState.activeTextAction = action || ensureActiveTextAction();
ensureActiveMessageBinding(); ensureActiveMessageBinding();
ctx.$forceUpdate(); ctx.$forceUpdate();
console.log('[DEBUG] text_start 处理完成');
}); });
// 文本内容块 // 文本内容块
@ -1201,12 +1174,6 @@ export async function initializeLegacySocket(ctx: any) {
if (ctx.usePollingMode && !ctx.waitingForSubAgent) { if (ctx.usePollingMode && !ctx.waitingForSubAgent) {
return; return;
} }
console.log('[DEBUG] 收到 text_chunk 事件:', {
conversation_id: data?.conversation_id,
currentConversationId: ctx.currentConversationId,
chunkLength: (data?.content || '').length,
index: data?.index
});
logStreamingDebug('socket:text_chunk', { logStreamingDebug('socket:text_chunk', {
index: data?.index ?? null, index: data?.index ?? null,
elapsed: data?.elapsed ?? null, elapsed: data?.elapsed ?? null,
@ -1301,30 +1268,15 @@ export async function initializeLegacySocket(ctx: any) {
if (ctx.dropToolEvents) { if (ctx.dropToolEvents) {
return; return;
} }
console.log('[DEBUG] 收到 tool_preparing 事件:', {
name: data.name,
id: data.id,
conversation_id: data?.conversation_id,
currentConversationId: ctx.currentConversationId,
match: data?.conversation_id === ctx.currentConversationId
});
socketLog('工具准备中:', data.name); socketLog('工具准备中:', data.name);
if (typeof console !== 'undefined' && console.debug) { if (typeof console !== 'undefined' && console.debug) {
console.debug('[tool_intent] preparing', {
id: data?.id,
name: data?.name,
intent: data?.intent,
convo: data?.conversation_id
});
} }
if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) { if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) {
console.log('[DEBUG] 跳过 tool_preparing (对话不匹配)');
socketLog('跳过tool_preparing(对话不匹配)', data.conversation_id); socketLog('跳过tool_preparing(对话不匹配)', data.conversation_id);
return; return;
} }
const msg = ctx.chatEnsureAssistantMessage(); const msg = ctx.chatEnsureAssistantMessage();
if (!msg) { if (!msg) {
console.log('[DEBUG] tool_preparing: 无法获取assistant消息');
return; return;
} }
if (msg.awaitingFirstContent) { if (msg.awaitingFirstContent) {
@ -1355,7 +1307,6 @@ export async function initializeLegacySocket(ctx: any) {
if (data.intent) { if (data.intent) {
startIntentTyping(action, data.intent); startIntentTyping(action, data.intent);
} }
console.log('[DEBUG] tool_preparing 处理完成action已添加');
ctx.$forceUpdate(); ctx.$forceUpdate();
ctx.conditionalScrollToBottom(); ctx.conditionalScrollToBottom();
if (ctx.monitorPreviewTool) { if (ctx.monitorPreviewTool) {
@ -1376,12 +1327,6 @@ export async function initializeLegacySocket(ctx: any) {
return; return;
} }
if (typeof console !== 'undefined' && console.debug) { if (typeof console !== 'undefined' && console.debug) {
console.debug('[tool_intent] update', {
id: data?.id,
name: data?.name,
intent: data?.intent,
convo: data?.conversation_id
});
} }
const target = const target =
ctx.toolFindAction(data.id, data.preparing_id, data.execution_id) || ctx.toolFindAction(data.id, data.preparing_id, data.execution_id) ||
@ -1689,35 +1634,21 @@ export async function initializeLegacySocket(ctx: any) {
// 任务完成重点更新Token统计 // 任务完成重点更新Token统计
ctx.socket.on('task_complete', (data) => { ctx.socket.on('task_complete', (data) => {
console.log('[DEBUG] 收到 task_complete 事件:', data);
console.log('[DEBUG] 当前状态 (before task_complete):', {
taskInProgress: ctx.taskInProgress,
streamingMessage: ctx.streamingMessage,
has_running_sub_agents: data.has_running_sub_agents
});
socketLog('任务完成', data); socketLog('任务完成', data);
const hasRunningMultiAgent = !!data?.has_running_multi_agent; const hasRunningMultiAgent = !!data?.has_running_multi_agent;
// 多智能体模式下,若仍有运行中的多智能体实例,保持对话运行态,继续接收后续消息; // 多智能体模式下,若仍有运行中的多智能体实例,保持对话运行态,继续接收后续消息;
// 但此时主智能体已空闲不应阻塞输入区waitingForSubAgent=false // 但此时主智能体已空闲不应阻塞输入区waitingForSubAgent=false
if (hasRunningMultiAgent) { if (hasRunningMultiAgent) {
console.log('[DEBUG] 多智能体实例仍在运行,保持任务状态但不阻塞输入');
} else if (ctx.multiAgentMode || !data.has_running_sub_agents) { } else if (ctx.multiAgentMode || !data.has_running_sub_agents) {
console.log('[DEBUG] 没有运行中的子智能体/多智能体,重置任务状态');
if (ctx.waitingForSubAgent) { if (ctx.waitingForSubAgent) {
ctx.waitingForSubAgent = false; ctx.waitingForSubAgent = false;
} }
ctx.taskInProgress = false; ctx.taskInProgress = false;
ctx.scheduleResetAfterTask('socket:task_complete', { preserveMonitorWindows: true }); ctx.scheduleResetAfterTask('socket:task_complete', { preserveMonitorWindows: true });
} else { } else {
console.log('[DEBUG] 有运行中的子智能体,保持任务状态');
} }
console.log('[DEBUG] 当前状态 (after task_complete):', {
taskInProgress: ctx.taskInProgress,
streamingMessage: ctx.streamingMessage
});
resetPendingToolEvents(); resetPendingToolEvents();
// 任务完成后立即更新Token统计关键修复 // 任务完成后立即更新Token统计关键修复
@ -1729,12 +1660,6 @@ export async function initializeLegacySocket(ctx: any) {
// 子智能体等待状态 // 子智能体等待状态
ctx.socket.on('sub_agent_waiting', (data) => { ctx.socket.on('sub_agent_waiting', (data) => {
console.log('[DEBUG] 收到 sub_agent_waiting 事件:', data);
console.log('[DEBUG] 当前状态 (before sub_agent_waiting):', {
taskInProgress: ctx.taskInProgress,
streamingMessage: ctx.streamingMessage,
stopRequested: ctx.stopRequested
});
socketLog('等待子智能体完成:', data); socketLog('等待子智能体完成:', data);
// 多智能体模式下,子智能体 idle/running 是常态,不阻塞主对话输入区 // 多智能体模式下,子智能体 idle/running 是常态,不阻塞主对话输入区
@ -1748,13 +1673,6 @@ export async function initializeLegacySocket(ctx: any) {
ctx.stopRequested = false; ctx.stopRequested = false;
} }
console.log('[DEBUG] 当前状态 (after sub_agent_waiting):', {
taskInProgress: ctx.taskInProgress,
streamingMessage: ctx.streamingMessage,
stopRequested: ctx.stopRequested,
waitingForSubAgent: ctx.waitingForSubAgent
});
// 显示等待提示 // 显示等待提示
if (typeof ctx.appendSystemAction === 'function') { if (typeof ctx.appendSystemAction === 'function') {
const taskList = data.tasks const taskList = data.tasks
@ -1764,7 +1682,6 @@ export async function initializeLegacySocket(ctx: any) {
} }
ctx.$forceUpdate(); ctx.$forceUpdate();
console.log('[DEBUG] sub_agent_waiting 处理完成');
}); });
// 聚焦文件更新 // 聚焦文件更新
@ -1886,7 +1803,6 @@ export async function initializeLegacySocket(ctx: any) {
// === 实时终端事件 === // === 实时终端事件 ===
ctx.socket.on('terminal_subscribed', (data) => { ctx.socket.on('terminal_subscribed', (data) => {
console.log('[Socket] terminal_subscribed:', data);
if (data?.terminals) { if (data?.terminals) {
const sessions: Record<string, { working_dir?: string; shell?: string }> = {}; const sessions: Record<string, { working_dir?: string; shell?: string }> = {};
for (const t of data.terminals) { for (const t of data.terminals) {
@ -1903,7 +1819,6 @@ export async function initializeLegacySocket(ctx: any) {
}); });
ctx.socket.on('terminal_started', (data) => { ctx.socket.on('terminal_started', (data) => {
console.log('[Socket] terminal_started:', data);
if (data?.session) { if (data?.session) {
const sessions = { ...ctx.terminalSessions }; const sessions = { ...ctx.terminalSessions };
sessions[data.session] = { sessions[data.session] = {

View File

@ -17,17 +17,16 @@ let showHtmlDebugCount = 0;
const SHOW_HTML_DEBUG_MAX = 500; const SHOW_HTML_DEBUG_MAX = 500;
function isShowHtmlDebugEnabled() { function isShowHtmlDebugEnabled() {
if (typeof window === 'undefined') return true; if (typeof window === 'undefined') return false;
try { try {
const flag = (window as any).__SHOW_HTML_DEBUG__; const flag = (window as any).__SHOW_HTML_DEBUG__;
if (flag === false || flag === '0') return false;
if (flag === true || flag === '1') return true; if (flag === true || flag === '1') return true;
if (flag === false || flag === '0') return false;
const localFlag = window.localStorage?.getItem('showHtmlDebug'); const localFlag = window.localStorage?.getItem('showHtmlDebug');
if (localFlag === '0' || localFlag === 'false') return false;
if (localFlag === '1' || localFlag === 'true') return true; if (localFlag === '1' || localFlag === 'true') return true;
return true; return false;
} catch { } catch {
return true; return false;
} }
} }

View File

@ -77,7 +77,8 @@ function isScrollDebugEnabled() {
} }
function isShowHtmlScrollTraceEnabled() { function isShowHtmlScrollTraceEnabled() {
if (typeof window === 'undefined') return true; // 默认关闭:排障时通过 window.__SHOW_HTML_SCROLL_TRACE__ = true 或 localStorage.showHtmlScrollTrace = '1' 显式打开
if (typeof window === 'undefined') return false;
try { try {
const explicit = (window as any).__SHOW_HTML_SCROLL_TRACE__; const explicit = (window as any).__SHOW_HTML_SCROLL_TRACE__;
if (explicit === false || explicit === '0') return false; if (explicit === false || explicit === '0') return false;
@ -85,9 +86,9 @@ function isShowHtmlScrollTraceEnabled() {
const localFlag = window.localStorage?.getItem('showHtmlScrollTrace'); const localFlag = window.localStorage?.getItem('showHtmlScrollTrace');
if (localFlag === '0' || localFlag === 'false') return false; if (localFlag === '0' || localFlag === 'false') return false;
if (localFlag === '1' || localFlag === 'true') return true; if (localFlag === '1' || localFlag === 'true') return true;
return true; return false;
} catch { } catch {
return true; return false;
} }
} }

View File

@ -84,7 +84,6 @@ function clearAwaitingFirstContent(message: any) {
} }
} }
const userMDebug = (...args: any[]) => { const userMDebug = (...args: any[]) => {
console.log('[USERMDEBUG]', ...args);
}; };
export const useChatStore = defineStore('chat', { export const useChatStore = defineStore('chat', {
@ -222,11 +221,6 @@ export const useChatStore = defineStore('chat', {
this.streamingMessage = true; this.streamingMessage = true;
message.awaitingFirstContent = true; message.awaitingFirstContent = true;
console.log('[DEBUG_AWAITING] ===== startAssistantMessage =====', {
awaitingFirstContent: message.awaitingFirstContent,
generatingLabel: message.generatingLabel
});
return message; return message;
}, },
startThinkingAction() { startThinkingAction() {

View File

@ -188,11 +188,6 @@ export const useConversationStore = defineStore('conversation', {
{ reset = false, refresh = false } = {} { reset = false, refresh = false } = {}
) { ) {
if (!workspaceId) return; if (!workspaceId) return;
console.log('[sidebar-debug] loadWorkspaceConversations', {
workspaceId,
reset,
refresh
});
let index = this.workspaceGroups.findIndex((g) => g.workspaceId === workspaceId); let index = this.workspaceGroups.findIndex((g) => g.workspaceId === workspaceId);
if (index === -1) { if (index === -1) {
this.ensureWorkspaceGroup(workspaceId); this.ensureWorkspaceGroup(workspaceId);

View File

@ -1,7 +1,6 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { useModelStore } from './model'; import { useModelStore } from './model';
export type BlockDisplayMode = 'traditional' | 'stacked' | 'minimal'; export type BlockDisplayMode = 'traditional' | 'stacked' | 'minimal';
export type CompactMessageDisplay = 'full' | 'brief'; export type CompactMessageDisplay = 'full' | 'brief';
type RunMode = 'fast' | 'thinking'; type RunMode = 'fast' | 'thinking';
@ -859,20 +858,17 @@ export const usePersonalizationStore = defineStore('personalization', {
}, },
async logout() { async logout() {
try { try {
console.info('[auth-debug] logout clicked, sending POST /logout');
const resp = await fetch('/logout', { const resp = await fetch('/logout', {
method: 'POST', method: 'POST',
credentials: 'same-origin', credentials: 'same-origin',
cache: 'no-store' cache: 'no-store'
}); });
console.info('[auth-debug] logout POST status:', resp.status);
let payload: any = null; let payload: any = null;
try { try {
payload = await resp.json(); payload = await resp.json();
} catch (_err) { } catch (_err) {
payload = null; payload = null;
} }
console.info('[auth-debug] logout POST payload:', payload);
if (resp.ok && (!payload || payload.success !== false)) { if (resp.ok && (!payload || payload.success !== false)) {
window.location.replace(`/login?logged_out=1&ts=${Date.now()}`); window.location.replace(`/login?logged_out=1&ts=${Date.now()}`);
return; return;

View File

@ -103,7 +103,6 @@ export const useResourceStore = defineStore('resource', {
this.currentContextTokens = value || 0; this.currentContextTokens = value || 0;
}, },
toggleTokenPanel() { toggleTokenPanel() {
console.log('[UI_DEBUG] toggleTokenPanel called, current state:', this.tokenPanelCollapsed, 'new state:', !this.tokenPanelCollapsed);
this.tokenPanelCollapsed = !this.tokenPanelCollapsed; this.tokenPanelCollapsed = !this.tokenPanelCollapsed;
if (this.tokenPanelCollapsed) { if (this.tokenPanelCollapsed) {
this.stopContainerStatsPolling(); this.stopContainerStatsPolling();

View File

@ -6,13 +6,24 @@ const debugNotifyLog = (...args: any[]) => {
void args; void args;
}; };
const keyNotifyLog = (...args: any[]) => { const keyNotifyLog = (...args: any[]) => {
console.log(...args);
}; };
const jsonDebug = (...args: any[]) => { const jsonDebug = (...args: any[]) => {
console.log('[JSONDEBUG]', ...args);
}; };
const CONN_DIAG_PREFIX = '[CONN_DIAG]'; const CONN_DIAG_PREFIX = '[CONN_DIAG]';
const TASK_POLL_DIAG_MAX = 2000; const TASK_POLL_DIAG_MAX = 2000;
// 默认关闭 console 输出(心跳类高频日志);排障时通过 window.__CONN_DIAG__ = true
// 或 localStorage.connDiag = '1' 显式打开。内存记录 __CONN_DIAG_LOGS__ 始终收集。
const isConnDiagConsoleEnabled = () => {
if (typeof window === 'undefined') return false;
try {
const w = window as any;
if (w.__CONN_DIAG__ === true || w.__CONN_DIAG__ === '1') return true;
const localFlag = window.localStorage?.getItem('connDiag');
return localFlag === '1' || localFlag === 'true';
} catch {
return false;
}
};
const taskPollDiag = (event: string, payload: Record<string, any> = {}) => { const taskPollDiag = (event: string, payload: Record<string, any> = {}) => {
const ts = new Date().toISOString(); const ts = new Date().toISOString();
const record = { ts, event, ...payload }; const record = { ts, event, ...payload };
@ -30,7 +41,9 @@ const taskPollDiag = (event: string, payload: Record<string, any> = {}) => {
} catch { } catch {
// ignore // ignore
} }
console.log(CONN_DIAG_PREFIX, event, record); if (isConnDiagConsoleEnabled()) {
console.log(CONN_DIAG_PREFIX, event, record);
}
}; };
export const useTaskStore = defineStore('task', { export const useTaskStore = defineStore('task', {

View File

@ -10,56 +10,43 @@ const applyTheme = (theme: ThemeKey) => {
document.body.setAttribute('data-theme', theme); document.body.setAttribute('data-theme', theme);
// 调试信息 // 调试信息
console.log('=== Theme Applied ===');
console.log('Theme:', theme);
// 检查样式是否生效 // 检查样式是否生效
setTimeout(() => { setTimeout(() => {
console.log('=== Elements Check ===');
// 输入栏底色 // 输入栏底色
const stadiumShell = document.querySelector('.stadium-shell'); const stadiumShell = document.querySelector('.stadium-shell');
console.log('.stadium-shell exists:', !!stadiumShell);
if (stadiumShell) { if (stadiumShell) {
const styles = window.getComputedStyle(stadiumShell); const styles = window.getComputedStyle(stadiumShell);
console.log('.stadium-shell background-color:', styles.backgroundColor);
} }
// 对话区域顶部的模型选择器 // 对话区域顶部的模型选择器
const ribbonSelector = document.querySelector('.conversation-ribbon__selector'); const ribbonSelector = document.querySelector('.conversation-ribbon__selector');
console.log('.conversation-ribbon__selector exists:', !!ribbonSelector);
if (ribbonSelector) { if (ribbonSelector) {
const styles = window.getComputedStyle(ribbonSelector); const styles = window.getComputedStyle(ribbonSelector);
console.log('.conversation-ribbon__selector color:', styles.color);
} }
const selectorModel = document.querySelector('.selector-model'); const selectorModel = document.querySelector('.selector-model');
if (selectorModel) { if (selectorModel) {
const styles = window.getComputedStyle(selectorModel); const styles = window.getComputedStyle(selectorModel);
console.log('.selector-model color:', styles.color);
} }
const selectorMode = document.querySelector('.selector-mode'); const selectorMode = document.querySelector('.selector-mode');
if (selectorMode) { if (selectorMode) {
const styles = window.getComputedStyle(selectorMode); const styles = window.getComputedStyle(selectorMode);
console.log('.selector-mode color:', styles.color);
} }
// 下拉菜单 // 下拉菜单
const dropdown = document.querySelector('.model-mode-dropdown'); const dropdown = document.querySelector('.model-mode-dropdown');
console.log('.model-mode-dropdown exists:', !!dropdown);
if (dropdown) { if (dropdown) {
const styles = window.getComputedStyle(dropdown); const styles = window.getComputedStyle(dropdown);
console.log('.model-mode-dropdown background-color:', styles.backgroundColor);
} }
const dropdownItem = document.querySelector('.dropdown-item'); const dropdownItem = document.querySelector('.dropdown-item');
if (dropdownItem) { if (dropdownItem) {
const styles = window.getComputedStyle(dropdownItem); const styles = window.getComputedStyle(dropdownItem);
console.log('.dropdown-item color:', styles.color);
} }
console.log('=== End Elements Check ===');
}, 100); }, 100);
}; };

View File

@ -3,6 +3,7 @@
import os import os
import json import json
import base64 import base64
import logging
import mimetypes import mimetypes
import io import io
import uuid import uuid
@ -13,6 +14,9 @@ from copy import deepcopy
from typing import Dict, List, Optional, Any from typing import Dict, List, Optional, Any
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
logger = logging.getLogger(__name__)
try: try:
from config import ( from config import (
MAX_CONTEXT_SIZE, MAX_CONTEXT_SIZE,
@ -198,23 +202,16 @@ class TokenMixin:
def safe_broadcast_token_update(self): def safe_broadcast_token_update(self):
"""安全的token更新广播只广播累计统计不重新计算""" """安全的token更新广播只广播累计统计不重新计算"""
try: try:
print(f"[Debug] 尝试广播token更新")
# 检查是否有回调函数 # 检查是否有回调函数
if not hasattr(self, '_web_terminal_callback'): if not hasattr(self, '_web_terminal_callback'):
print(f"[Debug] 没有_web_terminal_callback属性")
return return
if not self._web_terminal_callback: if not self._web_terminal_callback:
print(f"[Debug] _web_terminal_callback为None")
return return
if not self.current_conversation_id: if not self.current_conversation_id:
print(f"[Debug] 没有当前对话ID")
return return
print(f"[Debug] 广播token统计对话ID: {self.current_conversation_id}")
# 只获取已有的累计token统计不重新计算 # 只获取已有的累计token统计不重新计算
cumulative_stats = self.get_conversation_token_statistics() cumulative_stats = self.get_conversation_token_statistics()
@ -228,14 +225,8 @@ class TokenMixin:
'updated_at': datetime.now().isoformat() 'updated_at': datetime.now().isoformat()
} }
print(f"[Debug] Token统计: 累计输入={broadcast_data['cumulative_input_tokens']}, 累计输出={broadcast_data['cumulative_output_tokens']}")
# 广播到前端 # 广播到前端
self._web_terminal_callback('token_update', broadcast_data) self._web_terminal_callback('token_update', broadcast_data)
print(f"[Debug] token更新已广播")
except Exception as e: except Exception as e:
print(f"[Debug] 广播token更新失败: {e}") logger.warning(f"[TokenStats] 广播token更新失败: {e}")
import traceback
traceback.print_exc()