feat: update_doc_requirement工具(纠正回写原条目/删除编造项,根治add只增不改)

This commit is contained in:
yumoqing 2026-09-03 19:32:22 +08:00
parent b1ba0558b5
commit 2617726faf
2 changed files with 67 additions and 0 deletions

View File

@ -436,6 +436,64 @@ async def add_doc_requirement(project_id, requirement, req_type="structure",
return True, "投标文件要求已录入: %s %s" % (req_type, chapter_title or "")
async def update_doc_requirement(project_id, record_id="", chapter_no="", req_type="",
requirement="", source_ref="", page_limit="",
delete=False, who=None, agent_id=None):
"""更新/删除既有投标文件要求条目(2026-09-03,根治 add 只增不改)。
定位:record_id 优先;否则 chapter_no+req_type 唯一定位。
- delete=True → 删除该条(编造/无出处项的处置);
- requirement/source_ref/page_limit 非空 → 回写原条目(纠正必须回写,不得只追加新条目)。
"""
try:
project_id = await resolve_project_id(project_id)
except ValueError as e:
return False, str(e)
db, dbname = get_db()
async with db.sqlorContext(dbname) as sor:
if record_id:
recs = await sor.sqlExe(
"SELECT id FROM bid_doc_requirements WHERE project_id=${pid}$ AND id=${r}$",
{"pid": project_id, "r": record_id})
elif chapter_no:
recs = await sor.sqlExe(
"SELECT id FROM bid_doc_requirements WHERE project_id=${pid}$ "
"AND chapter_no=${c}$ AND req_type=${rt}$",
{"pid": project_id, "c": str(chapter_no)[:30],
"rt": (req_type or "structure")[:30]})
else:
return False, "需要 record_id 或 chapter_no 定位条目"
await sor.sqlExe("COMMIT", {})
if not recs:
return False, "未找到条目(record_id=%s chapter_no=%s req_type=%s)" % (
record_id, chapter_no, req_type)
if len(recs) > 1 and not record_id:
return False, "chapter_no+req_type 命中 %d 条,请改用 record_id 精确定位" % len(recs)
rid = getattr(recs[0], "id", "")
if delete:
await sor.sqlExe("DELETE FROM bid_doc_requirements WHERE id=${r}$", {"r": rid})
await sor.sqlExe("COMMIT", {})
await record(sor, project_id, "bid_doc_requirements", rid, "delete",
who=who, agent_id=agent_id, detail="删除条目")
return True, "已删除条目 %s" % rid
sets, p = [], {"r": rid}
if requirement:
sets.append("requirement=${rq}$"); p["rq"] = requirement
if source_ref:
sets.append("source_ref=${sr}$"); p["sr"] = str(source_ref)[:480]
if page_limit:
sets.append("page_limit=${pl}$"); p["pl"] = to_int(page_limit, 0) or None
if not sets:
return False, "无可更新字段(requirement/source_ref/page_limit 至少传一个)"
sets.append("updated_at=NOW()")
await sor.sqlExe("UPDATE bid_doc_requirements SET " + ", ".join(sets) +
" WHERE id=${r}$", p)
await sor.sqlExe("COMMIT", {})
await record(sor, project_id, "bid_doc_requirements", rid, "update",
who=who, agent_id=agent_id, detail="回写原条目")
return True, "已更新条目 %s" % rid
async def _upsert_tender_facts(project_id, facts, who=None, agent_id=None):
"""把投标要素写入 bid_tenders(source=tender_doc,复用原招标信息表承载商务要素)。

View File

@ -110,6 +110,15 @@ BID_ROLE_TOOL_SCHEMAS = {
"patches": "JSON数组[{chapter_no,title?,outline?,section?,scoring_item_ids?,scoring_items_by_name?,max_score?}]"},
"required": ["patches"],
},
"update_doc_requirement": {
"module": f"{_M}.bid_analysis_capability",
"description": "更新/删除既有投标文件要求条目(纠正必须回写原条目,不得只追加新条目形成矛盾对;编造/无出处项用 delete 删除)。add_doc_requirement 只增不改",
"params": {"project_id": "项目ID(可选,默认当前)", "record_id": "条目ID(优先)",
"chapter_no": "章节号(与req_type组合定位)", "req_type": "类型(structure/format/seal/copies/deadline/other)",
"requirement": "回写的新正文(可选)", "source_ref": "回写原文出处(可选)",
"page_limit": "页数(可选)", "delete": "true=删除该条(可选)"},
"required": [],
},
"list_scoring_items": {
"module": f"{_M}.bid_analysis_capability",
"description": "列出评分项与得分规则",