Files
ROMFASTSQL/proxmox/lxc171-claude-agent/maria-whatsapp-bridge/tests/test_triaj.py
Claude Agent 0ace9f97ac fix(maria): fara "caut informatia" la completari, si trei feluri de raspuns
Din firul testat in grup: la "Urgent este", "Nu m-a contactat nimeni. Cat mai
dureaza?" si "Tot nimic", Maria trimitea de fiecare data "Caut informatia, revin
imediat...", calcula un embedding pe care il arunca, si raspundea acelasi sablon
("am adaugat si asta la M-..."). La intrebarea "cat mai dureaza" nu raspundea deloc,
iar "urgent" nu schimba nimic nicaieri.

- Completarea se decide INAINTEA confirmarii si a cautarii: raspunsul vine instant,
  deci nici promisiune, nici embedding degeaba (~1-2s per mesaj).
- triaj.fel_completare: urgenta / stare / detaliu.
  - urgenta -> escaladarea se marcheaza si suportul primeste un mesaj cu URGENT;
  - stare -> raspuns cu ce stim (de cat timp asteapta) si reamintire catre echipa,
    cel mult una la 15 minute, ca sa nu sune telefonul la fiecare "tot nimic";
  - detaliu -> confirmare scurta, cu formularea rotita.
- Peste 30 de minute fara raspuns Maria o spune pe fata si indruma spre telefon
  (SUPPORT_PHONE), in loc sa repete ca "echipa vede detaliul".
- Gramatica: "acum 10 minute", nu "acum 10 de minute".

Teste: 99 pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4uzvgm7AyJch5WH8QHRhY
2026-09-01 07:19:06 +00:00

172 lines
6.6 KiB
Python

