@@ -909,3 +909,111 @@ def test_client_create_tracker_fails_on_invalid_json():
909909 result = ai_client .create_tracker (bad_token , context )
910910 assert not result .is_success ()
911911 assert "Invalid resumption token" in result .error
912+
913+
914+ # --- PR 10: LDAIMetrics enrichment + tracker integration ---
915+
916+
917+ def test_ldai_metrics_to_dict_includes_tool_calls_and_duration_ms ():
918+ metrics = LDAIMetrics (
919+ success = True ,
920+ usage = TokenUsage (total = 10 , input = 4 , output = 6 ),
921+ tool_calls = ["search" , "lookup" ],
922+ duration_ms = 123 ,
923+ )
924+ d = metrics .to_dict ()
925+ assert d ["success" ] is True
926+ assert d ["usage" ] == {"total" : 10 , "input" : 4 , "output" : 6 }
927+ assert d ["toolCalls" ] == ["search" , "lookup" ]
928+ assert d ["durationMs" ] == 123
929+
930+
931+ def test_ldai_metrics_to_dict_omits_optional_fields_when_none ():
932+ metrics = LDAIMetrics (success = False )
933+ d = metrics .to_dict ()
934+ assert d == {"success" : False }
935+
936+
937+ def test_track_metrics_of_uses_metrics_duration_ms_when_set (client : LDClient ):
938+ context = Context .create ("user-key" )
939+ tracker = LDAIConfigTracker (
940+ ld_client = client , run_id = "test-run-id" , config_key = "config-key" ,
941+ variation_key = "variation-key" , version = 3 , model_name = "m" ,
942+ provider_name = "p" , context = context ,
943+ )
944+
945+ def fn ():
946+ return "done"
947+
948+ def extract (_r ):
949+ return LDAIMetrics (success = True , duration_ms = 999 )
950+
951+ tracker .track_metrics_of (extract , fn )
952+ assert tracker .get_summary ().duration_ms == 999
953+
954+
955+ @pytest .mark .asyncio
956+ async def test_track_metrics_of_async_uses_metrics_duration_ms_when_set (client : LDClient ):
957+ context = Context .create ("user-key" )
958+ tracker = LDAIConfigTracker (
959+ ld_client = client , run_id = "test-run-id" , config_key = "config-key" ,
960+ variation_key = "variation-key" , version = 3 , model_name = "m" ,
961+ provider_name = "p" , context = context ,
962+ )
963+
964+ async def fn ():
965+ return "done"
966+
967+ def extract (_r ):
968+ return LDAIMetrics (success = True , duration_ms = 42 )
969+
970+ await tracker .track_metrics_of_async (extract , fn )
971+ assert tracker .get_summary ().duration_ms == 42
972+
973+
974+ def test_track_metrics_of_calls_track_tool_calls_when_present (client : LDClient ):
975+ context = Context .create ("user-key" )
976+ tracker = LDAIConfigTracker (
977+ ld_client = client , run_id = "test-run-id" , config_key = "config-key" ,
978+ variation_key = "variation-key" , version = 3 , model_name = "m" ,
979+ provider_name = "p" , context = context ,
980+ )
981+
982+ def fn ():
983+ return "done"
984+
985+ def extract (_r ):
986+ return LDAIMetrics (success = True , tool_calls = ["foo" , "bar" ])
987+
988+ tracker .track_metrics_of (extract , fn )
989+ summary = tracker .get_summary ()
990+ assert summary .tool_calls == ["foo" , "bar" ]
991+ # One $ld:ai:tool_call event per tool key.
992+ tool_call_events = [
993+ c for c in client .track .mock_calls # type: ignore
994+ if c .args [0 ] == "$ld:ai:tool_call"
995+ ]
996+ assert len (tool_call_events ) == 2
997+
998+
999+ def test_track_metrics_of_skips_track_tool_calls_when_absent (client : LDClient ):
1000+ context = Context .create ("user-key" )
1001+ tracker = LDAIConfigTracker (
1002+ ld_client = client , run_id = "test-run-id" , config_key = "config-key" ,
1003+ variation_key = "variation-key" , version = 3 , model_name = "m" ,
1004+ provider_name = "p" , context = context ,
1005+ )
1006+
1007+ def fn ():
1008+ return "done"
1009+
1010+ def extract (_r ):
1011+ return LDAIMetrics (success = True , usage = None )
1012+
1013+ tracker .track_metrics_of (extract , fn )
1014+ assert tracker .get_summary ().tool_calls is None
1015+ tool_call_events = [
1016+ c for c in client .track .mock_calls # type: ignore
1017+ if c .args [0 ] == "$ld:ai:tool_call"
1018+ ]
1019+ assert tool_call_events == []
0 commit comments