@@ -449,3 +449,74 @@ def evaluate_before_model(self, **_: Any) -> None:
449449 with caplog .at_level (logging .WARNING ):
450450 cb .on_request ([ModelRequest (parts = [UserPromptPart (content = "x" )])])
451451 assert any ("governance check failed" in r .message for r in caplog .records )
452+
453+
454+ # --------------------------------------------------------------------------
455+ # coverage: swallow paths on every hook + extraction/helper edges
456+ # --------------------------------------------------------------------------
457+
458+
459+ class _Boom :
460+ """Evaluator whose every evaluate_* raises a non-block error."""
461+
462+ def __getattr__ (self , _name : str ) -> Any :
463+ def _raise (* _a : Any , ** _k : Any ) -> None :
464+ raise RuntimeError ("evaluator bug" )
465+
466+ return _raise
467+
468+
469+ @pytest .mark .parametrize (
470+ "invoke" ,
471+ [
472+ lambda cb : cb .on_response (
473+ ModelResponse (
474+ parts = [
475+ TextPart (content = "x" ),
476+ ToolCallPart (tool_name = "t" , args = {}, tool_call_id = "c" ),
477+ ]
478+ )
479+ ),
480+ lambda cb : cb .on_request (
481+ [
482+ ModelRequest (
483+ parts = [ToolReturnPart (tool_name = "t" , content = "r" , tool_call_id = "c" )]
484+ )
485+ ]
486+ ),
487+ ],
488+ )
489+ def test_response_and_tool_paths_swallow_non_block_errors (invoke , caplog ):
490+ cb = GovernanceCallbacks (evaluator = _Boom (), agent_name = "a" , session_id = "s" ) # type: ignore[arg-type]
491+ with caplog .at_level (logging .WARNING ):
492+ invoke (cb ) # must NOT raise — a governance bug can't break the run
493+ assert any ("governance check failed" in r .message for r in caplog .records )
494+
495+
496+ def test_on_request_with_only_model_response_scans_empty ():
497+ # history ending with (only) a ModelResponse → no ModelRequest → empty input
498+ ev = FakeEvaluator ()
499+ cb = _make_callbacks (ev )
500+ cb .on_request ([ModelResponse (parts = [TextPart (content = "assistant" )])])
501+ assert ev .calls [0 ][1 ]["model_input" ] == ""
502+
503+
504+ def test_extraction_and_helper_edges ():
505+ from uipath_pydantic_ai .governance .model import (
506+ _content_text ,
507+ _stringify ,
508+ _tool_name ,
509+ )
510+
511+ # _content_text: None / str / list-of-(str|obj) / bare object
512+ assert _content_text (None ) == ""
513+ assert _content_text ("plain" ) == "plain"
514+ assert "a" in _content_text (["a" , SimpleNamespace (text = "b" )])
515+ assert isinstance (_content_text (SimpleNamespace ()), str )
516+ # _stringify: str passthrough + circular-ref fallback (no crash)
517+ assert _stringify ("hi" ) == "hi"
518+ circular : dict [str , Any ] = {}
519+ circular ["self" ] = circular
520+ assert isinstance (_stringify (circular ), str )
521+ # _tool_name: missing name → warns + "unknown"
522+ assert _tool_name (SimpleNamespace ()) == "unknown"
0 commit comments