From 2ecf6e06f720623dcf9ae4c1bbe99ba6af1443da Mon Sep 17 00:00:00 2001 From: yumoqing Date: Sat, 15 Aug 2026 00:11:47 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20load/save=5Fagent=5Fconfig=20=E7=94=A8?= =?UTF-8?q?=E4=B8=8D=E5=AD=98=E5=9C=A8=E7=9A=84=20project=5Fid=20=E5=88=97?= =?UTF-8?q?=E6=9F=A5=20sd=5Forg=5Fsettings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sd_org_settings 以 org_id 为键(无 project_id 列),导致每次 cockpit 请求抛 'Unknown column project_id'。 改为先由 sd_projects 解析 org_id 再查。save_agent_config 同步修正。 --- .../__pycache__/agent_config.cpython-310.pyc | Bin 0 -> 10692 bytes pipeline_core/agent_config.py | 58 +++++++++++------- 2 files changed, 37 insertions(+), 21 deletions(-) create mode 100644 pipeline_core/__pycache__/agent_config.cpython-310.pyc diff --git a/pipeline_core/__pycache__/agent_config.cpython-310.pyc b/pipeline_core/__pycache__/agent_config.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a50fd5a471d1132a0febc0851aab20d4613d5049 GIT binary patch literal 10692 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 literal 0 HcmV?d00001 diff --git a/pipeline_core/agent_config.py b/pipeline_core/agent_config.py index 432804d..5d45190 100644 --- a/pipeline_core/agent_config.py +++ b/pipeline_core/agent_config.py @@ -335,7 +335,7 @@ async def load_agent_config(pipeline_id: str = None, project_id: str = None) -> """加载产线的 Agent 配置。 优先级: - 1. 项目级 sd_org_settings.agent_config + 1. 项目级 sd_org_settings.agent_config(sd_org_settings 以 org_id 为键,由项目解析 org_id) 2. 产线级 pipelines.agent_config 3. SDLC_DEFAULT_CONFIG """ @@ -344,21 +344,27 @@ async def load_agent_config(pipeline_id: str = None, project_id: str = None) -> db = DBPools() async with db.sqlorContext("pipeline") as sor: - # 项目级配置 + # 项目级配置:sd_org_settings 无 project_id 列,需先由 sd_projects 解析 org_id 再查 if project_id: - recs = await sor.sqlExe( - "SELECT agent_config FROM sd_org_settings WHERE project_id=${pid}$", - {"pid": project_id}, - ) - if recs: - raw = getattr(recs[0], "agent_config", "") - if raw: - try: - data = json.loads(raw) if isinstance(raw, str) else raw - data["tools"] = _merge_tools(data.get("tools", []), SDLC_DEFAULT_TOOLS) - return AgentConfig.from_dict(data) - except (json.JSONDecodeError, TypeError): - pass + org_id = "" + proj_recs = await sor.sqlExe( + "SELECT org_id FROM sd_projects WHERE id=${pid}$", {"pid": project_id}) + if proj_recs: + org_id = getattr(proj_recs[0], "org_id", "") or "" + if org_id: + recs = await sor.sqlExe( + "SELECT agent_config FROM sd_org_settings WHERE org_id=${oid}$", + {"oid": org_id}, + ) + if recs: + raw = getattr(recs[0], "agent_config", "") + if raw: + try: + data = json.loads(raw) if isinstance(raw, str) else raw + data["tools"] = _merge_tools(data.get("tools", []), SDLC_DEFAULT_TOOLS) + return AgentConfig.from_dict(data) + except (json.JSONDecodeError, TypeError): + pass # 产线级配置 + 产线缺省模型 if pipeline_id: @@ -400,27 +406,37 @@ def _merge_tools(custom_tools: list, default_tools: list) -> list: async def save_agent_config(project_id: str, config: AgentConfig): - """保存项目级 Agent 配置到 sd_org_settings""" + """保存项目级 Agent 配置到 sd_org_settings(按 org_id 组织)""" from sqlor.dbpools import DBPools db = DBPools() async with db.sqlorContext("pipeline") as sor: + # sd_org_settings 以 org_id 为键,需先由项目解析 org_id + org_id = "" + ws = "" + proj_recs = await sor.sqlExe( + "SELECT org_id, workspace_dir FROM sd_projects WHERE id=${pid}$", {"pid": project_id}) + if proj_recs: + org_id = getattr(proj_recs[0], "org_id", "") or "" + ws = getattr(proj_recs[0], "workspace_dir", "") or "" + if not org_id: + return config_json = json.dumps(config.to_dict(), ensure_ascii=False) # UPDATE-first 防止竞态 await sor.sqlExe( - "UPDATE sd_org_settings SET agent_config=${cfg}$ WHERE project_id=${pid}$", - {"cfg": config_json, "pid": project_id}, + "UPDATE sd_org_settings SET agent_config=${cfg}$ WHERE org_id=${oid}$", + {"cfg": config_json, "oid": org_id}, ) existing = await sor.sqlExe( - "SELECT id FROM sd_org_settings WHERE project_id=${pid}$", - {"pid": project_id}, + "SELECT id FROM sd_org_settings WHERE org_id=${oid}$", {"oid": org_id}, ) if not existing: from appPublic.uniqueID import getID await sor.C("sd_org_settings", { "id": getID(), - "project_id": project_id, + "org_id": org_id, + "workspace_root": ws or "/tmp/ws", "agent_config": config_json, })