3434 from google .adk .a2a .utils .agent_card_builder import AgentCardBuilder
3535 from google .adk .a2a .utils .agent_to_a2a import to_a2a
3636 from google .adk .agents .base_agent import BaseAgent
37+ from google .adk .artifacts .base_artifact_service import BaseArtifactService
3738 from google .adk .artifacts .in_memory_artifact_service import InMemoryArtifactService
39+ from google .adk .auth .credential_service .base_credential_service import BaseCredentialService
3840 from google .adk .auth .credential_service .in_memory_credential_service import InMemoryCredentialService
41+ from google .adk .memory .base_memory_service import BaseMemoryService
3942 from google .adk .memory .in_memory_memory_service import InMemoryMemoryService
4043 from google .adk .runners import Runner
44+ from google .adk .sessions .base_session_service import BaseSessionService
4145 from google .adk .sessions .in_memory_session_service import InMemorySessionService
4246 from starlette .applications import Starlette
4347except ImportError as e :
@@ -869,3 +873,336 @@ def test_to_a2a_with_invalid_agent_card_file_path(
869873 # Act & Assert
870874 with pytest .raises (ValueError , match = "Failed to load agent card from" ):
871875 to_a2a (self .mock_agent , agent_card = "/invalid/path.json" )
876+
877+ @patch ("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor" )
878+ @patch ("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler" )
879+ @patch ("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore" )
880+ @patch ("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder" )
881+ @patch ("google.adk.a2a.utils.agent_to_a2a.Starlette" )
882+ @patch ("google.adk.a2a.utils.agent_to_a2a.Runner" )
883+ async def test_to_a2a_with_custom_services (
884+ self ,
885+ mock_runner_class ,
886+ mock_starlette_class ,
887+ mock_card_builder_class ,
888+ mock_task_store_class ,
889+ mock_request_handler_class ,
890+ mock_agent_executor_class ,
891+ ):
892+ """Test to_a2a with custom service implementations."""
893+ # Arrange
894+ mock_app = Mock (spec = Starlette )
895+ mock_starlette_class .return_value = mock_app
896+ mock_task_store = Mock (spec = InMemoryTaskStore )
897+ mock_task_store_class .return_value = mock_task_store
898+ mock_agent_executor = Mock (spec = A2aAgentExecutor )
899+ mock_agent_executor_class .return_value = mock_agent_executor
900+ mock_request_handler = Mock (spec = DefaultRequestHandler )
901+ mock_request_handler_class .return_value = mock_request_handler
902+ mock_card_builder = Mock (spec = AgentCardBuilder )
903+ mock_card_builder_class .return_value = mock_card_builder
904+ mock_runner = Mock (spec = Runner )
905+ mock_runner_class .return_value = mock_runner
906+
907+ # Create custom service mocks
908+ custom_artifact_service = Mock (spec = BaseArtifactService )
909+ custom_session_service = Mock (spec = BaseSessionService )
910+ custom_memory_service = Mock (spec = BaseMemoryService )
911+ custom_credential_service = Mock (spec = BaseCredentialService )
912+
913+ # Act
914+ result = to_a2a (
915+ self .mock_agent ,
916+ artifact_service = custom_artifact_service ,
917+ session_service = custom_session_service ,
918+ memory_service = custom_memory_service ,
919+ credential_service = custom_credential_service ,
920+ )
921+
922+ # Assert
923+ assert result == mock_app
924+ # Get the runner function that was passed to A2aAgentExecutor
925+ call_args = mock_agent_executor_class .call_args
926+ runner_func = call_args [1 ]["runner" ]
927+
928+ # Call the runner function to verify it creates Runner with custom services
929+ await runner_func ()
930+
931+ # Verify Runner was created with custom services
932+ mock_runner_class .assert_called_once_with (
933+ app_name = "test_agent" ,
934+ agent = self .mock_agent ,
935+ artifact_service = custom_artifact_service ,
936+ session_service = custom_session_service ,
937+ memory_service = custom_memory_service ,
938+ credential_service = custom_credential_service ,
939+ )
940+
941+ @patch ("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor" )
942+ @patch ("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler" )
943+ @patch ("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore" )
944+ @patch ("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder" )
945+ @patch ("google.adk.a2a.utils.agent_to_a2a.Starlette" )
946+ @patch ("google.adk.a2a.utils.agent_to_a2a.Runner" )
947+ async def test_to_a2a_with_none_services_uses_defaults (
948+ self ,
949+ mock_runner_class ,
950+ mock_starlette_class ,
951+ mock_card_builder_class ,
952+ mock_task_store_class ,
953+ mock_request_handler_class ,
954+ mock_agent_executor_class ,
955+ ):
956+ """Test to_a2a with None services uses default in-memory services."""
957+ # Arrange
958+ mock_app = Mock (spec = Starlette )
959+ mock_starlette_class .return_value = mock_app
960+ mock_task_store = Mock (spec = InMemoryTaskStore )
961+ mock_task_store_class .return_value = mock_task_store
962+ mock_agent_executor = Mock (spec = A2aAgentExecutor )
963+ mock_agent_executor_class .return_value = mock_agent_executor
964+ mock_request_handler = Mock (spec = DefaultRequestHandler )
965+ mock_request_handler_class .return_value = mock_request_handler
966+ mock_card_builder = Mock (spec = AgentCardBuilder )
967+ mock_card_builder_class .return_value = mock_card_builder
968+ mock_runner = Mock (spec = Runner )
969+ mock_runner_class .return_value = mock_runner
970+
971+ # Act
972+ result = to_a2a (
973+ self .mock_agent ,
974+ artifact_service = None ,
975+ session_service = None ,
976+ memory_service = None ,
977+ credential_service = None ,
978+ )
979+
980+ # Assert
981+ assert result == mock_app
982+ # Get the runner function that was passed to A2aAgentExecutor
983+ call_args = mock_agent_executor_class .call_args
984+ runner_func = call_args [1 ]["runner" ]
985+
986+ # Call the runner function to verify it creates Runner with default services
987+ await runner_func ()
988+
989+ # Verify Runner was created with default services
990+ mock_runner_class .assert_called_once ()
991+ call_args = mock_runner_class .call_args [1 ]
992+ assert call_args ["app_name" ] == "test_agent"
993+ assert call_args ["agent" ] == self .mock_agent
994+ # Verify the services are of the correct default types
995+ assert isinstance (call_args ["artifact_service" ], InMemoryArtifactService )
996+ assert isinstance (call_args ["session_service" ], InMemorySessionService )
997+ assert isinstance (call_args ["memory_service" ], InMemoryMemoryService )
998+ assert isinstance (call_args ["credential_service" ], InMemoryCredentialService )
999+
1000+ @patch ("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor" )
1001+ @patch ("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler" )
1002+ @patch ("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore" )
1003+ @patch ("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder" )
1004+ @patch ("google.adk.a2a.utils.agent_to_a2a.Starlette" )
1005+ @patch ("google.adk.a2a.utils.agent_to_a2a.Runner" )
1006+ async def test_to_a2a_with_mixed_services (
1007+ self ,
1008+ mock_runner_class ,
1009+ mock_starlette_class ,
1010+ mock_card_builder_class ,
1011+ mock_task_store_class ,
1012+ mock_request_handler_class ,
1013+ mock_agent_executor_class ,
1014+ ):
1015+ """Test to_a2a with mix of custom and default services."""
1016+ # Arrange
1017+ mock_app = Mock (spec = Starlette )
1018+ mock_starlette_class .return_value = mock_app
1019+ mock_task_store = Mock (spec = InMemoryTaskStore )
1020+ mock_task_store_class .return_value = mock_task_store
1021+ mock_agent_executor = Mock (spec = A2aAgentExecutor )
1022+ mock_agent_executor_class .return_value = mock_agent_executor
1023+ mock_request_handler = Mock (spec = DefaultRequestHandler )
1024+ mock_request_handler_class .return_value = mock_request_handler
1025+ mock_card_builder = Mock (spec = AgentCardBuilder )
1026+ mock_card_builder_class .return_value = mock_card_builder
1027+ mock_runner = Mock (spec = Runner )
1028+ mock_runner_class .return_value = mock_runner
1029+
1030+ # Create custom service mocks for some services
1031+ custom_artifact_service = Mock (spec = BaseArtifactService )
1032+ custom_memory_service = Mock (spec = BaseMemoryService )
1033+
1034+ # Act - only provide custom services for artifact and memory
1035+ result = to_a2a (
1036+ self .mock_agent ,
1037+ artifact_service = custom_artifact_service ,
1038+ memory_service = custom_memory_service ,
1039+ )
1040+
1041+ # Assert
1042+ assert result == mock_app
1043+ # Get the runner function that was passed to A2aAgentExecutor
1044+ call_args = mock_agent_executor_class .call_args
1045+ runner_func = call_args [1 ]["runner" ]
1046+
1047+ # Call the runner function to verify it creates Runner with mixed services
1048+ await runner_func ()
1049+
1050+ # Verify Runner was created with mixed services
1051+ mock_runner_class .assert_called_once ()
1052+ call_args = mock_runner_class .call_args [1 ]
1053+ assert call_args ["app_name" ] == "test_agent"
1054+ assert call_args ["agent" ] == self .mock_agent
1055+ # Verify custom services are used
1056+ assert call_args ["artifact_service" ] == custom_artifact_service
1057+ assert call_args ["memory_service" ] == custom_memory_service
1058+ # Verify default services are used for the others
1059+ assert isinstance (call_args ["session_service" ], InMemorySessionService )
1060+ assert isinstance (call_args ["credential_service" ], InMemoryCredentialService )
1061+
1062+ @patch ("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor" )
1063+ @patch ("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler" )
1064+ @patch ("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore" )
1065+ @patch ("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder" )
1066+ @patch ("google.adk.a2a.utils.agent_to_a2a.Starlette" )
1067+ @patch ("google.adk.a2a.utils.agent_to_a2a.Runner" )
1068+ async def test_to_a2a_services_parameter_order_independence (
1069+ self ,
1070+ mock_runner_class ,
1071+ mock_starlette_class ,
1072+ mock_card_builder_class ,
1073+ mock_task_store_class ,
1074+ mock_request_handler_class ,
1075+ mock_agent_executor_class ,
1076+ ):
1077+ """Test that services can be provided in any order and still work correctly."""
1078+ # Arrange
1079+ mock_app = Mock (spec = Starlette )
1080+ mock_starlette_class .return_value = mock_app
1081+ mock_task_store = Mock (spec = InMemoryTaskStore )
1082+ mock_task_store_class .return_value = mock_task_store
1083+ mock_agent_executor = Mock (spec = A2aAgentExecutor )
1084+ mock_agent_executor_class .return_value = mock_agent_executor
1085+ mock_request_handler = Mock (spec = DefaultRequestHandler )
1086+ mock_request_handler_class .return_value = mock_request_handler
1087+ mock_card_builder = Mock (spec = AgentCardBuilder )
1088+ mock_card_builder_class .return_value = mock_card_builder
1089+ mock_runner = Mock (spec = Runner )
1090+ mock_runner_class .return_value = mock_runner
1091+
1092+ # Create custom service mocks
1093+ custom_artifact_service = Mock (spec = BaseArtifactService )
1094+ custom_session_service = Mock (spec = BaseSessionService )
1095+ custom_memory_service = Mock (spec = BaseMemoryService )
1096+ custom_credential_service = Mock (spec = BaseCredentialService )
1097+
1098+ # Act - provide services in different order
1099+ result = to_a2a (
1100+ self .mock_agent ,
1101+ credential_service = custom_credential_service ,
1102+ artifact_service = custom_artifact_service ,
1103+ session_service = custom_session_service ,
1104+ memory_service = custom_memory_service ,
1105+ )
1106+
1107+ # Assert
1108+ assert result == mock_app
1109+ # Get the runner function that was passed to A2aAgentExecutor
1110+ call_args = mock_agent_executor_class .call_args
1111+ runner_func = call_args [1 ]["runner" ]
1112+
1113+ # Call the runner function to verify it creates Runner with correct services
1114+ await runner_func ()
1115+
1116+ # Verify Runner was created with all custom services regardless of order
1117+ mock_runner_class .assert_called_once ()
1118+ call_args = mock_runner_class .call_args [1 ]
1119+ assert call_args ["artifact_service" ] == custom_artifact_service
1120+ assert call_args ["session_service" ] == custom_session_service
1121+ assert call_args ["memory_service" ] == custom_memory_service
1122+ assert call_args ["credential_service" ] == custom_credential_service
1123+
1124+ @patch ("google.adk.a2a.utils.agent_to_a2a.A2aAgentExecutor" )
1125+ @patch ("google.adk.a2a.utils.agent_to_a2a.DefaultRequestHandler" )
1126+ @patch ("google.adk.a2a.utils.agent_to_a2a.InMemoryTaskStore" )
1127+ @patch ("google.adk.a2a.utils.agent_to_a2a.AgentCardBuilder" )
1128+ @patch ("google.adk.a2a.utils.agent_to_a2a.Starlette" )
1129+ @patch ("google.adk.a2a.utils.agent_to_a2a.Runner" )
1130+ async def test_to_a2a_with_agent_without_name_and_custom_services (
1131+ self ,
1132+ mock_runner_class ,
1133+ mock_starlette_class ,
1134+ mock_card_builder_class ,
1135+ mock_task_store_class ,
1136+ mock_request_handler_class ,
1137+ mock_agent_executor_class ,
1138+ ):
1139+ """Test to_a2a with agent that has no name and custom services."""
1140+ # Arrange
1141+ self .mock_agent .name = None
1142+ mock_app = Mock (spec = Starlette )
1143+ mock_starlette_class .return_value = mock_app
1144+ mock_task_store = Mock (spec = InMemoryTaskStore )
1145+ mock_task_store_class .return_value = mock_task_store
1146+ mock_agent_executor = Mock (spec = A2aAgentExecutor )
1147+ mock_agent_executor_class .return_value = mock_agent_executor
1148+ mock_request_handler = Mock (spec = DefaultRequestHandler )
1149+ mock_request_handler_class .return_value = mock_request_handler
1150+ mock_card_builder = Mock (spec = AgentCardBuilder )
1151+ mock_card_builder_class .return_value = mock_card_builder
1152+ mock_runner = Mock (spec = Runner )
1153+ mock_runner_class .return_value = mock_runner
1154+
1155+ # Create custom service mocks
1156+ custom_artifact_service = Mock (spec = BaseArtifactService )
1157+ custom_session_service = Mock (spec = BaseSessionService )
1158+
1159+ # Act
1160+ result = to_a2a (
1161+ self .mock_agent ,
1162+ artifact_service = custom_artifact_service ,
1163+ session_service = custom_session_service ,
1164+ )
1165+
1166+ # Assert
1167+ assert result == mock_app
1168+ # Get the runner function that was passed to A2aAgentExecutor
1169+ call_args = mock_agent_executor_class .call_args
1170+ runner_func = call_args [1 ]["runner" ]
1171+
1172+ # Call the runner function to verify it creates Runner correctly
1173+ await runner_func ()
1174+
1175+ # Verify Runner was created with default app_name and custom services
1176+ mock_runner_class .assert_called_once ()
1177+ call_args = mock_runner_class .call_args [1 ]
1178+ assert call_args ["app_name" ] == "adk_agent" # Default name when agent has no name
1179+ assert call_args ["agent" ] == self .mock_agent
1180+ assert call_args ["artifact_service" ] == custom_artifact_service
1181+ assert call_args ["session_service" ] == custom_session_service
1182+ # Verify default services are used for the others
1183+ assert isinstance (call_args ["memory_service" ], InMemoryMemoryService )
1184+ assert isinstance (call_args ["credential_service" ], InMemoryCredentialService )
1185+
1186+ def test_to_a2a_service_parameter_validation (self ):
1187+ """Test that to_a2a accepts valid service types without raising errors."""
1188+ # Arrange
1189+ custom_artifact_service = Mock (spec = BaseArtifactService )
1190+ custom_session_service = Mock (spec = BaseSessionService )
1191+ custom_memory_service = Mock (spec = BaseMemoryService )
1192+ custom_credential_service = Mock (spec = BaseCredentialService )
1193+
1194+ # Act & Assert - should not raise any errors
1195+ with patch ("google.adk.a2a.utils.agent_to_a2a.Starlette" ) as mock_starlette :
1196+ mock_app = Mock (spec = Starlette )
1197+ mock_starlette .return_value = mock_app
1198+
1199+ # This should not raise any validation errors
1200+ result = to_a2a (
1201+ self .mock_agent ,
1202+ artifact_service = custom_artifact_service ,
1203+ session_service = custom_session_service ,
1204+ memory_service = custom_memory_service ,
1205+ credential_service = custom_credential_service ,
1206+ )
1207+
1208+ assert result == mock_app
0 commit comments