from __future__ import annotations import asyncio, threading from agent_framework.guardrails.base import RailDecision from agent_framework.guardrails.parallel_executor import ParallelRailExecutor from agent_framework.guardrails.config_loader import load_guardrails_config from agent_framework.judges.judge import JudgePipeline, JudgeResult def test_contas_config_substitui_policies_tim_por_extensoes(): bundle=load_guardrails_config('config/guardrails.yaml') codes=[r.code for r in bundle.output_rails] assert 'TIM_OOS' in codes and 'TIM_AOFERTA' in codes and 'TIM_REVPREC' in codes assert 'OOS' not in codes and 'AOFERTA' not in codes and 'REVPREC' not in codes def test_sync_external_rail_runs_in_worker_thread(): main=threading.current_thread().name class R: code='THREAD_TEST' def evaluate(self,text,ctx): return RailDecision(code=self.code,allowed=True,metadata={'thread':threading.current_thread().name}) result=asyncio.run(ParallelRailExecutor().run('x',{},[R()])) assert result.results[0].metadata['thread'] != main def test_external_judges_load_from_agent_config(): pipeline=JudgePipeline(config_path='config/judges.yaml', llm=None) assert [j.name for j in pipeline.judges] == ['tim_response_quality','tim_groundedness'] def test_sync_judges_run_concurrently_in_threads(): names=[] class J: def __init__(self,name): self.name=name def evaluate(self,q,a,c): names.append(threading.current_thread().name) return JudgeResult(name=self.name,score=1,passed=True) p=JudgePipeline(judges=[J('a'),J('b')], enabled=True) p.sample_rate=1.0 results=asyncio.run(p.evaluate_all('q','answer with enough text',{})) assert [r.name for r in results]==['a','b'] assert all(n != threading.current_thread().name for n in names)