From d360227ad24722d08fe5bee54e92e62b9647e0ce Mon Sep 17 00:00:00 2001 From: Aref Behboudi Date: Mon, 6 Apr 2026 12:30:08 +0300 Subject: [PATCH 1/9] Multi-Agent Runtime --- .../java/ai/javaclaw/JavaClawApplication.java | 9 +- .../ai/javaclaw/api/AgentsController.java | 54 +++++ .../java/ai/javaclaw/chat/ChatChannel.java | 30 ++- .../main/java/ai/javaclaw/chat/ChatHtml.java | 23 +- .../chat/ws/ChatWebSocketHandler.java | 51 ++++- .../onboarding/steps/S2_ProviderStep.java | 79 ++++++- .../onboarding/steps/S3_CredentialsStep.java | 101 +++++++-- .../onboarding/steps/S4_AgentMdStep.java | 56 ++++- app/src/main/resources/application.yaml | 14 +- .../main/resources/templates/agents.html.peb | 127 +++++++++++ .../main/resources/templates/chat.html.peb | 10 +- .../onboarding/steps/S2-provider.html.peb | 10 +- .../onboarding/steps/S3-credentials.html.peb | 12 +- .../ai/javaclaw/api/AgentsControllerTest.java | 44 ++++ .../api/OnboardingControllerTest.java | 6 +- .../ai/javaclaw/chat/ChatChannelTest.java | 62 +++-- .../chat/ws/ChatWebSocketHandlerTest.java | 25 +- .../onboarding/steps/S4_AgentMdStepTest.java | 87 +++++++ app/workspace/app.mv.db | Bin 53248 -> 0 bytes base/build.gradle | 1 + .../ai/javaclaw/JavaClawConfiguration.java | 4 +- .../main/java/ai/javaclaw/agent/Agent.java | 12 +- .../java/ai/javaclaw/agent/DefaultAgent.java | 58 ++++- .../FileSystemChatMemoryRepository.java | 72 +++++- .../agents/AgentChatClientFactory.java | 214 ++++++++++++++++++ .../javaclaw/agents/AgentConversationId.java | 34 +++ .../ai/javaclaw/agents/AgentRegistry.java | 134 +++++++++++ .../agents/AgentWorkspaceResolver.java | 91 ++++++++ .../ai/javaclaw/agents/ConfiguredAgent.java | 14 ++ .../configuration/ConfigurationManager.java | 24 ++ .../onboarding/AgentOnboardingProvider.java | 8 + .../ai/javaclaw/providers/AgentProvider.java | 2 - .../FileSystemChatMemoryRepositoryTest.java | 10 +- .../models/AgentChatClientFactoryTest.java | 83 +++++++ .../ai/javaclaw/models/ModelRegistryTest.java | 81 +++++++ .../models/ModelWorkspaceResolverTest.java | 42 ++++ .../openai/OpenAIAgentOnboardingProvider.java | 5 + 37 files changed, 1569 insertions(+), 120 deletions(-) create mode 100644 app/src/main/java/ai/javaclaw/api/AgentsController.java create mode 100644 app/src/main/resources/templates/agents.html.peb create mode 100644 app/src/test/java/ai/javaclaw/api/AgentsControllerTest.java create mode 100644 app/src/test/java/ai/javaclaw/onboarding/steps/S4_AgentMdStepTest.java delete mode 100644 app/workspace/app.mv.db create mode 100644 base/src/main/java/ai/javaclaw/agents/AgentChatClientFactory.java create mode 100644 base/src/main/java/ai/javaclaw/agents/AgentConversationId.java create mode 100644 base/src/main/java/ai/javaclaw/agents/AgentRegistry.java create mode 100644 base/src/main/java/ai/javaclaw/agents/AgentWorkspaceResolver.java create mode 100644 base/src/main/java/ai/javaclaw/agents/ConfiguredAgent.java create mode 100644 base/src/test/java/ai/javaclaw/models/AgentChatClientFactoryTest.java create mode 100644 base/src/test/java/ai/javaclaw/models/ModelRegistryTest.java create mode 100644 base/src/test/java/ai/javaclaw/models/ModelWorkspaceResolverTest.java diff --git a/app/src/main/java/ai/javaclaw/JavaClawApplication.java b/app/src/main/java/ai/javaclaw/JavaClawApplication.java index e396ce6c..0f80245a 100644 --- a/app/src/main/java/ai/javaclaw/JavaClawApplication.java +++ b/app/src/main/java/ai/javaclaw/JavaClawApplication.java @@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.DefaultApplicationArguments; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; @@ -44,12 +45,16 @@ public void run(ApplicationArguments args) throws Exception { @EventListener public void on(ConfigurationChangedEvent configurationChangedEvent) { - ApplicationArguments args = applicationContext.getBean(ApplicationArguments.class); + Thread thread = new Thread(() -> { try { + ApplicationArguments args = new DefaultApplicationArguments(); + if(applicationContext != null){ + args = applicationContext.getBean(ApplicationArguments.class); + applicationContext.close(); + } Thread.sleep(2000); - applicationContext.close(); applicationContext = SpringApplication.run(JavaClawApplication.class, args.getSourceArgs()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/app/src/main/java/ai/javaclaw/api/AgentsController.java b/app/src/main/java/ai/javaclaw/api/AgentsController.java new file mode 100644 index 00000000..b4dc4035 --- /dev/null +++ b/app/src/main/java/ai/javaclaw/api/AgentsController.java @@ -0,0 +1,54 @@ +package ai.javaclaw.api; + +import ai.javaclaw.agents.AgentRegistry; +import ai.javaclaw.agents.AgentWorkspaceResolver; +import ai.javaclaw.agents.ConfiguredAgent; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; + +import java.nio.file.Path; +import java.util.List; + +@Controller +public class AgentsController { + + private final AgentRegistry agentRegistry; + private final AgentWorkspaceResolver agentWorkspaceResolver; + + public AgentsController(AgentRegistry agentRegistry, AgentWorkspaceResolver agentWorkspaceResolver) { + this.agentRegistry = agentRegistry; + this.agentWorkspaceResolver = agentWorkspaceResolver; + } + + @GetMapping("/agents") + public String agents(Model model) { + List agents = agentRegistry.getAgents().stream() + .map(configuredAgent -> new AgentView( + configuredAgent.id(), + configuredAgent.provider(), + configuredAgent.model(), + resolveWorkspace(configuredAgent), + configuredAgent.id().equals(agentRegistry.getDefaultAgentId()) + )) + .toList(); + + model.addAttribute("agents", agents); + model.addAttribute("hasAgents", !agents.isEmpty()); + return "agents"; + } + + private String resolveWorkspace(ConfiguredAgent configuredAgent) { + Path workspacePath = agentWorkspaceResolver.resolveWorkspacePath(configuredAgent.workspacePath(), configuredAgent.id()); + return workspacePath.toString(); + } + + public record AgentView( + String id, + String provider, + String model, + String workspace, + boolean isDefault + ) { + } +} diff --git a/app/src/main/java/ai/javaclaw/chat/ChatChannel.java b/app/src/main/java/ai/javaclaw/chat/ChatChannel.java index 2050c312..2c2f539f 100644 --- a/app/src/main/java/ai/javaclaw/chat/ChatChannel.java +++ b/app/src/main/java/ai/javaclaw/chat/ChatChannel.java @@ -1,6 +1,8 @@ package ai.javaclaw.chat; import ai.javaclaw.agent.Agent; +import ai.javaclaw.agents.AgentConversationId; +import ai.javaclaw.agents.AgentRegistry; import ai.javaclaw.channels.Channel; import ai.javaclaw.channels.ChannelMessageReceivedEvent; import ai.javaclaw.channels.ChannelRegistry; @@ -36,13 +38,15 @@ public class ChatChannel implements Channel { private static final Logger log = LoggerFactory.getLogger(ChatChannel.class); private final Agent agent; + private final AgentRegistry agentRegistry; private final ChannelRegistry channelRegistry; private final ChatMemoryRepository chatMemoryRepository; private final ConcurrentLinkedQueue pendingMessages = new ConcurrentLinkedQueue<>(); private final AtomicReference wsSession = new AtomicReference<>(); - public ChatChannel(Agent agent, ChannelRegistry channelRegistry, ChatMemoryRepository chatMemoryRepository) { + public ChatChannel(Agent agent, AgentRegistry agentRegistry, ChannelRegistry channelRegistry, ChatMemoryRepository chatMemoryRepository) { this.agent = agent; + this.agentRegistry = agentRegistry; this.channelRegistry = channelRegistry; this.chatMemoryRepository = chatMemoryRepository; channelRegistry.registerChannel(this); @@ -96,10 +100,24 @@ public void sendMessage(String message) { /** * Returns all known conversation IDs, always with "web" first. */ - public List conversationIds() { + public List agentIds() { + List ids = agentRegistry.getAgents().stream().map(ai.javaclaw.agents.ConfiguredAgent::id).toList(); + if (!ids.isEmpty()) { + return ids; + } + return List.of(agentRegistry.getDefaultAgentId()); + } + + public String defaultAgentId() { + return agentRegistry.getDefaultAgentId(); + } + + public List conversationIds(String agentId) { List result = new ArrayList<>(); result.add("web"); chatMemoryRepository.findConversationIds().stream() + .filter(id -> agentId.equals(AgentConversationId.agentId(id))) + .map(AgentConversationId::rawConversationId) .filter(id -> !id.equals("web")) .forEach(result::add); return result; @@ -109,8 +127,8 @@ public List conversationIds() { * Loads conversation history for the given conversationId as HTML bubbles. * Returns a single welcome bubble if no history exists yet. */ - public List loadHistoryAsHtml(String conversationId) { - List history = chatMemoryRepository.findByConversationId(conversationId); + public List loadHistoryAsHtml(String agentId, String conversationId) { + List history = chatMemoryRepository.findByConversationId(AgentConversationId.scoped(agentId, conversationId)); if (history.isEmpty()) { return List.of(ChatHtml.agentBubble("Hi! I'm your JavaClaw assistant. How can I help you today?")); } @@ -125,9 +143,9 @@ public List loadHistoryAsHtml(String conversationId) { /** * Handles a chat message from the web UI for the given conversationId. */ - public String chat(String conversationId, String message) { + public String chat(String agentId, String conversationId, String message) { channelRegistry.publishMessageReceivedEvent(new ChannelMessageReceivedEvent(getName(), message)); - return agent.respondTo(conversationId, message); + return agent.respondTo(agentId, conversationId, message); } private static String buildBackgroundMessageHtml(String text) { diff --git a/app/src/main/java/ai/javaclaw/chat/ChatHtml.java b/app/src/main/java/ai/javaclaw/chat/ChatHtml.java index c6416c80..b4a21210 100644 --- a/app/src/main/java/ai/javaclaw/chat/ChatHtml.java +++ b/app/src/main/java/ai/javaclaw/chat/ChatHtml.java @@ -34,11 +34,11 @@ public static String typingDots() { """; } - public static String chatInputArea(String conversationId) { + public static String chatInputArea(String agentId, String conversationId) { if ("web".equals(conversationId)) { return """
+ hx-vals='js:{"type": "userMessage", "agentId": document.getElementById("agent-select") ? document.getElementById("agent-select").value : "%s", "conversationId": document.getElementById("channel-select") ? document.getElementById("channel-select").value : "web"}'>
-
-
- -
-
-
+ {% autoescape false %}{{ inputAreaHtml }}{% endautoescape %} diff --git a/app/src/test/java/ai/javaclaw/api/AgentCreateControllerTest.java b/app/src/test/java/ai/javaclaw/api/AgentCreateControllerTest.java new file mode 100644 index 00000000..7c67db87 --- /dev/null +++ b/app/src/test/java/ai/javaclaw/api/AgentCreateControllerTest.java @@ -0,0 +1,52 @@ +package ai.javaclaw.api; + +import ai.javaclaw.agent.AgentRegistry; +import ai.javaclaw.agent.AgentWorkspaceResolver; +import ai.javaclaw.configuration.ConfigurationManager; +import ai.javaclaw.onboarding.AgentOnboardingProvider; +import ai.javaclaw.onboarding.AgentOnboardingProviders; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.List; +import java.util.Map; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(AgentCreateController.class) +class AgentCreateControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockitoBean + private AgentRegistry agentRegistry; + + @MockitoBean + private AgentOnboardingProviders agentOnboardingProviders; + + @MockitoBean + private ConfigurationManager configurationManager; + + @MockitoBean + private AgentWorkspaceResolver agentWorkspaceResolver; + + @Test + void newAgentPageRenders() throws Exception { + AgentOnboardingProvider provider = org.mockito.Mockito.mock(AgentOnboardingProvider.class); + when(provider.getId()).thenReturn("openai"); + when(provider.getLabel()).thenReturn("OpenAI"); + when(agentOnboardingProviders.getAll()).thenReturn(List.of(provider)); + when(configurationManager.readApplicationYaml()).thenReturn(Map.of()); + + mockMvc.perform(get("/agents/new")) + .andExpect(status().isOk()) + .andExpect(content().string(org.hamcrest.Matchers.containsString("Add Agent"))) + .andExpect(content().string(org.hamcrest.Matchers.containsString("OpenAI"))); + } +} diff --git a/app/src/test/java/ai/javaclaw/api/AgentEditControllerTest.java b/app/src/test/java/ai/javaclaw/api/AgentEditControllerTest.java new file mode 100644 index 00000000..8c50043d --- /dev/null +++ b/app/src/test/java/ai/javaclaw/api/AgentEditControllerTest.java @@ -0,0 +1,59 @@ +package ai.javaclaw.api; + +import ai.javaclaw.agent.AgentRegistry; +import ai.javaclaw.agent.AgentWorkspaceResolver; +import ai.javaclaw.agent.ConfiguredAgent; +import ai.javaclaw.configuration.ConfigurationManager; +import ai.javaclaw.onboarding.AgentOnboardingProvider; +import ai.javaclaw.onboarding.AgentOnboardingProviders; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.List; +import java.util.Optional; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(AgentCreateController.class) +class AgentEditControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockitoBean + private AgentRegistry agentRegistry; + + @MockitoBean + private AgentOnboardingProviders agentOnboardingProviders; + + @MockitoBean + private ConfigurationManager configurationManager; + + @MockitoBean + private AgentWorkspaceResolver agentWorkspaceResolver; + + @Test + void editAgentPageRendersWithoutApiKeyPrefill() throws Exception { + ConfiguredAgent configured = new ConfiguredAgent("openai-main", "openai", "gpt-5.4", "secret", "https://api.example.com", "/tmp/ws"); + when(agentRegistry.findAgent("openai-main")).thenReturn(Optional.of(configured)); + when(agentRegistry.getDefaultAgentId()).thenReturn("openai-main"); + + AgentOnboardingProvider provider = org.mockito.Mockito.mock(AgentOnboardingProvider.class); + when(provider.getId()).thenReturn("openai"); + when(provider.getLabel()).thenReturn("OpenAI"); + when(agentOnboardingProviders.getAll()).thenReturn(List.of(provider)); + + mockMvc.perform(get("/agents/openai-main/edit")) + .andExpect(status().isOk()) + .andExpect(content().string(org.hamcrest.Matchers.containsString("Edit Agent"))) + .andExpect(content().string(org.hamcrest.Matchers.containsString("Save Changes"))) + .andExpect(content().string(org.hamcrest.Matchers.containsString("openai-main"))); + } +} + diff --git a/app/src/test/java/ai/javaclaw/api/AgentsControllerTest.java b/app/src/test/java/ai/javaclaw/api/AgentsControllerTest.java index 19dbe863..f7dfdb8a 100644 --- a/app/src/test/java/ai/javaclaw/api/AgentsControllerTest.java +++ b/app/src/test/java/ai/javaclaw/api/AgentsControllerTest.java @@ -1,8 +1,8 @@ package ai.javaclaw.api; -import ai.javaclaw.agents.AgentRegistry; -import ai.javaclaw.agents.AgentWorkspaceResolver; -import ai.javaclaw.agents.ConfiguredAgent; +import ai.javaclaw.agent.AgentRegistry; +import ai.javaclaw.agent.AgentWorkspaceResolver; +import ai.javaclaw.agent.ConfiguredAgent; import org.junit.jupiter.api.Test; import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; diff --git a/app/src/test/java/ai/javaclaw/api/OnboardingControllerTest.java b/app/src/test/java/ai/javaclaw/api/OnboardingControllerTest.java index 6e40edaf..2da9ddd3 100644 --- a/app/src/test/java/ai/javaclaw/api/OnboardingControllerTest.java +++ b/app/src/test/java/ai/javaclaw/api/OnboardingControllerTest.java @@ -1,7 +1,7 @@ package ai.javaclaw.api; import ai.javaclaw.configuration.ConfigurationManager; -import ai.javaclaw.agents.AgentWorkspaceResolver; +import ai.javaclaw.agent.AgentWorkspaceResolver; import ai.javaclaw.onboarding.AgentOnboardingProviders; import ai.javaclaw.onboarding.api.OnboardingController; import ai.javaclaw.onboarding.steps.S1_WelcomeStep; diff --git a/app/src/test/java/ai/javaclaw/chat/ChatChannelTest.java b/app/src/test/java/ai/javaclaw/chat/ChatChannelTest.java index 3d1ad408..8c58e092 100644 --- a/app/src/test/java/ai/javaclaw/chat/ChatChannelTest.java +++ b/app/src/test/java/ai/javaclaw/chat/ChatChannelTest.java @@ -1,9 +1,9 @@ package ai.javaclaw.chat; import ai.javaclaw.agent.Agent; -import ai.javaclaw.agents.AgentConversationId; -import ai.javaclaw.agents.AgentRegistry; -import ai.javaclaw.agents.ConfiguredAgent; +import ai.javaclaw.agent.AgentConversationId; +import ai.javaclaw.agent.AgentRegistry; +import ai.javaclaw.agent.ConfiguredAgent; import ai.javaclaw.channels.ChannelRegistry; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/app/src/test/java/ai/javaclaw/onboarding/steps/S4_AgentMdStepTest.java b/app/src/test/java/ai/javaclaw/onboarding/steps/S4_AgentMdStepTest.java index 8cf9f9a7..ad3b3f99 100644 --- a/app/src/test/java/ai/javaclaw/onboarding/steps/S4_AgentMdStepTest.java +++ b/app/src/test/java/ai/javaclaw/onboarding/steps/S4_AgentMdStepTest.java @@ -1,6 +1,6 @@ package ai.javaclaw.onboarding.steps; -import ai.javaclaw.agents.AgentWorkspaceResolver; +import ai.javaclaw.agent.AgentWorkspaceResolver; import ai.javaclaw.onboarding.AgentOnboardingProvider; import ai.javaclaw.onboarding.AgentOnboardingProviders; import org.junit.jupiter.api.Test; diff --git a/base/src/main/java/ai/javaclaw/agents/AgentChatClientFactory.java b/base/src/main/java/ai/javaclaw/agent/AgentChatClientFactory.java similarity index 99% rename from base/src/main/java/ai/javaclaw/agents/AgentChatClientFactory.java rename to base/src/main/java/ai/javaclaw/agent/AgentChatClientFactory.java index 00c35d4a..539f5e9b 100644 --- a/base/src/main/java/ai/javaclaw/agents/AgentChatClientFactory.java +++ b/base/src/main/java/ai/javaclaw/agent/AgentChatClientFactory.java @@ -1,4 +1,4 @@ -package ai.javaclaw.agents; +package ai.javaclaw.agent; import ai.javaclaw.configuration.ConfigurationChangedEvent; import ai.javaclaw.configuration.ConfigurationManager; diff --git a/base/src/main/java/ai/javaclaw/agents/AgentChatModelFactory.java b/base/src/main/java/ai/javaclaw/agent/AgentChatModelFactory.java similarity index 95% rename from base/src/main/java/ai/javaclaw/agents/AgentChatModelFactory.java rename to base/src/main/java/ai/javaclaw/agent/AgentChatModelFactory.java index 9536c122..03d5a10b 100644 --- a/base/src/main/java/ai/javaclaw/agents/AgentChatModelFactory.java +++ b/base/src/main/java/ai/javaclaw/agent/AgentChatModelFactory.java @@ -1,4 +1,4 @@ -package ai.javaclaw.agents; +package ai.javaclaw.agent; import org.springframework.ai.chat.model.ChatModel; diff --git a/base/src/main/java/ai/javaclaw/agents/AgentConversationId.java b/base/src/main/java/ai/javaclaw/agent/AgentConversationId.java similarity index 97% rename from base/src/main/java/ai/javaclaw/agents/AgentConversationId.java rename to base/src/main/java/ai/javaclaw/agent/AgentConversationId.java index 4233f858..24f176ad 100644 --- a/base/src/main/java/ai/javaclaw/agents/AgentConversationId.java +++ b/base/src/main/java/ai/javaclaw/agent/AgentConversationId.java @@ -1,4 +1,4 @@ -package ai.javaclaw.agents; +package ai.javaclaw.agent; public final class AgentConversationId { diff --git a/base/src/main/java/ai/javaclaw/agents/AgentRegistry.java b/base/src/main/java/ai/javaclaw/agent/AgentRegistry.java similarity index 99% rename from base/src/main/java/ai/javaclaw/agents/AgentRegistry.java rename to base/src/main/java/ai/javaclaw/agent/AgentRegistry.java index c07d51a7..5157c256 100644 --- a/base/src/main/java/ai/javaclaw/agents/AgentRegistry.java +++ b/base/src/main/java/ai/javaclaw/agent/AgentRegistry.java @@ -1,4 +1,4 @@ -package ai.javaclaw.agents; +package ai.javaclaw.agent; import ai.javaclaw.configuration.ConfigurationChangedEvent; import ai.javaclaw.configuration.ConfigurationManager; diff --git a/base/src/main/java/ai/javaclaw/agents/AgentWorkspaceResolver.java b/base/src/main/java/ai/javaclaw/agent/AgentWorkspaceResolver.java similarity index 99% rename from base/src/main/java/ai/javaclaw/agents/AgentWorkspaceResolver.java rename to base/src/main/java/ai/javaclaw/agent/AgentWorkspaceResolver.java index 130d4b97..84ff2d6e 100644 --- a/base/src/main/java/ai/javaclaw/agents/AgentWorkspaceResolver.java +++ b/base/src/main/java/ai/javaclaw/agent/AgentWorkspaceResolver.java @@ -1,4 +1,4 @@ -package ai.javaclaw.agents; +package ai.javaclaw.agent; import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; diff --git a/base/src/main/java/ai/javaclaw/agents/ConfiguredAgent.java b/base/src/main/java/ai/javaclaw/agent/ConfiguredAgent.java similarity index 86% rename from base/src/main/java/ai/javaclaw/agents/ConfiguredAgent.java rename to base/src/main/java/ai/javaclaw/agent/ConfiguredAgent.java index 4e7a1f51..d08663af 100644 --- a/base/src/main/java/ai/javaclaw/agents/ConfiguredAgent.java +++ b/base/src/main/java/ai/javaclaw/agent/ConfiguredAgent.java @@ -1,4 +1,4 @@ -package ai.javaclaw.agents; +package ai.javaclaw.agent; public record ConfiguredAgent( String id, diff --git a/base/src/main/java/ai/javaclaw/agent/DefaultAgent.java b/base/src/main/java/ai/javaclaw/agent/DefaultAgent.java index b81322b2..4c444bd2 100644 --- a/base/src/main/java/ai/javaclaw/agent/DefaultAgent.java +++ b/base/src/main/java/ai/javaclaw/agent/DefaultAgent.java @@ -1,14 +1,13 @@ package ai.javaclaw.agent; -import ai.javaclaw.agents.AgentChatClientFactory; -import ai.javaclaw.agents.AgentConversationId; -import ai.javaclaw.agents.AgentRegistry; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.chat.model.ChatModel; import org.springframework.beans.factory.ObjectProvider; import org.springframework.stereotype.Component; +import java.util.Optional; + @Component public class DefaultAgent implements Agent { @@ -52,13 +51,13 @@ public T prompt(String agentId, String conversationId, String input, Class resolveAgent(String agentId) { + private Optional resolveAgent(String agentId) { return agentRegistry.findAgent(agentId) - .or(() -> agentRegistry.getDefaultAgent()); + .or(agentRegistry::getDefaultAgent); } private ChatClient fallbackChatClient() { diff --git a/base/src/main/java/ai/javaclaw/agent/memory/FileSystemChatMemoryRepository.java b/base/src/main/java/ai/javaclaw/agent/memory/FileSystemChatMemoryRepository.java index 64465486..15d60c9e 100644 --- a/base/src/main/java/ai/javaclaw/agent/memory/FileSystemChatMemoryRepository.java +++ b/base/src/main/java/ai/javaclaw/agent/memory/FileSystemChatMemoryRepository.java @@ -1,8 +1,8 @@ package ai.javaclaw.agent.memory; -import ai.javaclaw.agents.AgentRegistry; -import ai.javaclaw.agents.AgentConversationId; -import ai.javaclaw.agents.AgentWorkspaceResolver; +import ai.javaclaw.agent.AgentRegistry; +import ai.javaclaw.agent.AgentConversationId; +import ai.javaclaw.agent.AgentWorkspaceResolver; import ai.javaclaw.files.YamlDocument; import ai.javaclaw.files.YamlParser; import org.springframework.ai.chat.memory.AppendableChatMemoryRepository; diff --git a/base/src/test/java/ai/javaclaw/models/AgentChatClientFactoryTest.java b/base/src/test/java/ai/javaclaw/models/AgentChatClientFactoryTest.java index ffb2e21c..08005041 100644 --- a/base/src/test/java/ai/javaclaw/models/AgentChatClientFactoryTest.java +++ b/base/src/test/java/ai/javaclaw/models/AgentChatClientFactoryTest.java @@ -1,8 +1,8 @@ package ai.javaclaw.models; -import ai.javaclaw.agents.AgentChatClientFactory; -import ai.javaclaw.agents.AgentChatModelFactory; -import ai.javaclaw.agents.AgentWorkspaceResolver; +import ai.javaclaw.agent.AgentChatClientFactory; +import ai.javaclaw.agent.AgentChatModelFactory; +import ai.javaclaw.agent.AgentWorkspaceResolver; import ai.javaclaw.configuration.ConfigurationManager; import ai.javaclaw.tasks.TaskManager; import ai.javaclaw.tools.AutoDiscoveredTool; diff --git a/base/src/test/java/ai/javaclaw/models/ModelRegistryTest.java b/base/src/test/java/ai/javaclaw/models/ModelRegistryTest.java index 68771b61..106e18e4 100644 --- a/base/src/test/java/ai/javaclaw/models/ModelRegistryTest.java +++ b/base/src/test/java/ai/javaclaw/models/ModelRegistryTest.java @@ -1,7 +1,7 @@ package ai.javaclaw.models; -import ai.javaclaw.agents.AgentRegistry; -import ai.javaclaw.agents.ConfiguredAgent; +import ai.javaclaw.agent.AgentRegistry; +import ai.javaclaw.agent.ConfiguredAgent; import ai.javaclaw.configuration.ConfigurationManager; import org.junit.jupiter.api.Test; import org.springframework.mock.env.MockEnvironment; diff --git a/base/src/test/java/ai/javaclaw/models/ModelWorkspaceResolverTest.java b/base/src/test/java/ai/javaclaw/models/ModelWorkspaceResolverTest.java index c2d3c208..edfbaa1e 100644 --- a/base/src/test/java/ai/javaclaw/models/ModelWorkspaceResolverTest.java +++ b/base/src/test/java/ai/javaclaw/models/ModelWorkspaceResolverTest.java @@ -1,6 +1,6 @@ package ai.javaclaw.models; -import ai.javaclaw.agents.AgentWorkspaceResolver; +import ai.javaclaw.agent.AgentWorkspaceResolver; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.springframework.core.io.DefaultResourceLoader; diff --git a/build.gradle b/build.gradle index 7b822418..a7ad355a 100644 --- a/build.gradle +++ b/build.gradle @@ -25,14 +25,14 @@ configure(subprojects.findAll { it.buildFile.exists() }) { apply plugin: 'io.spring.dependency-management' ext { - springAiVersion = '2.0.0-SNAPSHOT' + springAiVersion = '2.0.0-M4' springModulithVersion = '2.0.3' } dependencyManagement { imports { mavenBom "org.springframework.boot:spring-boot-dependencies:4.0.3" - mavenBom "org.springframework.ai:spring-ai-bom:2.0.0-SNAPSHOT" + mavenBom "org.springframework.ai:spring-ai-bom:2.0.0-M4" mavenBom "org.springframework.modulith:spring-modulith-bom:2.0.3" } } diff --git a/providers/anthropic/src/main/java/ai/javaclaw/providers/anthropic/AnthropicAgentChatModelFactory.java b/providers/anthropic/src/main/java/ai/javaclaw/providers/anthropic/AnthropicAgentChatModelFactory.java index a98bd556..89ea8c18 100644 --- a/providers/anthropic/src/main/java/ai/javaclaw/providers/anthropic/AnthropicAgentChatModelFactory.java +++ b/providers/anthropic/src/main/java/ai/javaclaw/providers/anthropic/AnthropicAgentChatModelFactory.java @@ -1,7 +1,7 @@ package ai.javaclaw.providers.anthropic; -import ai.javaclaw.agents.AgentChatModelFactory; -import ai.javaclaw.agents.ConfiguredAgent; +import ai.javaclaw.agent.AgentChatModelFactory; +import ai.javaclaw.agent.ConfiguredAgent; import com.anthropic.client.AnthropicClient; import com.anthropic.client.AnthropicClientAsync; import com.anthropic.client.okhttp.AnthropicOkHttpClient; diff --git a/providers/google/src/main/java/ai/javaclaw/providers/google/genai/GoogleGenAiAgentChatModelFactory.java b/providers/google/src/main/java/ai/javaclaw/providers/google/genai/GoogleGenAiAgentChatModelFactory.java index e87e1894..484dda4a 100644 --- a/providers/google/src/main/java/ai/javaclaw/providers/google/genai/GoogleGenAiAgentChatModelFactory.java +++ b/providers/google/src/main/java/ai/javaclaw/providers/google/genai/GoogleGenAiAgentChatModelFactory.java @@ -1,7 +1,7 @@ package ai.javaclaw.providers.google.genai; -import ai.javaclaw.agents.AgentChatModelFactory; -import ai.javaclaw.agents.ConfiguredAgent; +import ai.javaclaw.agent.AgentChatModelFactory; +import ai.javaclaw.agent.ConfiguredAgent; import com.google.genai.Client; import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.chat.model.ChatModel; diff --git a/providers/ollama/src/main/java/ai/javaclaw/providers/ollama/OllamaAgentChatModelFactory.java b/providers/ollama/src/main/java/ai/javaclaw/providers/ollama/OllamaAgentChatModelFactory.java index 326ca337..210fe406 100644 --- a/providers/ollama/src/main/java/ai/javaclaw/providers/ollama/OllamaAgentChatModelFactory.java +++ b/providers/ollama/src/main/java/ai/javaclaw/providers/ollama/OllamaAgentChatModelFactory.java @@ -1,7 +1,7 @@ package ai.javaclaw.providers.ollama; -import ai.javaclaw.agents.AgentChatModelFactory; -import ai.javaclaw.agents.ConfiguredAgent; +import ai.javaclaw.agent.AgentChatModelFactory; +import ai.javaclaw.agent.ConfiguredAgent; import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.model.tool.DefaultToolExecutionEligibilityPredicate; diff --git a/providers/openai/src/main/java/ai/javaclaw/providers/openai/OpenAiAgentChatModelFactory.java b/providers/openai/src/main/java/ai/javaclaw/providers/openai/OpenAiAgentChatModelFactory.java index 9f7ed256..92ac3a4b 100644 --- a/providers/openai/src/main/java/ai/javaclaw/providers/openai/OpenAiAgentChatModelFactory.java +++ b/providers/openai/src/main/java/ai/javaclaw/providers/openai/OpenAiAgentChatModelFactory.java @@ -1,7 +1,7 @@ package ai.javaclaw.providers.openai; -import ai.javaclaw.agents.AgentChatModelFactory; -import ai.javaclaw.agents.ConfiguredAgent; +import ai.javaclaw.agent.AgentChatModelFactory; +import ai.javaclaw.agent.ConfiguredAgent; import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.model.tool.DefaultToolExecutionEligibilityPredicate; From f7d5f7b9556267606dbf379fb61941c57765ca11 Mon Sep 17 00:00:00 2001 From: arefbehboudi Date: Sat, 25 Apr 2026 10:56:51 +0300 Subject: [PATCH 8/9] Rmove onboarding from chat page --- app/src/main/resources/templates/chat.html.peb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/main/resources/templates/chat.html.peb b/app/src/main/resources/templates/chat.html.peb index f146984f..352af1ad 100644 --- a/app/src/main/resources/templates/chat.html.peb +++ b/app/src/main/resources/templates/chat.html.peb @@ -32,11 +32,6 @@ Agents -