"""Triajul: cand se cer detalii, cand pleaca automat la programatori."""
from __future__ import annotations
import json
import time
import triaj
CHUNK_06550 = """[eroare ORA 06550]
keywords: ORA-06550 PLS-00201 eroare compilare
mesaj eroare: ORA-06550: eroare de compilare in program
ce inseamna: Programul nu e adus la zi peste tot.
rezolvare: Nu se rezolva din aplicatie si nu ajuta sa incerci din nou.
cand suni suportul: Intotdeauna. Trimite si o captura de ecran."""
CHUNK_04068 = """[eroare ORA 04068]
mesaj eroare: ORA-04068: existing state of packages has been discarded
ce inseamna: Programul a fost actualizat in timp ce aplicatia ta era deschisa.
rezolvare: Inchide complet aplicatia si redeschide-o.
cand suni suportul: Daca revine si dupa restartul aplicatiei."""
def test_nivelul_se_citeste_din_dictionar():
assert triaj.nivel_suport(CHUNK_06550) == "intotdeauna"
assert triaj.nivel_suport(CHUNK_04068) is None
assert triaj.nivel_suport("cand suni suportul: Imediat. Blocheaza tot.") == "imediat"
def test_raspunsul_nu_vorbeste_ca_pentru_programatori():
"""Cazul din 2026-09-01: modelul ii cerea unui contabil sa verifice schema."""
text = triaj.raspuns_escaladat(CHUNK_06550, "intotdeauna", "M-260901-A1B2",
True, cu_imagine=True)
jos = text.lower()
for cuvant in ("procedura", "schema", "pl/sql", "obiect", "variabila", "compilare"):
assert cuvant not in jos, cuvant
assert "M-260901-A1B2" in text
assert "captura" in jos
assert "blocheaza complet" in jos # intreaba cat e de urgent
def test_cand_notificarea_nu_a_plecat_nu_promitem_ca_a_plecat():
text = triaj.raspuns_escaladat(CHUNK_06550, "intotdeauna", "M-1", False)
assert "am inregistrat" in text.lower()
assert "te contacteaza cineva" not in text.lower()
def test_prea_vag_doar_pentru_acuzatii_fara_continut():
assert triaj.prea_vag("am o eroare", False)
assert triaj.prea_vag("nu merge nimic", False)
# o intrebare adevarata nu se opreste ca sa i se ceara detalii
assert not triaj.prea_vag("cum trimit declaratia D406 SAF-T", False)
# un cod inseamna ca avem deja dupa ce cauta
assert not triaj.prea_vag("imi da ORA-01722 la salvare", False)
# captura vorbeste de la sine
assert not triaj.prea_vag("am o eroare", True)
# --- completarea la o escaladare deschisa -----------------------------------
def _escaladare(ref: str) -> None:
import config
d = config.STATE_DIR / "escalations"
d.mkdir(parents=True, exist_ok=True)
(d / f"{int(time.time())}-{ref}.json").write_text(
json.dumps({"ref": ref, "text": "eroare initiala"}), encoding="utf-8")
def _fara_suport(monkeypatch):
import config
monkeypatch.setattr(config, "get", lambda k, d=None: "" if k == "SUPPORT_JID"
else config.DEFAULTS.get(k, d))
def test_completarea_intra_in_escaladarea_deschisa(monkeypatch):
import config
import consumer
_fara_suport(monkeypatch)
_escaladare("M-TEST-1")
raspuns = consumer.completeaza("M-TEST-1", {"id": "x"}, "eram la salvarea unei facturi")
assert "M-TEST-1" in raspuns
fisier = next((config.STATE_DIR / "escalations").glob("*-M-TEST-1.json"))
record = json.loads(fisier.read_text(encoding="utf-8"))
assert record["completari"][0]["text"] == "eram la salvarea unei facturi"
assert record["completari"][0]["fel"] == "detaliu"
def test_completarile_se_aduna_si_nu_repeta_acelasi_text(monkeypatch):
"""Trei confirmari identice una dupa alta suna a robot."""
import config
import consumer
_fara_suport(monkeypatch)
_escaladare("M-TEST-3")
raspunsuri = [consumer.completeaza("M-TEST-3", {"id": str(i)}, t) for i, t in enumerate(
["eram la facturi", "si la rapoarte", "si la import"])]
assert len(set(raspunsuri)) == 3
fisier = next((config.STATE_DIR / "escalations").glob("*-M-TEST-3.json"))
record = json.loads(fisier.read_text(encoding="utf-8"))
assert len(record["completari"]) == 3
def test_urgenta_marcheaza_escaladarea_si_anunta(monkeypatch):
import config
import consumer
trimise = []
monkeypatch.setattr(consumer, "_notifica_suport",
lambda text: trimise.append(text) or True)
_escaladare("M-TEST-U")
raspuns = consumer.completeaza("M-TEST-U", {"id": "u"}, "Este foarte urgent, ma blocheaza")
record = json.loads(next((config.STATE_DIR / "escalations").glob("*-M-TEST-U.json"))
.read_text(encoding="utf-8"))
assert record["urgenta"] is True
assert record["completari"][0]["fel"] == "urgenta"
assert trimise and trimise[0].startswith("[Maria] URGENT")
assert "urgenta" in raspuns.lower()
def test_intrebarea_de_stare_primeste_un_raspuns_nu_o_confirmare(monkeypatch):
"""„Nu m-a contactat nimeni. Cat mai dureaza?" primea „am adaugat si asta"."""
import config
import consumer
trimise = []
monkeypatch.setattr(consumer, "_notifica_suport",
lambda text: trimise.append(text) or True)
_escaladare("M-TEST-S")
raspuns = consumer.completeaza("M-TEST-S", {"id": "s"},
"Nu m-a contactat nimeni. Cat mai dureaza?")
assert "am adaugat" not in raspuns.lower()
assert "M-TEST-S" in raspuns
assert trimise and "intreaba" in trimise[0]
# a doua intrebare la un minut distanta nu mai suna telefonul echipei
trimise.clear()
consumer.completeaza("M-TEST-S", {"id": "s2"}, "tot nimic")
assert not trimise
def test_dupa_o_jumatate_de_ora_maria_o_spune_pe_fata():
import triaj
text = triaj.raspuns_stare("M-1", 42, False, telefon="0241 000 000")
assert "42" in text and "0241 000 000" in text
assert "nu mi-a raspuns nimeni" in text
def test_fel_completare():
import triaj
assert triaj.fel_completare("Este foarte urgent") == "urgenta"
assert triaj.fel_completare("ma blocheaza complet") == "urgenta"
assert triaj.fel_completare("Cat mai dureaza?") == "stare"
assert triaj.fel_completare("Tot nimic") == "stare"
assert triaj.fel_completare("eram la salvarea unei facturi") == "detaliu"
# ordinea conteaza: urgenta bate intrebarea de stare
assert triaj.fel_completare("urgent, cat mai dureaza?") == "urgenta"
def test_a_doua_intrebare_de_stare_nu_repeta_acelasi_text():
import triaj
intai = triaj.raspuns_stare("M-1", 10, False, a_cata=0)
apoi = triaj.raspuns_stare("M-1", 11, False, a_cata=1)
assert intai != apoi
# „acum 10 minute", nu „acum 10 de minute"
assert "10 minute" in intai and "10 de minute" not in intai
assert triaj.minute_text(25) == "25 de minute"