001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2025-2026 The Enola <https://enola.dev> Authors 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package dev.enola.ai.dotagent; 019 020import com.google.adk.agents.BaseAgent; 021import com.google.adk.agents.LlmAgent; 022import com.google.adk.models.BaseLlm; 023import com.google.adk.tools.BaseToolset; 024import com.google.common.base.Strings; 025import com.google.common.collect.ImmutableList; 026import com.google.common.net.MediaType; 027import com.google.genai.types.Schema; 028 029import dev.enola.ai.adk.tool.ToolsetProvider; 030import dev.enola.ai.dotprompt.DotPromptLoader; 031import dev.enola.ai.iri.Provider; 032import dev.enola.common.function.MoreStreams; 033import dev.enola.common.io.iri.URIs; 034import dev.enola.common.io.object.ObjectWriter; 035import dev.enola.common.io.object.jackson.JsonObjectReaderWriter; 036import dev.enola.common.io.resource.ResourceProvider; 037 038import java.io.IOException; 039import java.net.URI; 040import java.util.ArrayList; 041import java.util.List; 042import java.util.Map; 043import java.util.stream.Stream; 044 045public class AgentsLoader { 046 047 // TODO Detect Agent name/id conflicts between agents in DIFFERENT resources 048 049 private final ToolsetProvider toolsProvider; 050 private final Provider<BaseLlm> llmProvider; 051 private final BaseLlm defaultLLM; 052 053 private final DotPromptLoader dotPromptLoader; 054 // TODO private final DotPrompt2LlmAgentConverter dotPrompt2LlmAgentConverter; 055 private final ObjectWriter objectWriter = new JsonObjectReaderWriter(); 056 057 private final AgentsModelLoader agentsModelLoader; 058 059 public AgentsLoader( 060 ResourceProvider resourceProvider, 061 URI defaultLLM, 062 Provider<BaseLlm> llmProvider, 063 ToolsetProvider toolsProvider) { 064 this.dotPromptLoader = new DotPromptLoader(resourceProvider, defaultLLM); 065 this.agentsModelLoader = new AgentsModelLoader(resourceProvider); 066 this.llmProvider = llmProvider; 067 this.defaultLLM = llmProvider.get(defaultLLM); 068 this.toolsProvider = toolsProvider; 069 } 070 071 public Iterable<BaseAgent> load(Stream<URI> uris) throws IOException { 072 var allLoadedAgents = new ArrayList<BaseAgent>(); 073 // TODO Load in parallel! (Req. using ConcurrentLinkedQueue instead of ArrayList.) 074 MoreStreams.forEach( 075 uris, 076 uri -> { 077 var agents = load(uri); 078 allLoadedAgents.addAll(agents); 079 }); 080 return ImmutableList.copyOf(allLoadedAgents); 081 } 082 083 private List<BaseAgent> load(URI uri) throws IOException { 084 if (URIs.hasExtension(uri, ".prompt", ".prompt.md")) { 085 var loadedDotPrompt = dotPromptLoader.load(uri); 086 throw new UnsupportedOperationException( 087 "https://github.com/google/adk-java/issues/288"); 088 } 089 090 var agentsModel = agentsModelLoader.load(uri); 091 var agents = ImmutableList.<BaseAgent>builderWithExpectedSize(agentsModel.agents.size()); 092 for (var agent : agentsModel.agents) { 093 // TODO Support SequentialAgent, ParallelAgent, LoopAgent 094 var agentBuilder = new LlmAgent.Builder(); 095 096 // TODO Share this code with DotPromptLoader / DotPrompt2LlmAgent !! 097 098 agentBuilder.name(agent.name); 099 // TODO Handle agent.variant ... 100 101 agentBuilder.description(agent.description); 102 agentBuilder.instruction(agent.instruction); 103 104 if (Strings.isNullOrEmpty(agent.model)) agentBuilder.model(defaultLLM); 105 else agentBuilder.model(llmProvider.get(agent.model, uri)); 106 107 // TODO Validate both input & output JSON Schemas!! 108 if (agent.input != null) agentBuilder.inputSchema(schema(agent.input.schema)); 109 if (agent.output != null) agentBuilder.outputSchema(schema(agent.output.schema)); 110 111 var tools = new ArrayList<BaseToolset>(agent.tools.size()); 112 for (var toolName : agent.tools) { 113 tools.add(toolsProvider.get(toolName, uri)); 114 } 115 agentBuilder.tools(tools); 116 117 agents.add(agentBuilder.build()); 118 } 119 120 return agents.build(); 121 } 122 123 private Schema schema(Map<String, Object> jsonSchemaMap) throws IOException { 124 var jsonText = objectWriter.write(jsonSchemaMap, MediaType.JSON_UTF_8).get(); 125 return Schema.fromJson(jsonText); 126 } 127}