Files
ROMFASTSQL/proxmox/lxc171-claude-agent/maria-whatsapp-bridge/tests/test_triaj.py
Claude Agent 4d6ff1940f feat(maria): fir de discutie — continuarea nu mai e tratata ca eroare noua
Fiecare mesaj pornea de la zero. Masurat pe indexul viu, dupa o escaladare pentru
ORA-06550: "da, ma blocheaza complet" primea raspuns despre ordinul de plata la
Trezorerie (cosinus 0,642, "acoperit"), "eram la salvarea unei facturi" despre
corectia unei eFacturi (0,742), iar "am incercat si tot nu merge" cerea din nou
detaliile tocmai date. Patru cuvinte fara context seamana cu ceva din documente,
iar cautarea nu avea de unde sti ca sunt raspunsul la intrebarea Mariei.

rag/fir.py tine ancora (textul erorii), codurile ei, referinta escaladarii si
ultimele 6 schimburi, in ~/.maria-bridge/conversations/ (expira, ca si capturile).
La o continuare: cautarea e pe ancora + mesajul nou, modelul primeste istoricul,
mesajul se adauga la escaladarea deschisa de cate ori e nevoie, iar "mesaj prea
vag" nu se mai aplica. Escaladarea duce firul intreg la suport, nu un mesaj rupt
din context.

Firul se rupe doar la o captura noua sau un cod de eroare diferit — schimbarea
subiectului in cuvinte e prea usor de confundat cu o continuare.

In plus:
- Maria tace 60 min cand preia un om, dar automat doar in grupuri cu >= 2
  participanti: in self-chat totul e `fromMe`. Comenzi explicite oriunde
  ("Maria, stop" / "Maria, continua").
- ALLOWED_GROUP_JIDS: testarea se muta in grupul "Maria Test"
  (120363409761730101@g.us), ca sa nu mai poluam chatul "Eu". Filtru si in punte,
  si in consumer. NU echo-test: puntea lui Echo nu filtreaza fromMe in grupuri,
  deci cei doi boti ar intra in bucla.

Teste: 94 pass. Calibrare 23/23, cu doua cazuri de continuare.

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

99 lines
3.9 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 test_raspunsul_despre_urgenta_intra_in_escaladarea_deschisa(monkeypatch):
import config
import consumer
monkeypatch.setattr(config, "get", lambda k, d=None: "" if k == "SUPPORT_JID"
else config.DEFAULTS.get(k, d))
_escaladare("M-TEST-1")
assert consumer.append_followup("M-TEST-1", {"id": "x"}, "ma blocheaza, nu pot factura")
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"] == "ma blocheaza, nu pot factura"
def test_completarile_se_aduna_nu_se_inlocuiesc(monkeypatch):
"""Omul raspunde de mai multe ori; prima data nu inchide firul."""
import config
import consumer
monkeypatch.setattr(config, "get", lambda k, d=None: "" if k == "SUPPORT_JID"
else config.DEFAULTS.get(k, d))
_escaladare("M-TEST-3")
consumer.append_followup("M-TEST-3", {"id": "a"}, "da, ma blocheaza")
consumer.append_followup("M-TEST-3", {"id": "b"}, "eram la salvarea unei facturi")
fisier = next((config.STATE_DIR / "escalations").glob("*-M-TEST-3.json"))
record = json.loads(fisier.read_text(encoding="utf-8"))
assert [c["text"] for c in record["completari"]] == [
"da, ma blocheaza", "eram la salvarea unei facturi"]