from __future__ import annotations import argparse import asyncio import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) from app.orchestrator import Orchestrator CASES_PATH = ROOT / "golden" / "golden_cases.jsonl" async def full_decide(orch: Orchestrator, cid: str, msg: str, goods_order: str) -> tuple[str, str, dict]: context = { "customer_key": f"demo_acc:{cid}", "acc_id": "demo_acc", "customer_id": cid, "goods_name": "demo_goods", "goods_order": goods_order, "msg": msg, "pending_images": 0, "auto_quote_trigger": False, "last_reply": "", } route, decision, state = await orch.decide(context) return route, decision.action, state async def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--mode", choices=["full"], default="full") parser.add_argument("--cases", default=str(CASES_PATH)) args = parser.parse_args() p = Path(args.cases) if not p.exists(): print(f"cases not found: {p}") return 2 cases = [json.loads(line) for line in p.read_text(encoding="utf-8").splitlines() if line.strip()] orch = Orchestrator() passed = 0 failed = 0 for i, c in enumerate(cases, 1): cid = f"case_{i}" route, action, state = await full_decide(orch, cid, c.get("msg", ""), c.get("goods_order", "")) ok = route == c.get("expected_route") and action == c.get("expected_action") if ok and c.get("expected_stage"): ok = state.get("after_sales_stage") == c.get("expected_stage") if ok: passed += 1 print(f"[PASS] {c.get('id')} route={route} action={action} stage={state.get('after_sales_stage')}") else: failed += 1 print( f"[FAIL] {c.get('id')} expect=({c.get('expected_route')},{c.get('expected_action')},{c.get('expected_stage','-')}) " f"got=({route},{action},{state.get('after_sales_stage')})" ) print(f"\nSummary: passed={passed} failed={failed} total={len(cases)} mode={args.mode}") return 1 if failed else 0 if __name__ == "__main__": raise SystemExit(asyncio.run(main()))