diff --git a/pipeline_service/agent_loop_v2.py b/pipeline_service/agent_loop_v2.py index 888e35a..9d639af 100644 --- a/pipeline_service/agent_loop_v2.py +++ b/pipeline_service/agent_loop_v2.py @@ -859,6 +859,7 @@ class AgentExecutor: async def _t_create_project(self, sor, p, pid): import os + import re from appPublic.uniqueID import getID name = p.get("name", "").strip() @@ -874,18 +875,29 @@ class AgentExecutor: if _u: org_id = getattr(_u[0], "orgid", "0") or "0" - # 项目专属工作空间目录(workspace_base 从 appbase params 表读,可动态配置) - # 项目空间 = self.space(通用助手 'general' / 专业产线 pipeline_id),隔离不共享。 - from .workspace import get_workspace_base, build_workspace_path + # 项目专属工作空间目录(新结构:{base}/{org}/{space}/projects/{英文slug}/, + # 与 apps/、modules/ 平级;工作空间控件按此结构读取)。 + # 英文 slug:项目名保留 [A-Za-z0-9_-],且须含字母才有辨识度(避免纯数字如 "7"); + # 纯中文或纯数字名兑底 proj_{短ID}。 + from .workspace import get_workspace_base, build_space_path workspace_base = await get_workspace_base(sor) pid_val = getID() - workspace_dir = build_workspace_path(workspace_base, org_id, self.space, name, pid_val) - os.makedirs(workspace_dir, exist_ok=True) + space_dir = build_space_path(workspace_base, org_id, self.space) + slug = re.sub(r'[^A-Za-z0-9_-]', '', name).strip('_-') + if not slug or not re.search(r'[A-Za-z]', slug): + slug = 'proj_' + pid_val[-8:] + project_dir = os.path.join(space_dir, 'projects', slug) + if os.path.isdir(project_dir): + # 同 slug 已存在(不同项目重名)→ 追加短 ID,避免共享目录互相覆盖 + slug = f"{slug}_{pid_val[-8:]}" + project_dir = os.path.join(space_dir, 'projects', slug) + os.makedirs(project_dir, exist_ok=True) await sor.C("sd_projects", { "id": pid_val, "name": name, "description": desc, "status": "active", "org_id": org_id, - "pipeline_id": self.space, "workspace_dir": workspace_dir, + "pipeline_id": self.space, "workspace_dir": project_dir, + "directory_name": slug, "created_by": self.user_id or "", "default_model": self.model_name or "", })