adjustments: manual

This commit is contained in:
2026-09-12 07:11:07 -03:00
parent 7a22b7af11
commit 2f9b053098
3 changed files with 940 additions and 231 deletions

View File

@@ -0,0 +1,190 @@
from __future__ import annotations
import ast
import re
import sys
from pathlib import Path
from types import MethodType, SimpleNamespace
import pytest
ROOT = Path(__file__).resolve().parents[1]
FRAMEWORK_SRC = ROOT / "libs" / "agent_framework" / "src"
TEMPLATE_ROOT = ROOT / "templates" / "agent_template_backend"
for path in (FRAMEWORK_SRC, TEMPLATE_ROOT):
if str(path) not in sys.path:
sys.path.insert(0, str(path))
EXAMPLES = (
("README.md", "**COPIAR — arquivo completo canônico:**"),
("README_en.md", "**COPY — complete canonical file:**"),
)
class FakeLLM:
def __init__(self):
self.calls = 0
async def ainvoke(self, messages, **kwargs):
self.calls += 1
assert messages
assert kwargs["profile_name"] == "FinanceiroAgent"
return "resposta documentada"
class CaptureObserver:
def __init__(self):
self.events: list[tuple[str, dict, str | None]] = []
async def emit_ic(self, code, payload, component=None):
self.events.append((code, payload, component))
def extract_documented_class(readme_name: str, marker: str):
text = (ROOT / readme_name).read_text(encoding="utf-8")
marked = text[text.index(marker) :]
match = re.search(r"```python\n(.*?)\n```", marked, re.DOTALL)
assert match, f"Bloco Python canônico ausente em {readme_name}"
source = match.group(1)
ast.parse(source, filename=readme_name)
namespace: dict[str, object] = {}
exec(compile(source, readme_name, "exec"), namespace)
return namespace["FinanceiroAgent"], source
def make_agent(agent_class, *, observer=None):
llm = FakeLLM()
agent = agent_class(
llm,
settings=SimpleNamespace(CACHE_TTL_SECONDS=0, RAG_PROVIDER="standard"),
observer=observer,
)
return agent, llm
def base_state():
return {
"user_text": "Qual é a situação do meu pagamento?",
"sanitized_input": "Qual é a situação do meu pagamento?",
"session_id": "readme-test",
"tenant_id": "default",
"agent_id": "financeiro_agent",
"route": "financeiro_agent",
"intent": "financeiro_pagamentos",
"mcp_tools": [],
"context": {},
}
@pytest.mark.parametrize(("readme_name", "marker"), EXAMPLES)
def test_documented_financeiro_agent_compiles_and_uses_current_contract(readme_name, marker):
_, source = extract_documented_class(readme_name, marker)
required = {
"transaction_clarification_message",
"transaction_confirmation_message",
"build_direct_mcp_answer",
"prepare_memory_context",
"build_messages",
"transaction_state_patch",
"rag_results",
"IC.FINANCEIRO_RAG_CONTEXT_EVALUATED",
}
assert all(item in source for item in required)
@pytest.mark.asyncio
@pytest.mark.parametrize(("readme_name", "marker"), EXAMPLES)
async def test_documented_financeiro_agent_runs_normal_composition(readme_name, marker):
agent_class, _ = extract_documented_class(readme_name, marker)
observer = CaptureObserver()
agent, llm = make_agent(agent_class, observer=observer)
result = await agent.run(base_state())
assert result["answer"] == "[FinanceiroAgent] resposta documentada"
assert result["next_state"] == "FINANCEIRO_ACTIVE"
assert result["mcp_results"] == []
assert result["rag"]["status"] == "no_service"
assert result["rag_results"][0]["agent"] == "financeiro_agent"
assert llm.calls == 1
codes = [event[0] for event in observer.events]
assert "IC.FINANCEIRO_AGENT_STARTED" in codes
assert "IC.FINANCEIRO_RAG_CONTEXT_EVALUATED" in codes
assert "IC.FINANCEIRO_AGENT_COMPLETED" in codes
@pytest.mark.asyncio
@pytest.mark.parametrize(("readme_name", "marker"), EXAMPLES)
@pytest.mark.parametrize(
("method_name", "message", "expected_state"),
(
("transaction_clarification_message", "Informe o contrato.", "COLLECTING_PARAMETERS"),
("transaction_confirmation_message", "Confirma a operação?", "AWAITING_CONFIRMATION"),
),
)
async def test_documented_financeiro_agent_returns_before_llm_for_transaction_prompts(
readme_name, marker, method_name, message, expected_state
):
agent_class, _ = extract_documented_class(readme_name, marker)
agent, llm = make_agent(agent_class)
state = base_state()
state["next_state"] = expected_state
setattr(agent, method_name, MethodType(lambda self, state: message, agent))
result = await agent.run(state)
assert result["answer"] == f"[FinanceiroAgent] {message}"
assert result["next_state"] == expected_state
assert llm.calls == 0
@pytest.mark.asyncio
@pytest.mark.parametrize(("readme_name", "marker"), EXAMPLES)
async def test_documented_financeiro_agent_honors_direct_mcp_response(readme_name, marker):
agent_class, _ = extract_documented_class(readme_name, marker)
agent, llm = make_agent(agent_class)
async def collect(self, state):
return [{"ok": True, "tool_name": "consultar_pagamento", "result": {"status": "PAGO"}}]
agent._collect_tool_context = MethodType(collect, agent)
agent.build_direct_mcp_answer = MethodType(
lambda self, state, results, agent_label: "[FinanceiroAgent] Pagamento confirmado.", agent
)
result = await agent.run(base_state())
assert result["answer"] == "[FinanceiroAgent] Pagamento confirmado."
assert result["rag"]["reason"] == "direct_mcp_answer"
assert llm.calls == 0
@pytest.mark.asyncio
@pytest.mark.parametrize(("readme_name", "marker"), EXAMPLES)
async def test_documented_financeiro_agent_emits_complete_rag_evaluation(readme_name, marker):
agent_class, _ = extract_documented_class(readme_name, marker)
observer = CaptureObserver()
agent, llm = make_agent(agent_class, observer=observer)
async def retrieve(self, state):
return "contexto financeiro", {
"provider": "test",
"status": "executed",
"attempted": True,
"enabled": True,
"document_count": 1,
"graph_neighbors": 0,
"latency_ms": 1,
"query": state["sanitized_input"],
"namespace": "financeiro_agent",
}
agent._retrieve_rag_context = MethodType(retrieve, agent)
result = await agent.run(base_state())
codes = [event[0] for event in observer.events]
assert "IC.FINANCEIRO_RAG_CONTEXT_EVALUATED" in codes
assert "IC.FINANCEIRO_RAG_CONTEXT_RETRIEVED" in codes
assert result["rag_context"] == "contexto financeiro"
assert llm.calls == 1