fix(admin): 修复管理面板创建旧式命名孤儿容器,切除 app_legacy 旧架构死代码
This commit is contained in:
parent
cf51ab0555
commit
b78504c31e
@ -209,13 +209,23 @@ def admin_dashboard_snapshot_api():
|
||||
return guard
|
||||
try:
|
||||
# 若当前管理员没有容器句柄,主动确保容器存在,避免面板始终显示“宿主机模式”
|
||||
# 注意:容器 key 必须带工作区后缀({username}::{workspace_id}),
|
||||
# 否则会创建出旧式命名的 agent-term-{username} 孤儿容器。
|
||||
try:
|
||||
record = get_current_user_record()
|
||||
uname = record.username if record else None
|
||||
if uname:
|
||||
handles = state.container_manager.list_containers()
|
||||
if uname not in handles:
|
||||
state.container_manager.ensure_container(uname, str(state.user_manager.ensure_user_workspace(uname).project_path), preferred_mode="docker")
|
||||
default_ws_id = "default"
|
||||
container_key = f"{uname}::{default_ws_id}"
|
||||
if container_key not in handles:
|
||||
workspace = state.user_manager.ensure_user_workspace(uname, default_ws_id)
|
||||
state.container_manager.ensure_container(
|
||||
uname,
|
||||
str(workspace.project_path),
|
||||
container_key=container_key,
|
||||
preferred_mode="docker",
|
||||
)
|
||||
except Exception as ensure_exc:
|
||||
logging.getLogger(__name__).warning("ensure_container for admin failed: %s", ensure_exc)
|
||||
|
||||
|
||||
@ -881,178 +881,6 @@ def admin_api_required(view_func):
|
||||
return wrapped
|
||||
|
||||
|
||||
def make_terminal_callback(username: str):
|
||||
"""生成面向指定用户的广播函数"""
|
||||
def _callback(event_type, data):
|
||||
try:
|
||||
socketio.emit(event_type, data, room=f"user_{username}")
|
||||
except Exception as exc:
|
||||
debug_log(f"广播事件失败 ({username}): {event_type} - {exc}")
|
||||
return _callback
|
||||
|
||||
|
||||
def attach_user_broadcast(terminal: WebTerminal, username: str):
|
||||
"""确保终端的广播函数指向当前用户的房间"""
|
||||
callback = make_terminal_callback(username)
|
||||
terminal.message_callback = callback
|
||||
if terminal.terminal_manager:
|
||||
terminal.terminal_manager.broadcast = callback
|
||||
|
||||
|
||||
def get_user_resources(username: Optional[str] = None) -> Tuple[Optional[WebTerminal], Optional[UserWorkspace]]:
|
||||
username = (username or get_current_username())
|
||||
if not username:
|
||||
return None, None
|
||||
record = get_current_user_record()
|
||||
workspace = user_manager.ensure_user_workspace(username)
|
||||
container_handle = container_manager.ensure_container(username, str(workspace.project_path), preferred_mode="docker")
|
||||
usage_tracker = get_or_create_usage_tracker(username, workspace)
|
||||
terminal = user_terminals.get(username)
|
||||
if not terminal:
|
||||
run_mode = session.get('run_mode')
|
||||
thinking_mode_flag = session.get('thinking_mode')
|
||||
if run_mode not in {"fast", "thinking", "deep"}:
|
||||
preferred_run_mode = None
|
||||
try:
|
||||
personal_config = load_personalization_config(workspace.data_dir)
|
||||
candidate_mode = (personal_config or {}).get('default_run_mode')
|
||||
if isinstance(candidate_mode, str) and candidate_mode.lower() in {"fast", "thinking", "deep"}:
|
||||
preferred_run_mode = candidate_mode.lower()
|
||||
except Exception as exc:
|
||||
debug_log(f"[UserInit] 加载个性化偏好失败: {exc}")
|
||||
|
||||
if preferred_run_mode:
|
||||
run_mode = preferred_run_mode
|
||||
thinking_mode_flag = preferred_run_mode != "fast"
|
||||
elif thinking_mode_flag:
|
||||
run_mode = "deep"
|
||||
else:
|
||||
run_mode = "fast"
|
||||
thinking_mode = run_mode != "fast"
|
||||
terminal = WebTerminal(
|
||||
project_path=str(workspace.project_path),
|
||||
thinking_mode=thinking_mode,
|
||||
run_mode=run_mode,
|
||||
message_callback=make_terminal_callback(username),
|
||||
data_dir=str(workspace.data_dir),
|
||||
container_session=container_handle,
|
||||
usage_tracker=usage_tracker
|
||||
)
|
||||
if terminal.terminal_manager:
|
||||
terminal.terminal_manager.broadcast = terminal.message_callback
|
||||
user_terminals[username] = terminal
|
||||
terminal.username = username
|
||||
terminal.user_role = get_current_user_role(record)
|
||||
terminal.quota_update_callback = lambda metric=None: emit_user_quota_update(username)
|
||||
session['run_mode'] = terminal.run_mode
|
||||
session['thinking_mode'] = terminal.thinking_mode
|
||||
else:
|
||||
terminal.update_container_session(container_handle)
|
||||
attach_user_broadcast(terminal, username)
|
||||
terminal.username = username
|
||||
terminal.user_role = get_current_user_role(record)
|
||||
terminal.quota_update_callback = lambda metric=None: emit_user_quota_update(username)
|
||||
|
||||
# 应用管理员策略(工具分类、强制开关、模型禁用)
|
||||
try:
|
||||
from core.tool_config import ToolCategory
|
||||
|
||||
policy = resolve_admin_policy(user_manager.get_user(username))
|
||||
categories_map = {
|
||||
cid: ToolCategory(
|
||||
label=cat.get("label") or cid,
|
||||
tools=list(cat.get("tools") or []),
|
||||
default_enabled=bool(cat.get("default_enabled", True)),
|
||||
silent_when_disabled=bool(cat.get("silent_when_disabled", False)),
|
||||
)
|
||||
for cid, cat in policy.get("categories", {}).items()
|
||||
}
|
||||
forced_states = policy.get("forced_category_states") or {}
|
||||
disabled_models = policy.get("disabled_models") or []
|
||||
terminal.set_admin_policy(categories_map, forced_states, disabled_models)
|
||||
terminal.admin_policy_ui_blocks = policy.get("ui_blocks") or {}
|
||||
terminal.admin_policy_version = policy.get("updated_at")
|
||||
# 若当前模型被禁用,则回退到第一个可用模型
|
||||
if terminal.model_key in disabled_models:
|
||||
for candidate in get_registered_model_keys(visible_only=True):
|
||||
if candidate not in disabled_models:
|
||||
try:
|
||||
terminal.set_model(candidate)
|
||||
session["model_key"] = terminal.model_key
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
except Exception as exc:
|
||||
debug_log(f"[admin_policy] 应用失败: {exc}")
|
||||
return terminal, workspace
|
||||
|
||||
|
||||
def get_or_create_usage_tracker(username: Optional[str], workspace: Optional[UserWorkspace] = None) -> Optional[UsageTracker]:
|
||||
if not username:
|
||||
return None
|
||||
tracker = usage_trackers.get(username)
|
||||
if tracker:
|
||||
return tracker
|
||||
if workspace is None:
|
||||
workspace = user_manager.ensure_user_workspace(username)
|
||||
record = user_manager.get_user(username)
|
||||
role = getattr(record, "role", "user") if record else "user"
|
||||
tracker = UsageTracker(str(workspace.data_dir), role=role or "user")
|
||||
usage_trackers[username] = tracker
|
||||
return tracker
|
||||
|
||||
|
||||
def emit_user_quota_update(username: Optional[str]):
|
||||
if not username:
|
||||
return
|
||||
tracker = get_or_create_usage_tracker(username)
|
||||
if not tracker:
|
||||
return
|
||||
try:
|
||||
snapshot = tracker.get_quota_snapshot()
|
||||
socketio.emit('quota_update', {
|
||||
'quotas': snapshot
|
||||
}, room=f"user_{username}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def with_terminal(func):
|
||||
"""注入用户专属终端和工作区"""
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
username = get_current_username()
|
||||
try:
|
||||
terminal, workspace = get_user_resources(username)
|
||||
except RuntimeError as exc:
|
||||
return jsonify({"error": str(exc), "code": "resource_busy"}), 503
|
||||
if not terminal or not workspace:
|
||||
return jsonify({"error": "System not initialized"}), 503
|
||||
kwargs.update({
|
||||
'terminal': terminal,
|
||||
'workspace': workspace,
|
||||
'username': username
|
||||
})
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
def get_terminal_for_sid(sid: str) -> Tuple[Optional[str], Optional[WebTerminal], Optional[UserWorkspace]]:
|
||||
username = connection_users.get(sid)
|
||||
if not username:
|
||||
return None, None, None
|
||||
try:
|
||||
terminal, workspace = get_user_resources(username)
|
||||
except RuntimeError:
|
||||
return username, None, None
|
||||
return username, terminal, workspace
|
||||
|
||||
|
||||
def get_gui_manager(workspace: UserWorkspace) -> GuiFileManager:
|
||||
"""构建 GUI 文件管理器"""
|
||||
return GuiFileManager(str(workspace.project_path))
|
||||
|
||||
|
||||
def get_upload_guard(workspace: UserWorkspace) -> UploadQuarantineManager:
|
||||
"""构建上传隔离管理器"""
|
||||
return UploadQuarantineManager(workspace)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user