3939import com .google .adk .agents .Callbacks .BeforeToolCallback ;
4040import com .google .adk .agents .Callbacks .BeforeToolCallbackBase ;
4141import com .google .adk .agents .Callbacks .BeforeToolCallbackSync ;
42+ import com .google .adk .agents .ConfigAgentUtils .ConfigurationException ;
4243import com .google .adk .events .Event ;
4344import com .google .adk .examples .BaseExampleProvider ;
4445import com .google .adk .examples .Example ;
4950import com .google .adk .models .LlmRegistry ;
5051import com .google .adk .models .Model ;
5152import com .google .adk .tools .BaseTool ;
53+ import com .google .adk .tools .BaseTool .ToolConfig ;
5254import com .google .adk .tools .BaseToolset ;
55+ import com .google .common .base .CaseFormat ;
5356import com .google .common .base .Preconditions ;
5457import com .google .common .collect .ImmutableList ;
5558import com .google .errorprone .annotations .CanIgnoreReturnValue ;
5962import io .reactivex .rxjava3 .core .Flowable ;
6063import io .reactivex .rxjava3 .core .Maybe ;
6164import io .reactivex .rxjava3 .core .Single ;
65+ import java .lang .reflect .Constructor ;
6266import java .util .ArrayList ;
6367import java .util .List ;
6468import java .util .Map ;
@@ -864,20 +868,20 @@ private Model resolveModelInternal() {
864868 * @param configAbsPath The absolute path to the agent config file. This is needed for resolving
865869 * relative paths for e.g. tools.
866870 * @return the configured LlmAgent
867- * @throws ConfigAgentUtils. ConfigurationException if the configuration is invalid
871+ * @throws ConfigurationException if the configuration is invalid
868872 * <p>TODO: Config agent features are not yet ready for public use.
869873 */
870874 public static LlmAgent fromConfig (LlmAgentConfig config , String configAbsPath )
871- throws ConfigAgentUtils . ConfigurationException {
875+ throws ConfigurationException {
872876 logger .debug ("Creating LlmAgent from config: {}" , config .name ());
873877
874878 // Validate required fields
875879 if (config .name () == null || config .name ().trim ().isEmpty ()) {
876- throw new ConfigAgentUtils . ConfigurationException ("Agent name is required" );
880+ throw new ConfigurationException ("Agent name is required" );
877881 }
878882
879883 if (config .instruction () == null || config .instruction ().trim ().isEmpty ()) {
880- throw new ConfigAgentUtils . ConfigurationException ("Agent instruction is required" );
884+ throw new ConfigurationException ("Agent instruction is required" );
881885 }
882886
883887 // Create builder with required fields
@@ -891,6 +895,14 @@ public static LlmAgent fromConfig(LlmAgentConfig config, String configAbsPath)
891895 builder .model (config .model ());
892896 }
893897
898+ try {
899+ if (config .tools () != null ) {
900+ builder .tools (resolveTools (config .tools (), configAbsPath ));
901+ }
902+ } catch (ConfigurationException e ) {
903+ throw new ConfigurationException ("Error resolving tools for agent " + config .name (), e );
904+ }
905+
894906 // Set optional transfer configuration
895907 if (config .disallowTransferToParent () != null ) {
896908 builder .disallowTransferToParent (config .disallowTransferToParent ());
@@ -911,4 +923,116 @@ public static LlmAgent fromConfig(LlmAgentConfig config, String configAbsPath)
911923
912924 return agent ;
913925 }
926+
927+ private static ImmutableList <BaseTool > resolveTools (
928+ List <ToolConfig > toolConfigs , String configAbsPath ) throws ConfigurationException {
929+
930+ if (toolConfigs == null || toolConfigs .isEmpty ()) {
931+ return ImmutableList .of ();
932+ }
933+
934+ List <BaseTool > resolvedTools = new ArrayList <>();
935+
936+ for (ToolConfig toolConfig : toolConfigs ) {
937+ try {
938+ String toolName = toolConfig .name ();
939+ if (toolName == null || toolName .trim ().isEmpty ()) {
940+ throw new ConfigurationException ("Tool name cannot be empty" );
941+ }
942+
943+ toolName = toolName .trim ();
944+ BaseTool tool ;
945+
946+ if (!toolName .contains ("." )) {
947+ tool = resolveBuiltInTool (toolName , toolConfig );
948+ } else {
949+ // TODO: Support user-defined tools
950+ logger .debug ("configAbsPath is: {}" , configAbsPath );
951+ throw new ConfigurationException ("User-defined tools are not yet supported" );
952+ }
953+
954+ resolvedTools .add (tool );
955+ logger .debug ("Successfully resolved tool: {}" , toolConfig .name ());
956+ } catch (Exception e ) {
957+ String errorMsg = "Failed to resolve tool: " + toolConfig .name ();
958+ logger .error (errorMsg , e );
959+ throw new ConfigurationException (errorMsg , e );
960+ }
961+ }
962+
963+ return ImmutableList .copyOf (resolvedTools );
964+ }
965+
966+ private static BaseTool resolveBuiltInTool (String toolName , ToolConfig toolConfig )
967+ throws ConfigurationException {
968+ try {
969+ logger .debug ("Resolving built-in tool: {}" , toolName );
970+ // TODO: Handle built-in tool name end with Tool while config yaml file does not.
971+ // e.g.google_search in config yaml file and GoogleSearchTool in tool class name.
972+ String pascalCaseToolName = CaseFormat .LOWER_UNDERSCORE .to (CaseFormat .UPPER_CAMEL , toolName );
973+ String className = "com.google.adk.tools." + pascalCaseToolName ;
974+ Class <?> toolClass ;
975+ try {
976+ toolClass = Class .forName (className );
977+ logger .debug ("Successfully loaded tool class: {}" , className );
978+ } catch (ClassNotFoundException e ) {
979+ String fallbackClassName = "com.google.adk.tools." + toolName ;
980+ try {
981+ toolClass = Class .forName (fallbackClassName );
982+ } catch (ClassNotFoundException e2 ) {
983+ throw new ConfigurationException (
984+ "Built-in tool not found: "
985+ + toolName
986+ + ". Expected class: "
987+ + className
988+ + " or "
989+ + fallbackClassName ,
990+ e2 );
991+ }
992+ }
993+
994+ if (!BaseTool .class .isAssignableFrom (toolClass )) {
995+ throw new ConfigurationException (
996+ "Built-in tool class " + toolClass .getName () + " does not extend BaseTool" );
997+ }
998+
999+ @ SuppressWarnings ("unchecked" )
1000+ Class <? extends BaseTool > baseToolClass = (Class <? extends BaseTool >) toolClass ;
1001+
1002+ BaseTool tool = createToolInstance (baseToolClass , toolConfig );
1003+ logger .info (
1004+ "Successfully created built-in tool: {} (class: {})" , toolName , toolClass .getName ());
1005+
1006+ return tool ;
1007+
1008+ } catch (Exception e ) {
1009+ logger .error ("Failed to create built-in tool: {}" , toolName , e );
1010+ throw new ConfigurationException ("Failed to create built-in tool: " + toolName , e );
1011+ }
1012+ }
1013+
1014+ private static BaseTool createToolInstance (
1015+ Class <? extends BaseTool > toolClass , ToolConfig toolConfig )
1016+ throws ConfigAgentUtils .ConfigurationException {
1017+
1018+ try {
1019+ // TODO:implement constructor with ToolArgsConfig
1020+ logger .debug ("ToolConfig is: {}" , toolConfig );
1021+
1022+ // Try default constructor
1023+ try {
1024+ Constructor <? extends BaseTool > constructor = toolClass .getConstructor ();
1025+ return constructor .newInstance ();
1026+ } catch (NoSuchMethodException e ) {
1027+ // Continue
1028+ }
1029+
1030+ throw new ConfigAgentUtils .ConfigurationException (
1031+ "No suitable constructor found for tool class: " + toolClass .getName ());
1032+
1033+ } catch (Exception e ) {
1034+ throw new ConfigAgentUtils .ConfigurationException (
1035+ "Failed to instantiate tool class: " + toolClass .getName (), e );
1036+ }
1037+ }
9141038}
0 commit comments