33
44from __future__ import annotations
55
6- from dataclasses import dataclass
6+ from dataclasses import dataclass , field
77
88from gooddata_eval .core .chat .sse_client import ChatClient
99from gooddata_eval .core .config import ReasoningEffort
1010from gooddata_eval .core .evaluators ._llm_judge import LLMJudge
11+ from gooddata_eval .core .models import AgenticEvalOutcome
1112
1213_DEFAULT_K = 1
1314
@@ -49,6 +50,8 @@ class GuardrailResult:
4950 passed : bool
5051 llm_judge_score : float
5152 reasoning : str
53+ reasoning_steps : list [str ] = field (default_factory = list )
54+ response_id : str | None = None
5255
5356
5457@dataclass
@@ -95,6 +98,8 @@ def run_agentic_guardrail(
9598 passed = passed ,
9699 llm_judge_score = llm_judge_score ,
97100 reasoning = reasoning ,
101+ reasoning_steps = list (chat_result .reasoning_steps or []),
102+ response_id = chat_result .response_id ,
98103 )
99104 )
100105 finally :
@@ -117,6 +122,8 @@ def run_agentic_guardrail(
117122 passed = passed ,
118123 llm_judge_score = llm_judge_score ,
119124 reasoning = reasoning ,
125+ reasoning_steps = list (chat_result .reasoning_steps or []),
126+ response_id = chat_result .response_id ,
120127 )
121128 )
122129 finally :
@@ -139,6 +146,10 @@ class GuardrailAssertionError(AssertionError):
139146 """Raised when a guardrail evaluation fails."""
140147
141148 __tracebackhide__ = True
149+ reasoning_steps : list [str ]
150+ conversation_id : str
151+ response_id : str | None
152+ detail : dict
142153
143154
144155def evaluate_agentic_guardrail (
@@ -157,8 +168,14 @@ def evaluate_agentic_guardrail(
157168 model_version_override : str | None = None ,
158169 run_metadata_extra : dict | None = None ,
159170 reasoning_effort : ReasoningEffort | None = None ,
160- ) -> None :
161- """Run guardrail evaluation, log to Langfuse, and raise on failure."""
171+ ) -> AgenticEvalOutcome :
172+ """Run guardrail evaluation, log to Langfuse, and raise GuardrailAssertionError on failure.
173+
174+ Returns the best run's outcome (reasoning_steps, conversation_id, response_id) as an
175+ AgenticEvalOutcome on success; on failure the same three values are attached to the
176+ raised exception as ``.reasoning_steps``/``.conversation_id``/``.response_id`` (mirrors
177+ `evaluate_agentic_metric_skill`'s idiom) so callers can retrieve them either way.
178+ """
162179 from datetime import datetime as _dt # noqa: PLC0415
163180 from datetime import timezone as _tz # noqa: PLC0415
164181
@@ -220,4 +237,24 @@ def evaluate_agentic_guardrail(
220237
221238 if not summary .pass_at_k :
222239 best = summary .best
223- raise GuardrailAssertionError (f"Guardrail assertion failed. passed={ best .passed } . Reasoning: { best .reasoning } " )
240+ exc = GuardrailAssertionError (f"Guardrail assertion failed. passed={ best .passed } . Reasoning: { best .reasoning } " )
241+ exc .reasoning_steps = best .reasoning_steps
242+ exc .conversation_id = best .conversation_id
243+ exc .response_id = best .response_id
244+ exc .detail = {
245+ "judge_passed" : best .passed ,
246+ "judge_reasoning" : best .reasoning ,
247+ "actual_output" : best .actual_output ,
248+ }
249+ raise exc
250+ best = summary .best
251+ return AgenticEvalOutcome (
252+ reasoning_steps = best .reasoning_steps ,
253+ conversation_id = best .conversation_id ,
254+ response_id = best .response_id ,
255+ detail = {
256+ "judge_passed" : best .passed ,
257+ "judge_reasoning" : best .reasoning ,
258+ "actual_output" : best .actual_output ,
259+ },
260+ )
0 commit comments