feat: add chat replay verification
This commit is contained in:
@@ -69,6 +69,14 @@ def sha(text: str) -> str:
|
||||
return hashlib.sha256(text.encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
def sha_file(path: str) -> str:
|
||||
h = hashlib.sha256()
|
||||
with open(path, "rb") as fh:
|
||||
for chunk in iter(lambda: fh.read(65536), b""):
|
||||
h.update(chunk)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def git_commit() -> str:
|
||||
try:
|
||||
r = subprocess.run(["git", "rev-parse", "HEAD"], cwd=ROOT, capture_output=True, text=True, timeout=5)
|
||||
@@ -204,6 +212,12 @@ def record_metrics(trace_id: str, message: str, answer: str, status: str, latenc
|
||||
def finish(started, trace_id, chat_id, turn_id, tenant_id, actor, message, router, decision, answer,
|
||||
action=None, action_gate=None, artifact_path="", safe_message=""):
|
||||
elapsed = int((datetime.now(timezone.utc) - started).total_seconds() * 1000)
|
||||
loop_run = {}
|
||||
if os.environ.get("CASAN_CHAT_LOOP_RUN_JSON"):
|
||||
try:
|
||||
loop_run = json.loads(os.environ["CASAN_CHAT_LOOP_RUN_JSON"])
|
||||
except ValueError:
|
||||
loop_run = {"success": False, "decision": "DENIED", "reason": "loop_run_json_invalid"}
|
||||
source = []
|
||||
if artifact_path:
|
||||
source.append({
|
||||
@@ -211,6 +225,7 @@ def finish(started, trace_id, chat_id, turn_id, tenant_id, actor, message, route
|
||||
"line": 1,
|
||||
"excerpt": answer[:260],
|
||||
"score": 10 if decision == "ACTION_COMPLETED" else 1,
|
||||
"hash": sha_file(artifact_path),
|
||||
"envelope": provenance("chat-operator-artifact", artifact_path, decision == "ACTION_COMPLETED"),
|
||||
})
|
||||
rec = record_turn({
|
||||
@@ -229,7 +244,8 @@ def finish(started, trace_id, chat_id, turn_id, tenant_id, actor, message, route
|
||||
"user_msg_ref": sha(message),
|
||||
"safe_preview": (safe_message or "")[:180],
|
||||
"answer_ref": sha(answer),
|
||||
"sources": [{"path": s.get("path"), "line": s.get("line")} for s in source],
|
||||
"sources": [{"path": s.get("path"), "line": s.get("line"), "hash": s.get("hash")} for s in source],
|
||||
"loop_run": loop_run,
|
||||
})
|
||||
record_metrics(trace_id, safe_message or message, answer, "success" if decision == "ACTION_COMPLETED" else "failed", elapsed, (action or {}).get("id", "none"))
|
||||
return {
|
||||
@@ -247,6 +263,7 @@ def finish(started, trace_id, chat_id, turn_id, tenant_id, actor, message, route
|
||||
"router": router,
|
||||
"action": {k: action.get(k) for k in ("id", "label", "description")} if action else None,
|
||||
"action_gate": action_gate or {},
|
||||
"loop_run": loop_run,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user