Spaces:
Sleeping
Sleeping
| """ | |
| Regression tests β one test per failure in the feedback. | |
| Runs with the RULES backend (no model download) so it's fast and CI-able. | |
| The LLM backends only improve on these results. | |
| """ | |
| import sys | |
| import logging | |
| logging.basicConfig(level=logging.WARNING) | |
| from nlu import NLU | |
| from orchestrator import Orchestrator, fmt_amount | |
| PASS, FAIL = "\033[92mPASS\033[0m", "\033[91mFAIL\033[0m" | |
| results = [] | |
| def check(name: str, cond: bool, detail: str = ""): | |
| results.append((name, cond)) | |
| print(f" [{PASS if cond else FAIL}] {name}" + (f" β {detail}" if detail else "")) | |
| def new_orch(): | |
| return Orchestrator(nlu=NLU(prefer="rules")) | |
| def turn(orch, session, text): | |
| resp, session, esc = orch.respond(text, text, session) | |
| return resp, session, esc | |
| print("\nββ P1: 'send money to abu now' must NOT re-ask for recipient ββ") | |
| orch = new_orch() | |
| s = orch.new_session() | |
| resp, s, _ = turn(orch, s, "I want to send money to abu now") | |
| check("recipient 'abu' prefilled (no 'who do you want to send to')", | |
| "who" not in resp.lower() and "abu" not in resp.lower().replace("abu", "") or | |
| ("recipient" not in resp.lower() and "who would you like to send" not in resp.lower()), | |
| f"agent said: {resp[:90]}") | |
| check("asks for the AMOUNT instead (the actually-missing slot)", | |
| "how much" in resp.lower(), f"agent said: {resp[:90]}") | |
| print("\nββ P0: compound 'check my balance and also send 350000 to amina' ββ") | |
| orch = new_orch() | |
| s = orch.new_session() | |
| resp, s, _ = turn(orch, s, "check my balance and also send 350000 to amina") | |
| check("acknowledges BOTH tasks", "one at a time" in resp.lower() or | |
| ("balance" in resp.lower() and ("transfer" in resp.lower() or "amina" in resp.lower())), | |
| f"agent said: {resp[:120]}") | |
| # give account number β balance executes, transfer flow continues | |
| resp, s, _ = turn(orch, s, "1234567890") | |
| check("balance is delivered", "balance is" in resp.lower(), f"{resp[:90]}") | |
| check("transfer to amina NOT dropped (asks to confirm or continues it)", | |
| "amina" in resp.lower() or "send" in resp.lower() or "confirm" in resp.lower() | |
| or "yes" in resp.lower(), | |
| f"{resp[:140]}") | |
| print("\nββ P0: 'where is your closest branch so I can get my ATM card' ββ") | |
| orch = new_orch() | |
| s = orch.new_session() | |
| resp, s, _ = turn(orch, s, "where is your closest branch so I can get my ATM card") | |
| check("NOT classified as block_card (no 'block' confirmation)", | |
| "block" not in resp.lower(), f"{resp[:120]}") | |
| check("gives branch info", "branch" in resp.lower() or "open" in resp.lower(), | |
| f"{resp[:120]}") | |
| print("\nββ P1: return reason 'too small' must not dead-end ββ") | |
| orch = new_orch() | |
| s = orch.new_session() | |
| resp, s, _ = turn(orch, s, "I want to return my order") | |
| resp, s, _ = turn(orch, s, "ORD-4521") | |
| resp, s, _ = turn(orch, s, "too small") | |
| check("'too small' accepted as return reason", | |
| "too small" in resp.lower() or "return" in resp.lower(), | |
| f"{resp[:120]}") | |
| check("no 'did not understand' dead-end", | |
| "didn't understand" not in resp.lower() and "did not understand" not in resp.lower(), | |
| f"{resp[:90]}") | |
| print("\nββ P1: unknown input β clarify once, then human WITH context ββ") | |
| orch = new_orch() | |
| s = orch.new_session() | |
| resp, s, esc = turn(orch, s, "florble the wumbus") | |
| check("first unknown β clarifying question, not menu dump", | |
| "are you asking" in resp.lower() or "balance" in resp.lower(), f"{resp[:110]}") | |
| check("not escalated yet", not esc) | |
| resp, s, esc = turn(orch, s, "zorp zorp quux") | |
| check("second unknown β human handoff", esc, f"{resp[:110]}") | |
| check("handoff mentions context is preserved", | |
| "won't have to repeat" in resp.lower() or "conversation" in resp.lower(), | |
| f"{resp[:140]}") | |
| print("\nββ P2: balance guard β 350,000 against smaller balance ββ") | |
| orch = new_orch() | |
| s = orch.new_session() | |
| resp, s, _ = turn(orch, s, "check my balance") | |
| resp, s, _ = turn(orch, s, "1111111") # deterministic mock balance | |
| bal = s.balance | |
| too_much = bal + 100_000 | |
| resp, s, _ = turn(orch, s, f"send {too_much} to musa") | |
| check("over-balance transfer is refused, not confirmed", | |
| "can't process" in resp.lower() or "balance is" in resp.lower(), | |
| f"balance={fmt_amount(bal)}, asked={fmt_amount(too_much)} β {resp[:130]}") | |
| print("\nββ P2: consistent β¦ formatting ββ") | |
| check("fmt_amount('350000') == 'β¦350,000'", fmt_amount("350000") == "β¦350,000") | |
| check("fmt_amount('134200') == 'β¦134,200'", fmt_amount("134200") == "β¦134,200") | |
| check("fmt_amount(245000) == 'β¦245,000'", fmt_amount(245000) == "β¦245,000") | |
| print("\nββ Destructive confirmation gate ββ") | |
| orch = new_orch() | |
| s = orch.new_session() | |
| resp, s, _ = turn(orch, s, "send 5000 to fatima") | |
| resp, s, _ = turn(orch, s, "1234567890") # account slot | |
| check("transfer requires explicit yes/no before executing", | |
| "yes" in resp.lower() and "confirm" in resp.lower(), f"{resp[:130]}") | |
| resp, s, _ = turn(orch, s, "no") | |
| check("'no' cancels cleanly", "cancelled" in resp.lower(), f"{resp[:90]}") | |
| # ββ Summary ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| passed = sum(1 for _, ok in results if ok) | |
| total = len(results) | |
| print(f"\n{'='*60}\n {passed}/{total} checks passed\n{'='*60}") | |
| sys.exit(0 if passed == total else 1) | |