1717LLM_ENV = {
1818 "GALILEO_API_SECRET_KEY" : "test-secret" ,
1919 "GALILEO_LUNA_INVOKE_URL" : "http://luna-invoke:8090" ,
20+ "GALILEO_FEATURE_FLAG_LLM_INVOKE_RUNTIME" : "enabled" ,
2021}
2122
23+ _EXTENSIONS = {
24+ "namespace_key" : "org-1" ,
25+ "caller_id" : "user-1" ,
26+ "target_type" : "log_stream" ,
27+ "target_id" : "run-1" ,
28+ "metadata" : {},
29+ }
30+
31+
32+ def _make_invoke_kwargs () -> dict [str , object ]:
33+ """Minimal required kwargs for GalileoLLMClient.invoke()."""
34+ from agent_control_models import Step
35+
36+ from agent_control_evaluator_galileo .llm .client import GalileoExecutionContext
37+
38+ return {
39+ "step" : Step (type = "llm" , name = "test" , input = "prompt" ),
40+ "execution_context" : GalileoExecutionContext (organization_id = "org-1" ),
41+ }
42+
2243
2344def _decode_jwt_payload (token : str ) -> dict [str , object ]:
2445 payload_segment = token .split ("." )[1 ]
@@ -289,12 +310,15 @@ async def test_evaluator_handles_non_success_status(monkeypatch):
289310 """A non-success status from the scorer must surface as an error result."""
290311 for key , value in LLM_ENV .items ():
291312 monkeypatch .setenv (key , value )
313+ from agent_control_models import Step
314+
292315 from agent_control_evaluator_galileo .llm import LlmEvaluator , ScorerInvokeResponse
293316 from agent_control_evaluator_galileo .llm .client import GalileoLLMClient
294317
295318 evaluator = LlmEvaluator .from_dict (
296319 {"scorer_id" : "scorer-123" , "threshold" : 0.5 , "operator" : "gte" }
297320 )
321+ step = Step (type = "llm" , name = "test" , input = "prompt" )
298322
299323 with patch .object (GalileoLLMClient , "invoke" , new_callable = AsyncMock ) as mock_invoke :
300324 mock_invoke .return_value = ScorerInvokeResponse (
@@ -304,7 +328,7 @@ async def test_evaluator_handles_non_success_status(monkeypatch):
304328 error_message = "upstream timeout" ,
305329 )
306330
307- result = await evaluator .evaluate ("hello" )
331+ result = await evaluator .evaluate_with_extensions ("hello" , step , _EXTENSIONS )
308332
309333 assert result .matched is False
310334 assert result .error is not None
@@ -316,13 +340,16 @@ async def test_evaluator_skips_empty_data(monkeypatch):
316340 """Evaluator skips invocation when there is no text to score."""
317341 for key , value in LLM_ENV .items ():
318342 monkeypatch .setenv (key , value )
343+ from agent_control_models import Step
344+
319345 from agent_control_evaluator_galileo .llm import LlmEvaluator
320346 from agent_control_evaluator_galileo .llm .client import GalileoLLMClient
321347
322348 evaluator = LlmEvaluator .from_dict ({"scorer_id" : "scorer-123" , "threshold" : 0.5 })
349+ step = Step (type = "llm" , name = "test" , input = "prompt" )
323350
324351 with patch .object (GalileoLLMClient , "invoke" , new_callable = AsyncMock ) as mock_invoke :
325- result = await evaluator .evaluate (None )
352+ result = await evaluator .evaluate_with_extensions (None , step , _EXTENSIONS )
326353
327354 assert result .matched is False
328355 assert result .error is None
@@ -335,10 +362,13 @@ async def test_evaluator_returns_error_result_on_http_error(monkeypatch):
335362 """HTTP errors must surface as a non-matched EvaluatorResult with metadata."""
336363 for key , value in LLM_ENV .items ():
337364 monkeypatch .setenv (key , value )
365+ from agent_control_models import Step
366+
338367 from agent_control_evaluator_galileo .llm import LlmEvaluator
339368 from agent_control_evaluator_galileo .llm .client import GalileoLLMClient
340369
341370 evaluator = LlmEvaluator .from_dict ({"scorer_id" : "scorer-123" , "threshold" : 0.5 })
371+ step = Step (type = "llm" , name = "test" , input = "prompt" )
342372
343373 fake_request = httpx .Request ("POST" , "http://luna-invoke:8090/api/v1/scorers/invoke" )
344374 fake_response = httpx .Response (500 , text = "internal server error" , request = fake_request )
@@ -349,7 +379,7 @@ async def test_evaluator_returns_error_result_on_http_error(monkeypatch):
349379 new_callable = AsyncMock ,
350380 side_effect = httpx .HTTPStatusError ("500" , request = fake_request , response = fake_response ),
351381 ):
352- result = await evaluator .evaluate ("hello" )
382+ result = await evaluator .evaluate_with_extensions ("hello" , step , _EXTENSIONS )
353383
354384 assert result .matched is False
355385 assert result .error is not None
@@ -755,7 +785,7 @@ async def test_invoke_raises_when_response_is_not_a_json_object(monkeypatch):
755785
756786 try :
757787 with pytest .raises (RuntimeError , match = "not a JSON object" ):
758- await client .invoke (scorer_id = "scorer-123" , input = "hello" )
788+ await client .invoke (scorer_id = "scorer-123" , input = "hello" , ** _make_invoke_kwargs () )
759789 finally :
760790 await client .close ()
761791
@@ -785,7 +815,7 @@ async def test_invoke_propagates_http_status_error(monkeypatch):
785815
786816 try :
787817 with pytest .raises (httpx .HTTPStatusError ):
788- await client .invoke (scorer_id = "scorer-123" , input = "hello" )
818+ await client .invoke (scorer_id = "scorer-123" , input = "hello" , ** _make_invoke_kwargs () )
789819 finally :
790820 await client .close ()
791821
@@ -806,7 +836,7 @@ async def test_invoke_propagates_request_error(monkeypatch):
806836
807837 try :
808838 with pytest .raises (httpx .RequestError ):
809- await client .invoke (scorer_id = "scorer-123" , input = "hello" )
839+ await client .invoke (scorer_id = "scorer-123" , input = "hello" , ** _make_invoke_kwargs () )
810840 finally :
811841 await client .close ()
812842
@@ -846,6 +876,7 @@ def handler(request: httpx.Request) -> httpx.Response:
846876 scorer_id = "scorer-123" ,
847877 input = "hello" ,
848878 headers = {"Galileo-API-Key" : "should-be-stripped" , "X-Custom" : "keep-me" },
879+ ** _make_invoke_kwargs (),
849880 )
850881 finally :
851882 await client .close ()
@@ -873,7 +904,7 @@ def handler(request: httpx.Request) -> httpx.Response:
873904 client ._client = httpx .AsyncClient (transport = httpx .MockTransport (handler ))
874905
875906 try :
876- await client .invoke (scorer_id = "scorer-123" , input = "hello" )
907+ await client .invoke (scorer_id = "scorer-123" , input = "hello" , ** _make_invoke_kwargs () )
877908 finally :
878909 await client .close ()
879910
@@ -951,7 +982,7 @@ def test_coerce_number_parses_numeric_string(self):
951982
952983@pytest .mark .asyncio
953984async def test_evaluator_with_context_uses_step (monkeypatch ):
954- """evaluate_with_context passes the step to _evaluate ."""
985+ """evaluate_with_extensions passes the step and execution_context to invoke ."""
955986 for key , value in LLM_ENV .items ():
956987 monkeypatch .setenv (key , value )
957988 from agent_control_models import Step
@@ -964,29 +995,33 @@ async def test_evaluator_with_context_uses_step(monkeypatch):
964995
965996 with patch .object (GalileoLLMClient , "invoke" , new_callable = AsyncMock ) as mock_invoke :
966997 mock_invoke .return_value = ScorerInvokeResponse (score = 0.8 , status = "success" )
967- result = await evaluator .evaluate_with_context ("selected input" , step )
998+ result = await evaluator .evaluate_with_extensions ("selected input" , step , _EXTENSIONS )
968999
9691000 assert result .matched is True
9701001 assert mock_invoke .call_args .kwargs ["step" ] == step
1002+ assert mock_invoke .call_args .kwargs ["execution_context" ] is not None
9711003
9721004
9731005@pytest .mark .asyncio
9741006async def test_evaluator_scorer_label_echoed_in_metadata (monkeypatch ):
9751007 """scorer_label echoed from the response is included in result metadata."""
9761008 for key , value in LLM_ENV .items ():
9771009 monkeypatch .setenv (key , value )
1010+ from agent_control_models import Step
1011+
9781012 from agent_control_evaluator_galileo .llm import LlmEvaluator
9791013 from agent_control_evaluator_galileo .llm .client import GalileoLLMClient , ScorerInvokeResponse
9801014
9811015 evaluator = LlmEvaluator .from_dict (
9821016 {"scorer_id" : "scorer-123" , "threshold" : 0.5 , "scorer_label" : "my-label" }
9831017 )
1018+ step = Step (type = "llm" , name = "test" , input = "prompt" )
9841019
9851020 with patch .object (GalileoLLMClient , "invoke" , new_callable = AsyncMock ) as mock_invoke :
9861021 mock_invoke .return_value = ScorerInvokeResponse (
9871022 scorer_label = "echoed-label" , score = 0.8 , status = "success"
9881023 )
989- result = await evaluator .evaluate ("hello" )
1024+ result = await evaluator .evaluate_with_extensions ("hello" , step , _EXTENSIONS )
9901025
9911026 assert result .metadata .get ("scorer_label" ) == "echoed-label"
9921027
@@ -996,6 +1031,8 @@ async def test_evaluator_scorer_version_id_in_metadata(monkeypatch):
9961031 """scorer_version_id is included in metadata when configured."""
9971032 for key , value in LLM_ENV .items ():
9981033 monkeypatch .setenv (key , value )
1034+ from agent_control_models import Step
1035+
9991036 from agent_control_evaluator_galileo .llm import LlmEvaluator
10001037 from agent_control_evaluator_galileo .llm .client import GalileoLLMClient , ScorerInvokeResponse
10011038
@@ -1006,10 +1043,11 @@ async def test_evaluator_scorer_version_id_in_metadata(monkeypatch):
10061043 "threshold" : 0.5 ,
10071044 }
10081045 )
1046+ step = Step (type = "llm" , name = "test" , input = "prompt" )
10091047
10101048 with patch .object (GalileoLLMClient , "invoke" , new_callable = AsyncMock ) as mock_invoke :
10111049 mock_invoke .return_value = ScorerInvokeResponse (score = 0.8 , status = "success" )
1012- result = await evaluator .evaluate ("hello" )
1050+ result = await evaluator .evaluate_with_extensions ("hello" , step , _EXTENSIONS )
10131051
10141052 assert result .metadata .get ("requested_scorer_version_id" ) == "ver-456"
10151053 assert mock_invoke .call_args .kwargs ["scorer_version_id" ] == "ver-456"
0 commit comments