diff --git a/pipeline_bidding/bid_analysis_capability.py b/pipeline_bidding/bid_analysis_capability.py index 359da79..58a6b1d 100644 --- a/pipeline_bidding/bid_analysis_capability.py +++ b/pipeline_bidding/bid_analysis_capability.py @@ -151,28 +151,15 @@ def _extract_file_text(path): async def _project_dir_of(sor, project_id): - """项目根目录(供相对路径解析)。解析口径与引擎上传落盘一致: - sd_projects.workspace_dir 优先;为空时按 {base}/{org}/{pipeline}/{项目名} 兜底。 + """项目根目录(供相对路径解析)。统一走引擎 get_project_dir_by_id: + 读库(创建时已写死),不再自行推导——口径漂移是上传错位的根因(2026-09-01 根治)。 """ if not project_id: return "" try: - recs = await sor.sqlExe( - "SELECT name, org_id, pipeline_id, workspace_dir FROM sd_projects " - "WHERE id=${p}$ LIMIT 1", {"p": project_id}) - if not recs: - return "" - r = recs[0] - ws = (getattr(r, 'workspace_dir', '') or '').strip() - if ws.startswith('/'): - return ws - from pipeline_service.workspace import get_workspace_base, build_workspace_path - base = await get_workspace_base(sor) - name = (getattr(r, 'name', '') or '').strip() - if not base or not name: - return "" - return build_workspace_path(base, getattr(r, 'org_id', '0') or '0', - getattr(r, 'pipeline_id', '') or 'general', name) + from pipeline_service.workspace import get_project_dir_by_id + pdir, _ = await get_project_dir_by_id(sor, project_id) + return pdir or "" except Exception as e: logger.warning("project dir resolve failed pid=%s: %s", project_id, str(e)[:120]) return "" diff --git a/pipeline_bidding/bid_compose_capability.py b/pipeline_bidding/bid_compose_capability.py index 27b5667..34b6e2a 100644 --- a/pipeline_bidding/bid_compose_capability.py +++ b/pipeline_bidding/bid_compose_capability.py @@ -18,23 +18,18 @@ logger = logging.getLogger("pipeline.bidding.compose") async def _workspace_dir(sor, project_id): - """项目工作目录:复用引擎 build_workspace_path({base}/{org}/{pipeline_id}/{项目名})。 + """项目工作目录:统一走引擎 get_project_dir_by_id(读库,创建时已写死)。 不走 get_workspace_dir(那个依赖会话当前项目),角色 agent 场景下按项目自身字段解析。 + 旧实现自行拼 {base}/{org}/{pipeline_id}/{项目名}(旧平铺口径)导致与项目目录错位, + 2026-09-01 收敛到引擎统一函数根治。 """ try: - from pipeline_service.workspace import get_workspace_base, build_workspace_path - base = await get_workspace_base(sor) - recs = await sor.sqlExe( - "SELECT name, org_id, pipeline_id FROM sd_projects WHERE id=${p}$", {"p": project_id}) - await sor.sqlExe("COMMIT", {}) - if base and recs: - r = recs[0] - d = build_workspace_path(base, getattr(r, "org_id", "0") or "0", - getattr(r, "pipeline_id", "") or "bidding_general", - getattr(r, "name", "") or project_id, project_id) - os.makedirs(d, exist_ok=True) - return d + from pipeline_service.workspace import get_project_dir_by_id + pdir, _ = await get_project_dir_by_id(sor, project_id) + if pdir: + os.makedirs(pdir, exist_ok=True) + return pdir except Exception as e: logger.warning("workspace resolve failed: %s", str(e)[:120]) d = os.path.join("/tmp", "pipeline_bidding", project_id) diff --git a/pipeline_bidding/bid_tender_capability.py b/pipeline_bidding/bid_tender_capability.py index e211e30..57a12ec 100644 --- a/pipeline_bidding/bid_tender_capability.py +++ b/pipeline_bidding/bid_tender_capability.py @@ -38,6 +38,10 @@ async def create_bid_project(name, description="", org_id="", created_by="", async with db.sqlorContext(dbname) as sor: pid = new_id() pname = str(name).strip()[:190] + # 创建时定死项目目录并写库(统一机制:解析只读库不推导, + # 保证上传落盘=agent工作目录=工作控件显示目录) + from pipeline_service.workspace import alloc_project_dir + ws_path, dname = await alloc_project_dir(sor, org_id or "0", PIPELINE_ID, pname, pid) await sor.C("sd_projects", { "id": pid, "name": pname, @@ -47,6 +51,8 @@ async def create_bid_project(name, description="", org_id="", created_by="", "status": "in_progress", "org_id": org_id or "0", "created_by": created_by or (who or "agent.pm"), + "workspace_dir": ws_path, + "directory_name": dname, }) await sor.sqlExe("COMMIT", {}) await record(sor, pid, "sd_projects", pid, "create_bid_project", @@ -115,6 +121,10 @@ async def import_tender_file(project_id, content_text="", file_path="", file_nam pname = (str(file_name or "").strip() or (fp.split("/")[-1] if fp else "") or txt.split("\n")[0].strip())[:190] or "投标项目" pid = new_id() + # 创建时定死项目目录并写库(统一机制,同 create_bid_project) + from pipeline_service.workspace import alloc_project_dir + ws_path, dname = await alloc_project_dir( + sor, org_id or "0", PIPELINE_ID, pname, pid) await sor.C("sd_projects", { "id": pid, "name": pname, @@ -124,6 +134,8 @@ async def import_tender_file(project_id, content_text="", file_path="", file_nam "status": "in_progress", "org_id": org_id or "0", "created_by": created_by or (who or "agent.main_agent"), + "workspace_dir": ws_path, + "directory_name": dname, }) await sor.sqlExe("COMMIT", {}) await record(sor, pid, "sd_projects", pid, "auto_create_bid_project",