fix(workspace): 创建入口写死项目目录+解析收敛引擎统一函数

- create_bid_project/自动立项: 创建时写 workspace_dir+directory_name
- _project_dir_of/_workspace_dir: 自抄旧口径推导→收敛 get_project_dir_by_id
This commit is contained in:
yumoqing 2026-09-01 11:54:59 +08:00
parent e387c7c5ce
commit ceeec055a3
3 changed files with 25 additions and 31 deletions

View File

@ -151,28 +151,15 @@ def _extract_file_text(path):
async def _project_dir_of(sor, project_id): async def _project_dir_of(sor, project_id):
"""项目根目录(供相对路径解析)。解析口径与引擎上传落盘一致: """项目根目录(供相对路径解析)。统一走引擎 get_project_dir_by_id:
sd_projects.workspace_dir 优先;为空时按 {base}/{org}/{pipeline}/{项目名} 兜底。 读库(创建时已写死),不再自行推导——口径漂移是上传错位的根因(2026-09-01 根治)。
""" """
if not project_id: if not project_id:
return "" return ""
try: try:
recs = await sor.sqlExe( from pipeline_service.workspace import get_project_dir_by_id
"SELECT name, org_id, pipeline_id, workspace_dir FROM sd_projects " pdir, _ = await get_project_dir_by_id(sor, project_id)
"WHERE id=${p}$ LIMIT 1", {"p": project_id}) return pdir or ""
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)
except Exception as e: except Exception as e:
logger.warning("project dir resolve failed pid=%s: %s", project_id, str(e)[:120]) logger.warning("project dir resolve failed pid=%s: %s", project_id, str(e)[:120])
return "" return ""

View File

@ -18,23 +18,18 @@ logger = logging.getLogger("pipeline.bidding.compose")
async def _workspace_dir(sor, project_id): async def _workspace_dir(sor, project_id):
"""项目工作目录:复用引擎 build_workspace_path({base}/{org}/{pipeline_id}/{项目名})。 """项目工作目录:统一走引擎 get_project_dir_by_id(读库,创建时已写死)。
不走 get_workspace_dir(那个依赖会话当前项目),角色 agent 场景下按项目自身字段解析。 不走 get_workspace_dir(那个依赖会话当前项目),角色 agent 场景下按项目自身字段解析。
旧实现自行拼 {base}/{org}/{pipeline_id}/{项目名}(旧平铺口径)导致与项目目录错位,
2026-09-01 收敛到引擎统一函数根治。
""" """
try: try:
from pipeline_service.workspace import get_workspace_base, build_workspace_path from pipeline_service.workspace import get_project_dir_by_id
base = await get_workspace_base(sor) pdir, _ = await get_project_dir_by_id(sor, project_id)
recs = await sor.sqlExe( if pdir:
"SELECT name, org_id, pipeline_id FROM sd_projects WHERE id=${p}$", {"p": project_id}) os.makedirs(pdir, exist_ok=True)
await sor.sqlExe("COMMIT", {}) return pdir
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
except Exception as e: except Exception as e:
logger.warning("workspace resolve failed: %s", str(e)[:120]) logger.warning("workspace resolve failed: %s", str(e)[:120])
d = os.path.join("/tmp", "pipeline_bidding", project_id) d = os.path.join("/tmp", "pipeline_bidding", project_id)

View File

@ -38,6 +38,10 @@ async def create_bid_project(name, description="", org_id="", created_by="",
async with db.sqlorContext(dbname) as sor: async with db.sqlorContext(dbname) as sor:
pid = new_id() pid = new_id()
pname = str(name).strip()[:190] 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", { await sor.C("sd_projects", {
"id": pid, "id": pid,
"name": pname, "name": pname,
@ -47,6 +51,8 @@ async def create_bid_project(name, description="", org_id="", created_by="",
"status": "in_progress", "status": "in_progress",
"org_id": org_id or "0", "org_id": org_id or "0",
"created_by": created_by or (who or "agent.pm"), "created_by": created_by or (who or "agent.pm"),
"workspace_dir": ws_path,
"directory_name": dname,
}) })
await sor.sqlExe("COMMIT", {}) await sor.sqlExe("COMMIT", {})
await record(sor, pid, "sd_projects", pid, "create_bid_project", 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 "") pname = (str(file_name or "").strip() or (fp.split("/")[-1] if fp else "")
or txt.split("\n")[0].strip())[:190] or "投标项目" or txt.split("\n")[0].strip())[:190] or "投标项目"
pid = new_id() 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", { await sor.C("sd_projects", {
"id": pid, "id": pid,
"name": pname, "name": pname,
@ -124,6 +134,8 @@ async def import_tender_file(project_id, content_text="", file_path="", file_nam
"status": "in_progress", "status": "in_progress",
"org_id": org_id or "0", "org_id": org_id or "0",
"created_by": created_by or (who or "agent.main_agent"), "created_by": created_by or (who or "agent.main_agent"),
"workspace_dir": ws_path,
"directory_name": dname,
}) })
await sor.sqlExe("COMMIT", {}) await sor.sqlExe("COMMIT", {})
await record(sor, pid, "sd_projects", pid, "auto_create_bid_project", await record(sor, pid, "sd_projects", pid, "auto_create_bid_project",