feat(v2): 实现SQLite对公租赁经验加工与卡片预审轨迹闭环
This commit is contained in:
@@ -10,7 +10,7 @@ from copy import deepcopy
|
||||
from services.assistant_store import get, put, listing, event, uid, now, digest, finish_time_event
|
||||
from services import prescreen, prescreen_store
|
||||
from services.assistant_data import read_cards
|
||||
from services.skill_executor import execute_skill, execute_rules
|
||||
from services.skill_executor import execute_skill, execute_rules, applicability_checks
|
||||
from services.assistant_experiences import apply_experiences
|
||||
from services import assistant_model
|
||||
from contracts.project_assistant import SkillResult, ProjectSnapshot
|
||||
@@ -55,7 +55,6 @@ def reconcile(db, project_id, run_id, checks):
|
||||
put(db, "finding", finding)
|
||||
key = "new" if not old else "resolved" if status == "已解决" and previous_status != status else "reopened" if previous_status == "已解决" and status != previous_status else "retained"
|
||||
changes[key].append(finding["id"])
|
||||
# Unexecuted checks remain unresolved/stale, never disappear into an implied pass.
|
||||
executed = {c["code"] for c in checks}
|
||||
for code, old in prior.items():
|
||||
if code not in executed:
|
||||
@@ -203,7 +202,6 @@ class DurableWorker:
|
||||
db.execute("UPDATE assistant_jobs SET state='failed' WHERE id=? AND owner=?", (run["id"], self.owner))
|
||||
finish_time_event(db, "run", run["id"])
|
||||
event(db, run["project_id"], "run.failed", self.owner, {"error_type": type(exc).__name__}, run["id"])
|
||||
# AC-48:失败运行同样要能被页面读到,并明确显示未完成原因
|
||||
self.save_prescreen_view(db, current)
|
||||
finally:
|
||||
done.set()
|
||||
@@ -232,7 +230,6 @@ class DurableWorker:
|
||||
run["snapshot_id"] = snapshot["id"]
|
||||
current = get(db, "run", run["id"])
|
||||
current["snapshot_id"] = snapshot["id"]
|
||||
# Freeze applicable experience versions once; recovery never reads a newer release.
|
||||
current["experience_versions"] = [get(db, "experience_version", r["version_id"]) for r in listing(db, "experience_release")] if run.get("feature_flags", {}).get("experiences", True) else []
|
||||
put(db, "run", current)
|
||||
run.update(current)
|
||||
@@ -262,7 +259,10 @@ class DurableWorker:
|
||||
if time.monotonic() >= deadline:
|
||||
raise TimeoutError("运行时间预算已耗尽")
|
||||
engine = skill["engine"]
|
||||
if engine == "model":
|
||||
gate = applicability_checks(skill, values, sources) if engine not in ("rules", "experience") else None
|
||||
if gate is not None:
|
||||
step["findings"] = gate
|
||||
elif engine == "model":
|
||||
payload, trace = self.bounded_model(lambda: assistant_model.invoke(skill, dict(snapshot, values=values, sources=sources), all_checks, components["rules"], run["requirement"], guidance,
|
||||
run["model_config"], budget, cancelled=lambda: not self.alive(run) or time.monotonic() >= deadline, feedback=run.get("feedback_context")), max(.1, deadline - time.monotonic()), run)
|
||||
step["outputs"] = {"requirement_response": payload["requirement_response"]}
|
||||
@@ -280,7 +280,7 @@ class DurableWorker:
|
||||
step["findings"] = [c for c in step["findings"] if not set(c["fields"]).issubset(required_fields)]
|
||||
if engine == "ratio":
|
||||
step["output_sources"] = {skill["output"]: sources.get(skill["numerator"], []) + sources.get(skill["denominator"], [])}
|
||||
step["missing_inputs"] = [f for f in skill.get("inputs", []) if f != "*" and values.get(f) is None]
|
||||
step["missing_inputs"] = [] if step["findings"] and all(c["result"] == "not_applicable" for c in step["findings"]) else [f for f in skill.get("inputs", []) if f != "*" and values.get(f) is None]
|
||||
step["status"] = "partial" if any(c["result"] in ("unknown", "error") for c in step["findings"]) else "completed"
|
||||
except Exception as exc:
|
||||
step.update(status="failed", errors=[{"type": type(exc).__name__, "message": str(exc)[:400] if isinstance(exc, (ValueError, TimeoutError)) else "步骤执行失败,请检查内网模型或数据服务"}])
|
||||
@@ -319,9 +319,7 @@ class DurableWorker:
|
||||
db.execute("UPDATE assistant_jobs SET state=? WHERE id=? AND owner=?", (current["status"], run["id"], self.owner))
|
||||
finish_time_event(db, "run", run["id"])
|
||||
self.service.mark_stale(db, run["project_id"], ["*"])
|
||||
# A new result invalidates existing drafts, not the findings just reconciled.
|
||||
for finding in findings:
|
||||
put(db, "finding", finding)
|
||||
event(db, run["project_id"], "run." + current["status"], self.owner, {"summary": current["summary"], "superseded": current["superseded"]}, run["id"])
|
||||
# 纠偏第一批(BR-45):运行结束即产出新版预审视图,页面直接读它。
|
||||
self.save_prescreen_view(db, current)
|
||||
|
||||
Reference in New Issue
Block a user