AgentEvalTool/backend/agenteval/intelligent_eval/decision_logs.py
sinohqb 3376caca7b
All checks were successful
CI / test (push) Successful in 3m57s
fix(decision-logs): remove unused context_json + json import (ruff F841/F401)
2026-08-14 15:23:36 +08:00

83 lines
2.7 KiB
Python

"""Decision-log service (P3 deepening, S2).
Pulled out of ``web/routers/intelligent_evals.py`` so the router only handles
HTTP validation and error translation. The ORM writes and reads now live here.
"""
from typing import Any
from sqlmodel import Session, select
from agenteval.storage.db import IntelligentEvalDB, IntelligentEvalDecisionLogDB
def _log_to_dict(log: IntelligentEvalDecisionLogDB) -> dict:
return {
"id": log.id,
"eval_id": log.eval_id,
"decision_type": log.decision_type,
"reason": log.reason,
"context": log.get_context(),
"cron_id": log.cron_id,
"created_at": log.created_at.isoformat() if log.created_at else None,
}
def create_decision_log(
eval_id: str,
decision_type: str,
reason: str,
cron_id: str,
context: dict[str, Any],
session: Session,
) -> dict:
"""Create a decision log entry, or return the existing one if the
(eval_id, decision_type, context) tuple is already recorded.
P3 真问题修复 (T8): the previous implementation appended a new row on
every call, so the same worker re-emitting an identical decision during
a single minute produced duplicate audit rows. Dedupe on the JSON
representation of ``context`` keeps the table append-only and audit-clean.
Raises ``LookupError`` if eval not found.
"""
eval_db = session.get(IntelligentEvalDB, eval_id)
if eval_db is None:
raise LookupError(f"intelligent eval {eval_id} not found")
# Dedupe: same (eval, decision_type, context) → return existing.
for existing in session.exec(
select(IntelligentEvalDecisionLogDB).where(
IntelligentEvalDecisionLogDB.eval_id == eval_id,
IntelligentEvalDecisionLogDB.decision_type == decision_type,
)
).all():
if existing.get_context() == context:
return _log_to_dict(existing)
log = IntelligentEvalDecisionLogDB(
eval_id=eval_id,
decision_type=decision_type,
reason=reason,
cron_id=cron_id,
)
log.set_context(context)
session.add(log)
session.commit()
session.refresh(log)
return _log_to_dict(log)
def list_decision_logs(eval_id: str, session: Session) -> list[dict]:
"""List decision logs for an eval. Raises ``LookupError`` if eval not found."""
eval_db = session.get(IntelligentEvalDB, eval_id)
if eval_db is None:
raise LookupError(f"intelligent eval {eval_id} not found")
logs = session.exec(
select(IntelligentEvalDecisionLogDB)
.where(IntelligentEvalDecisionLogDB.eval_id == eval_id)
.order_by(IntelligentEvalDecisionLogDB.created_at.desc())
).all()
return [_log_to_dict(log) for log in logs]