Files
ROMFASTSQL/proxmox/lxc171-claude-agent/maria-whatsapp-bridge/tests/test_triaj.py
Claude Agent 5342875aa2 feat(maria): triaj — raspuns pentru utilizatori, escaladare automata la programatori
Pe captura cu ORA-06550, avand in context chiar intrarea din dictionar care spune
"nu se rezolva din aplicatie", modelul i-a raspuns unui contabil sa verifice
schema de date si sa foloseasca "procedura alternativa MI_pack_parteneri_old" —
inventata. Si nu escalada, fiindca escaladarea se declansa doar cand NU exista
acoperire in documente, iar aici exista.

rag/triaj.py, trei decizii inaintea modelului:

- **Mesaj prea vag.** "Am o eroare" -> Maria cere operatiunea, ecranul si textul
  erorii, in loc sa ghiceasca. Regula e ingusta: text scurt, fara captura, fara cod.
- **Erori marcate "Intotdeauna"/"Imediat" in dictionar** (9 din 29) -> raspunsul se
  compune din campurile dictionarului, fara model, si pleaca automat la suport cu
  referinta si captura. Textul de acolo e scris pentru clienti; parafrazarea lui nu
  adauga nimic si poate strica tot.
- **Urgenta se intreaba, nu se deduce.** Raspunsul ("ma blocheaza" / "pot continua")
  se ataseaza escaladarii deschise, nu deschide alta referinta. Fereastra 30 min.

In plus: SYSTEM_PROMPT interzice explicit vocabularul tehnic (procedura, schema,
tabela, PL/SQL, compilare, sesiune) si propunerile de verificat baza de date; cele
mai tehnice cinci intrari din dictionar rescrise in limbaj de client.

Teste: 85 pass. Calibrare 21/21. Reindexare: 5 embeddings noi, 164 refolosite.

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

96 lines
3.8 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")
consumer.pending_set("40712@s.whatsapp.net", "M-TEST-1")
assert consumer.pending_get("40712@s.whatsapp.net")["ref"] == "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"
consumer.pending_clear("40712@s.whatsapp.net")
assert consumer.pending_get("40712@s.whatsapp.net") is None
def test_completarea_expira(monkeypatch):
import consumer
consumer.pending_set("40799@s.whatsapp.net", "M-TEST-2")
peste_o_ora = time.time() + consumer.PENDING_TTL_S + 1
monkeypatch.setattr(consumer.time, "time", lambda: peste_o_ora)
assert consumer.pending_get("40799@s.whatsapp.net") is None