Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/hesabixAPI/tests/test_ai_agent_regression_db.py
Babak Alizadeh 0c4079d765 fix(ai): evidence-based agent loop without semantic regex on model text
Replace regex/LLM shims for continue/stop decisions with structural evidence
(API tool_calls, Harmony parser, ObservationStore). Add DB regression fixtures
and remove unused aux.agent_continuation prompt.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-16 09:44:43 +00:00

106 lines
3.6 KiB
Python

"""Regression از پیام‌های واقعی DB — اعتبارسنجی Plan C روی باگ‌های شناخته‌شده."""
from __future__ import annotations
import json
import os
from pathlib import Path
import pytest
from app.services.ai.ai_agent_continuation import (
assess_text_round_evidence,
resolve_needs_tools,
)
from app.services.ai.ai_budget import build_agent_budget
from app.services.ai.ai_exploration_service import ObservationStore
from app.services.ai.ai_goal_assessment import (
AgentGoalTracker,
should_agent_continue_after_text_round,
)
from app.services.ai.ai_trace import extract_final_content_from_trace
_FIXTURES = Path(__file__).parent / "fixtures" / "agent_regression_db.json"
_CASES = json.loads(_FIXTURES.read_text(encoding="utf-8"))
@pytest.mark.parametrize("case", _CASES, ids=lambda c: c["id"])
def test_db_regression_evidence(case):
needs_tools = case.get("needs_tools_override")
history = case.get("history_messages")
if needs_tools is None:
needs_tools = resolve_needs_tools(case["user_query"], history)
result = assess_text_round_evidence(
round_text=case["round_text"],
user_query=case["user_query"],
observation_store=ObservationStore(),
needs_tools=needs_tools,
)
assert result.should_continue == case["expect_continue"], (
f"{case['id']}: expected continue={case['expect_continue']}, "
f"got {result.should_continue} ({result.reason_fa})"
)
assert result.goal_reached == case["expect_goal_reached"]
@pytest.mark.parametrize(
"case",
[c for c in _CASES if c["expect_continue"]],
ids=lambda c: c["id"],
)
def test_db_regression_agent_loop_would_continue(case):
budget = build_agent_budget("medium", max_iterations=6)
needs_tools = case.get("needs_tools_override")
history = case.get("history_messages")
if needs_tools is None:
needs_tools = resolve_needs_tools(case["user_query"], history)
result = should_agent_continue_after_text_round(
goal_tracker=AgentGoalTracker(),
observation_store=ObservationStore(),
exploration_enabled=True,
iteration=2,
budget=budget,
round_text=case["round_text"],
user_query=case["user_query"],
history_messages=history,
needs_tools=needs_tools,
)
assert result is True, f"{case['id']}: agent loop should continue, not stop"
@pytest.mark.skipif(
not os.getenv("DB_HOST"),
reason="DB not configured — set DB_HOST to run live trace checks",
)
def test_db_1350_trace_has_no_answer_fallback():
"""پیام budget (msg 1350) نباید از trace به answer fallback شود."""
import json as json_mod
from sqlalchemy import create_engine, text
from app.core.settings import get_settings
settings = get_settings()
url = (
f"postgresql://{settings.db_user}:{settings.db_password}"
f"@{settings.db_host}:{settings.db_port}/{settings.db_name}"
)
engine = create_engine(url)
with engine.connect() as conn:
row = conn.execute(
text(
"SELECT content, function_results FROM ai_chat_messages "
"WHERE id = 1350"
),
).fetchone()
assert row is not None
content, function_results = row
trace_raw = json_mod.loads(function_results or "{}").get("_agent_trace", [])
extracted = extract_final_content_from_trace(trace_raw)
assert extracted == "", (
"budget stop message trace must not synthesize answer from narrative/plan steps"
)
assert "دادهٔ تازه" in content