From 6789f035b2bceff128689b2db403876425d4757d Mon Sep 17 00:00:00 2001 From: Mahesh Kommareddi Date: Tue, 30 Jul 2024 23:21:45 -0400 Subject: [PATCH] Mostly working system --- README.md | 3 + application.properties | 2 + src/main/java/com/ioa/IoASystem.java | 222 ++++-------------- src/main/java/com/ioa/agent/AgentInfo.java | 73 +++--- src/main/java/com/ioa/agent/AgentMessage.java | 12 + .../java/com/ioa/agent/AgentRegistry.java | 37 ++- .../java/com/ioa/config/WebSocketConfig.java | 44 +++- .../com/ioa/conversation/ConversationFSM.java | 36 ++- .../ioa/conversation/ConversationManager.java | 44 ++-- .../ioa/conversation/ConversationState.java | 2 + .../com/ioa/model/BedrockLanguageModel.java | 102 +++++--- .../com/ioa/service/WebSocketService.java | 66 +----- src/main/java/com/ioa/task/Task.java | 21 +- .../java/com/ioa/task/TaskAssignment.java | 14 ++ src/main/java/com/ioa/task/TaskManager.java | 77 +++++- src/main/java/com/ioa/task/TaskResult.java | 31 +++ src/main/java/com/ioa/tool/ToolInfo.java | 29 +++ .../ioa/websocket/AgentProcessingUpdate.java | 16 ++ .../ioa/websocket/AgentResponseUpdate.java | 16 ++ .../com/ioa/websocket/ChatController.java | 50 ++++ .../com/ioa/websocket/WebSocketHandler.java | 91 +++++++ target/classes/com/ioa/IoASystem.class | Bin 9489 -> 4387 bytes target/classes/com/ioa/agent/AgentInfo.class | Bin 3746 -> 9180 bytes .../classes/com/ioa/agent/AgentRegistry.class | Bin 5473 -> 6094 bytes .../com/ioa/config/WebSocketConfig.class | Bin 1911 -> 3804 bytes ...versationFSM$ConversationStateUpdate.class | Bin 1115 -> 1150 bytes .../ioa/conversation/ConversationFSM.class | Bin 8361 -> 8733 bytes .../conversation/ConversationManager.class | Bin 5185 -> 3311 bytes .../ioa/conversation/ConversationState.class | Bin 1465 -> 1508 bytes .../com/ioa/conversation/Message.class | Bin 1390 -> 1402 bytes .../com/ioa/model/BedrockLanguageModel.class | Bin 7103 -> 8750 bytes .../com/ioa/service/WebSocketService.class | Bin 3403 -> 1369 bytes target/classes/com/ioa/task/Task.class | Bin 4771 -> 2282 bytes target/classes/com/ioa/task/TaskManager.class | Bin 4357 -> 7673 bytes .../classes/com/ioa/team/TeamFormation.class | Bin 8562 -> 8589 bytes .../classes/com/ioa/tool/ToolRegistry.class | Bin 1542 -> 1546 bytes .../common/AppointmentSchedulerTool.class | Bin 1113 -> 1113 bytes .../tool/common/DistanceCalculatorTool.class | Bin 1113 -> 1113 bytes .../ioa/tool/common/FinancialAdviceTool.class | Bin 1093 -> 1093 bytes .../tool/common/FitnessClassFinderTool.class | Bin 1107 -> 1107 bytes .../tool/common/MovieRecommendationTool.class | Bin 1110 -> 1110 bytes .../com/ioa/tool/common/NewsUpdateTool.class | Bin 1074 -> 1074 bytes .../ioa/tool/common/PriceComparisonTool.class | Bin 1093 -> 1093 bytes .../com/ioa/tool/common/RecipeTool.class | Bin 1062 -> 1062 bytes .../com/ioa/tool/common/ReminderTool.class | Bin 1068 -> 1068 bytes .../tool/common/RestaurantFinderTool.class | Bin 1098 -> 1098 bytes .../com/ioa/tool/common/TranslationTool.class | Bin 1072 -> 1072 bytes .../ioa/tool/common/TravelBookingTool.class | Bin 1084 -> 1084 bytes .../com/ioa/tool/common/WeatherTool.class | Bin 1072 -> 1072 bytes .../com/ioa/tool/common/WebSearchTool.class | Bin 1077 -> 1077 bytes .../classes/com/ioa/util/TreeOfThought.class | Bin 6068 -> 5907 bytes 51 files changed, 623 insertions(+), 365 deletions(-) create mode 100644 README.md create mode 100644 application.properties create mode 100644 src/main/java/com/ioa/agent/AgentMessage.java create mode 100644 src/main/java/com/ioa/task/TaskAssignment.java create mode 100644 src/main/java/com/ioa/task/TaskResult.java create mode 100644 src/main/java/com/ioa/tool/ToolInfo.java create mode 100644 src/main/java/com/ioa/websocket/AgentProcessingUpdate.java create mode 100644 src/main/java/com/ioa/websocket/AgentResponseUpdate.java create mode 100644 src/main/java/com/ioa/websocket/ChatController.java create mode 100644 src/main/java/com/ioa/websocket/WebSocketHandler.java diff --git a/README.md b/README.md new file mode 100644 index 0000000..e2475c5 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +mvn spring-boot:run + +http://localhost:8080/ \ No newline at end of file diff --git a/application.properties b/application.properties new file mode 100644 index 0000000..10f9312 --- /dev/null +++ b/application.properties @@ -0,0 +1,2 @@ +logging.level.org.springframework.messaging=TRACE +logging.level.org.springframework.web.socket=TRACE diff --git a/src/main/java/com/ioa/IoASystem.java b/src/main/java/com/ioa/IoASystem.java index beefa21..6f9e41a 100644 --- a/src/main/java/com/ioa/IoASystem.java +++ b/src/main/java/com/ioa/IoASystem.java @@ -1,59 +1,51 @@ package com.ioa; -import com.ioa.agent.AgentInfo; -import com.ioa.agent.AgentRegistry; -import com.ioa.conversation.ConversationManager; -import com.ioa.task.Task; -import com.ioa.task.TaskManager; -import com.ioa.team.TeamFormation; -import com.ioa.tool.ToolRegistry; -import com.ioa.tool.Tool; -import com.ioa.tool.common.*; -import com.ioa.model.BedrockLanguageModel; -import com.ioa.service.WebSocketService; -import com.ioa.util.TreeOfThought; - -import com.ioa.tool.common.AppointmentSchedulerTool; -import com.ioa.tool.common.DistanceCalculatorTool; -import com.ioa.tool.common.FinancialAdviceTool; -import com.ioa.tool.common.FitnessClassFinderTool; -import com.ioa.tool.common.MovieRecommendationTool; -import com.ioa.tool.common.NewsUpdateTool; -import com.ioa.tool.common.PriceComparisonTool; -import com.ioa.tool.common.RecipeTool; -import com.ioa.tool.common.ReminderTool; -import com.ioa.tool.common.RestaurantFinderTool; -import com.ioa.tool.common.TranslationTool; -import com.ioa.tool.common.TravelBookingTool; -import com.ioa.tool.common.WeatherTool; -import com.ioa.tool.common.WebSearchTool; - -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.ComponentScan; import org.springframework.messaging.simp.SimpMessagingTemplate; -import java.util.Arrays; -import java.util.List; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.CountDownLatch; +import com.ioa.agent.AgentRegistry; +import com.ioa.task.TaskManager; +import com.ioa.websocket.WebSocketHandler; +import com.ioa.tool.ToolRegistry; +import com.ioa.model.BedrockLanguageModel; +import com.ioa.util.TreeOfThought; +import com.ioa.service.WebSocketService; +import com.ioa.conversation.ConversationManager; @SpringBootApplication +@ComponentScan(basePackages = "com.ioa") public class IoASystem { @Bean - public WebSocketService webSocketService(SimpMessagingTemplate messagingTemplate, @Lazy ConversationManager conversationManager) { - return new WebSocketService(messagingTemplate, conversationManager); + public WebSocketHandler webSocketHandler(AgentRegistry agentRegistry, + TaskManager taskManager, + SimpMessagingTemplate messagingTemplate, + TreeOfThought treeOfThought, + WebSocketService webSocketService, + ToolRegistry toolRegistry, + BedrockLanguageModel model) { + return new WebSocketHandler(agentRegistry, taskManager, messagingTemplate, + treeOfThought, webSocketService, toolRegistry, model); } @Bean - public ConversationManager conversationManager(BedrockLanguageModel model, WebSocketService webSocketService) { - return new ConversationManager(model, webSocketService); + public AgentRegistry agentRegistry(SimpMessagingTemplate messagingTemplate, ToolRegistry toolRegistry) { + return new AgentRegistry(messagingTemplate, toolRegistry); + } + + @Bean + public TaskManager taskManager(AgentRegistry agentRegistry, + BedrockLanguageModel model, + ToolRegistry toolRegistry, + TreeOfThought treeOfThought, + ConversationManager conversationManager, + WebSocketService webSocketService, + SimpMessagingTemplate messagingTemplate) { + return new TaskManager(agentRegistry, model, toolRegistry, treeOfThought, + conversationManager, webSocketService, messagingTemplate); } @Bean @@ -67,149 +59,21 @@ public class IoASystem { } @Bean - public AgentRegistry agentRegistry(ToolRegistry toolRegistry, TreeOfThought treeOfThought, WebSocketService webSocketService, ConversationManager conversationManager) { - AgentRegistry registry = new AgentRegistry(toolRegistry); - - // Agent creation is now moved to processTasksAndAgents method - - return registry; - } - - @Bean - public TaskManager taskManager(AgentRegistry agentRegistry, BedrockLanguageModel model, ToolRegistry toolRegistry, TreeOfThought treeOfThought, ConversationManager conversationManager) { - return new TaskManager(agentRegistry, model, toolRegistry, treeOfThought, conversationManager); - } - - @Bean - public TeamFormation teamFormation(AgentRegistry agentRegistry, TreeOfThought treeOfThought, WebSocketService webSocketService, BedrockLanguageModel model) { - return new TeamFormation(agentRegistry, treeOfThought, webSocketService, model); + public WebSocketService webSocketService(SimpMessagingTemplate messagingTemplate) { + return new WebSocketService(messagingTemplate); } @Bean public ToolRegistry toolRegistry() { - ToolRegistry toolRegistry = new ToolRegistry(); - - // Register all tools - toolRegistry.registerTool("webSearch", new WebSearchTool()); - toolRegistry.registerTool("getWeather", new WeatherTool()); - toolRegistry.registerTool("setReminder", new ReminderTool()); - toolRegistry.registerTool("bookTravel", new TravelBookingTool()); - toolRegistry.registerTool("calculateDistance", new DistanceCalculatorTool()); - toolRegistry.registerTool("findRestaurants", new RestaurantFinderTool()); - toolRegistry.registerTool("scheduleAppointment", new AppointmentSchedulerTool()); - toolRegistry.registerTool("findFitnessClasses", new FitnessClassFinderTool()); - toolRegistry.registerTool("getRecipe", new RecipeTool()); - toolRegistry.registerTool("getNewsUpdates", new NewsUpdateTool()); - toolRegistry.registerTool("translate", new TranslationTool()); - toolRegistry.registerTool("compareProductPrices", new PriceComparisonTool()); - toolRegistry.registerTool("getMovieRecommendations", new MovieRecommendationTool()); - toolRegistry.registerTool("getFinancialAdvice", new FinancialAdviceTool()); - - return toolRegistry; + return new ToolRegistry(); + } + + @Bean + public ConversationManager conversationManager(BedrockLanguageModel model, WebSocketService webSocketService) { + return new ConversationManager(model, webSocketService); } public static void main(String[] args) { - ConfigurableApplicationContext context = SpringApplication.run(IoASystem.class, args); - IoASystem system = context.getBean(IoASystem.class); - system.processTasksAndAgents(context); + SpringApplication.run(IoASystem.class, args); } - - public void processTasksAndAgents(ConfigurableApplicationContext context) { - AgentRegistry agentRegistry = context.getBean(AgentRegistry.class); - TeamFormation teamFormation = context.getBean(TeamFormation.class); - TaskManager taskManager = context.getBean(TaskManager.class); - TreeOfThought treeOfThought = context.getBean(TreeOfThought.class); - WebSocketService webSocketService = context.getBean(WebSocketService.class); - ToolRegistry toolRegistry = context.getBean(ToolRegistry.class); - ConversationManager conversationManager = context.getBean(ConversationManager.class); - BedrockLanguageModel model = context.getBean(BedrockLanguageModel.class); - - - // Register all agents - agentRegistry.registerAgent("agent1", new AgentInfo("agent1", "General Assistant", - Arrays.asList("general", "search"), - Arrays.asList("webSearch", "getWeather", "setReminder"), - treeOfThought, webSocketService, toolRegistry, model)); - agentRegistry.registerAgent("agent2", new AgentInfo("agent2", "Travel Expert", - Arrays.asList("travel", "booking"), - Arrays.asList("bookTravel", "calculateDistance", "findRestaurants"), - treeOfThought, webSocketService, toolRegistry, model)); - agentRegistry.registerAgent("agent3", new AgentInfo("agent3", "Event Planner Extraordinaire", - Arrays.asList("event planning", "team management", "booking"), - Arrays.asList("findRestaurants", "bookTravel", "scheduleAppointment", "getWeather"), - treeOfThought, webSocketService, toolRegistry, model)); - agentRegistry.registerAgent("agent4", new AgentInfo("agent4", "Fitness Guru", - Arrays.asList("health", "nutrition", "motivation"), - Arrays.asList("findFitnessClasses", "getRecipe", "setReminder", "getWeather"), - treeOfThought, webSocketService, toolRegistry, model)); - agentRegistry.registerAgent("agent5", new AgentInfo("agent5", "Research Specialist", - Arrays.asList("research", "writing", "analysis"), - Arrays.asList("webSearch", "getNewsUpdates", "translate", "compareProductPrices"), - treeOfThought, webSocketService, toolRegistry, model)); - agentRegistry.registerAgent("agent6", new AgentInfo("agent6", "Digital Marketing Expert", - Arrays.asList("marketing", "social media", "content creation"), - Arrays.asList("webSearch", "getNewsUpdates", "scheduleAppointment", "getMovieRecommendations"), - treeOfThought, webSocketService, toolRegistry, model)); - agentRegistry.registerAgent("agent7", new AgentInfo("agent7", "Family Travel Coordinator", - Arrays.asList("travel", "family planning", "budgeting"), - Arrays.asList("bookTravel", "calculateDistance", "getWeather", "findRestaurants", "getFinancialAdvice"), - treeOfThought, webSocketService, toolRegistry, model)); - - // Create all tasks - List tasks = Arrays.asList( - new Task("task1", "Plan a weekend trip to Paris", - Arrays.asList("travel", "booking"), - Arrays.asList("bookTravel", "findRestaurants", "getWeather"))//, - // new Task("task2", "Organize a corporate team-building event in New York", - // Arrays.asList("event planning", "team management"), - // Arrays.asList("findRestaurants", "bookTravel", "scheduleAppointment")), - // new Task("task3", "Develop a personalized fitness and nutrition plan", - // Arrays.asList("health", "nutrition"), - // Arrays.asList("getWeather", "findFitnessClasses", "getRecipe")), - // new Task("task4", "Research and summarize recent advancements in renewable energy", - // Arrays.asList("research", "writing"), - // Arrays.asList("webSearch", "getNewsUpdates", "translate")), - // new Task("task5", "Plan and execute a social media marketing campaign for a new product launch", - // Arrays.asList("marketing", "social media"), - // Arrays.asList("webSearch", "getNewsUpdates", "scheduleAppointment")), - // new Task("task6", "Assist in planning a multi-city European vacation for a family of four", - // Arrays.asList("travel", "family planning"), - // Arrays.asList("bookTravel", "calculateDistance", "getWeather", "findRestaurants")), - - // new Task("task7", "Organize an international tech conference with virtual and in-person components", - // Arrays.asList("event planning", "tech expertise", "marketing", "travel coordination", "content creation"), - // Arrays.asList("scheduleAppointment", "webSearch", "bookTravel", "getWeather", "findRestaurants", "getNewsUpdates"))//, - - // new Task("task8", "Develop and launch a multi-lingual mobile app for sustainable tourism", - // Arrays.asList("software development", "travel", "language expertise", "environmental science", "user experience design"), - // Arrays.asList("webSearch", "translate", "getWeather", "findRestaurants", "getNewsUpdates", "compareProductPrices")), - - // new Task("task9", "Create a comprehensive health and wellness program for a large corporation, including mental health support", - // Arrays.asList("health", "nutrition", "psychology", "corporate wellness", "data analysis"), - // Arrays.asList("findFitnessClasses", "getRecipe", "setReminder", "getWeather", "scheduleAppointment", "getFinancialAdvice")), - - // new Task("task10", "Plan and execute a global product launch campaign for a revolutionary eco-friendly technology", - // Arrays.asList("marketing", "environmental science", "international business", "public relations", "social media"), - // Arrays.asList("webSearch", "getNewsUpdates", "scheduleAppointment", "translate", "compareProductPrices", "bookTravel")), - - // new Task("task11", "Design and implement a smart city initiative focusing on transportation, energy, and public safety", - // Arrays.asList("urban planning", "environmental science", "data analysis", "public policy", "technology integration"), - // Arrays.asList("webSearch", "getWeather", "calculateDistance", "getNewsUpdates", "getFinancialAdvice", "findHomeServices")) - - ); - - for (Task task : tasks) { - taskManager.addTask(task); // Add each task to the TaskManager - System.out.println("\nProcessing task: " + task.getDescription()); - List team = teamFormation.formTeam(task); - System.out.println("Formed team: " + team); - - if (!team.isEmpty()) { - taskManager.executeTask(task.getId(), team); - System.out.println("Task result: " + task.getResult()); - } else { - System.out.println("No suitable agents found for this task. Consider updating the agent pool or revising the task requirements."); - } - } - } -} +} \ No newline at end of file diff --git a/src/main/java/com/ioa/agent/AgentInfo.java b/src/main/java/com/ioa/agent/AgentInfo.java index 4b7a676..f788771 100644 --- a/src/main/java/com/ioa/agent/AgentInfo.java +++ b/src/main/java/com/ioa/agent/AgentInfo.java @@ -1,15 +1,21 @@ package com.ioa.agent; -import com.ioa.conversation.ConversationFSM; import com.ioa.conversation.Message; import com.ioa.model.BedrockLanguageModel; import com.ioa.service.WebSocketService; import com.ioa.tool.ToolRegistry; import com.ioa.util.TreeOfThought; +import com.ioa.websocket.AgentProcessingUpdate; +import com.ioa.websocket.AgentResponseUpdate; import java.util.List; -import java.util.Map; +import java.util.UUID; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor public class AgentInfo { private String id; private String name; @@ -21,59 +27,56 @@ public class AgentInfo { private ToolRegistry toolRegistry; private BedrockLanguageModel model; - public AgentInfo(String id, String name, List capabilities, List tools, - TreeOfThought treeOfThought, WebSocketService webSocketService, - ToolRegistry toolRegistry, BedrockLanguageModel model) { + public AgentInfo(String id, String name, List capabilities, List tools) { this.id = id; this.name = name; this.capabilities = capabilities; this.tools = tools; + this.memory = new Memory(); + } + + public void setDependencies(TreeOfThought treeOfThought, WebSocketService webSocketService, + ToolRegistry toolRegistry, BedrockLanguageModel model) { this.treeOfThought = treeOfThought; this.webSocketService = webSocketService; this.toolRegistry = toolRegistry; this.model = model; - this.memory = new Memory(); } - public void receiveMessage(Message message) { + public void receiveMessageLocal(Message message) { + if (this.memory == null) + this.memory = new Memory(); memory.addToHistory(message.getContent()); - String prompt = "You are " + name + " with capabilities: " + capabilities + - "\nYou received a message: " + message.getContent() + - "\nBased on your memory and context, how would you respond or what actions would you take?" + - "\n\nMemory:\n" + memory.getFormattedMemory(); + String prompt = "You are " + name + " with capabilities: " + capabilities + + "\nYou received a message: " + message.getContent() + + "\nBased on your memory and context, how would you respond or what actions would you take?" + + "\n\nMemory:\n" + memory.getFormattedMemory(); String response = model.generate(prompt, null); System.out.println("DEBUG: " + name + " processed message: " + message.getContent()); System.out.println("DEBUG: " + name + " response: " + response); - + // Add the response to memory memory.addToHistory("My response: " + response); } - public void performTreeOfThought(String task) { - String prompt = "You are " + name + " with capabilities: " + capabilities + - "\nTask: " + task + - "\nBased on your memory and context, perform a tree of thought reasoning to approach this task." + - "\n\nMemory:\n" + memory.getFormattedMemory(); - - Map totResult = treeOfThought.reason(prompt, 3, 2); - String reasoning = (String) totResult.get("reasoning"); - - // Add the reasoning to memory - memory.addContextualFact("Tree of Thought for task '" + task + "': " + reasoning); - - System.out.println("DEBUG: " + name + " Tree of Thought reasoning: " + reasoning); + public void receiveMessage(Message message) { + if (this.memory == null) + this.memory = new Memory(); + + + // This is a turn notification for this agent + respondToTurn(message.getConversationId()); + } - public void notifyTurn(ConversationFSM conversation) { - String prompt = "You are " + name + " with capabilities: " + capabilities + - "\nIt's your turn to speak in the conversation. What would you like to say or do?"; - String response = model.generate(prompt, null); - conversation.postMessage(new Message(conversation.getConversationId(), id, response)); + private void respondToTurn(String conversationId) { + String prompt = "You are " + name + " with capabilities: " + capabilities + + "\nIt's your turn to speak in the conversation. What would you like to say or do?" + + "\n\nMemory:\n" + memory.getFormattedMemory(); + + // Send the response back to the conversation + Message responseMessage = new Message(conversationId, this.id, prompt); + webSocketService.sendUpdate("conversation_message", responseMessage); } - // Getters and setters - public String getId() { return id; } - public String getName() { return name; } - public List getCapabilities() { return capabilities; } - public List getTools() { return tools; } } \ No newline at end of file diff --git a/src/main/java/com/ioa/agent/AgentMessage.java b/src/main/java/com/ioa/agent/AgentMessage.java new file mode 100644 index 0000000..ce514e6 --- /dev/null +++ b/src/main/java/com/ioa/agent/AgentMessage.java @@ -0,0 +1,12 @@ +package com.ioa.agent; + +public class AgentMessage { + private String agentId; + private String content; + + // Getters and setters + public String getAgentId() { return agentId; } + public void setAgentId(String agentId) { this.agentId = agentId; } + public String getContent() { return content; } + public void setContent(String content) { this.content = content; } +} \ No newline at end of file diff --git a/src/main/java/com/ioa/agent/AgentRegistry.java b/src/main/java/com/ioa/agent/AgentRegistry.java index 5ea4d42..552ce5c 100644 --- a/src/main/java/com/ioa/agent/AgentRegistry.java +++ b/src/main/java/com/ioa/agent/AgentRegistry.java @@ -1,34 +1,53 @@ package com.ioa.agent; -import com.ioa.tool.ToolRegistry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Component; +import com.ioa.tool.ToolRegistry; -import java.util.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Component public class AgentRegistry { - private Map agents = new HashMap<>(); - private ToolRegistry toolRegistry; + private Map agents = new ConcurrentHashMap<>(); + private final SimpMessagingTemplate messagingTemplate; + private final ToolRegistry toolRegistry; - public AgentRegistry(ToolRegistry toolRegistry) { + @Autowired + public AgentRegistry(SimpMessagingTemplate messagingTemplate, ToolRegistry toolRegistry) { + this.messagingTemplate = messagingTemplate; this.toolRegistry = toolRegistry; } - public void registerAgent(String agentId, AgentInfo agentInfo) { - agents.put(agentId, agentInfo); + public void registerAgent(AgentInfo agentInfo) { + agents.put(agentInfo.getId(), agentInfo); // Verify that all tools the agent claims to have are registered for (String tool : agentInfo.getTools()) { if (toolRegistry.getTool(tool) == null) { throw new IllegalArgumentException("Tool not found in registry: " + tool); } } + messagingTemplate.convertAndSend("/topic/agents", "New agent registered: " + agentInfo.getId()); + } + + public void unregisterAgent(String agentId) { + agents.remove(agentId); + messagingTemplate.convertAndSend("/topic/agents", "Agent unregistered: " + agentId); } public AgentInfo getAgent(String agentId) { return agents.get(agentId); } + public List getAllAgents() { + return new ArrayList<>(agents.values()); + } + public List searchAgents(List capabilities) { return searchAgents(capabilities, 1.0); // Default to exact match } @@ -50,8 +69,4 @@ public class AgentRegistry { .count(); return (double) matchingCapabilities / requiredCapabilities.size(); } - - public List getAllAgents() { - return new ArrayList<>(agents.values()); - } } \ No newline at end of file diff --git a/src/main/java/com/ioa/config/WebSocketConfig.java b/src/main/java/com/ioa/config/WebSocketConfig.java index 70919ec..6368707 100644 --- a/src/main/java/com/ioa/config/WebSocketConfig.java +++ b/src/main/java/com/ioa/config/WebSocketConfig.java @@ -1,7 +1,19 @@ package com.ioa.config; +import org.springframework.messaging.converter.MappingJackson2MessageConverter; +import org.springframework.messaging.converter.MessageConverter; +import org.springframework.util.MimeTypeUtils; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.converter.DefaultContentTypeResolver; +import java.util.List; + import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.ChannelRegistration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.messaging.simp.stomp.StompHeaderAccessor; +import org.springframework.messaging.support.ChannelInterceptor; +import org.springframework.messaging.support.MessageHeaderAccessor; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; @@ -18,6 +30,34 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/ws").withSockJS(); + registry.addEndpoint("/ws") + .setAllowedOriginPatterns("*") + .withSockJS(); } -} \ No newline at end of file + + @Override + public boolean configureMessageConverters(List messageConverters) { + MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); + DefaultContentTypeResolver resolver = new DefaultContentTypeResolver(); + resolver.setDefaultMimeType(MimeTypeUtils.APPLICATION_JSON); + converter.setContentTypeResolver(resolver); + messageConverters.add(converter); + return false; + } + + @Override + public void configureClientInboundChannel(ChannelRegistration registration) { + registration.interceptors(new ChannelInterceptor() { + @Override + public Message preSend(Message message, MessageChannel channel) { + StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); + if (accessor != null && accessor.getCommand() != null) { + System.out.println("Received STOMP Frame: " + accessor.getCommand()); + System.out.println("Destination: " + accessor.getDestination()); + System.out.println("Payload: " + new String((byte[]) message.getPayload())); + } + return message; + } + }); + } +} \ No newline at end of file diff --git a/src/main/java/com/ioa/conversation/ConversationFSM.java b/src/main/java/com/ioa/conversation/ConversationFSM.java index e118dae..a1141cf 100644 --- a/src/main/java/com/ioa/conversation/ConversationFSM.java +++ b/src/main/java/com/ioa/conversation/ConversationFSM.java @@ -91,18 +91,33 @@ public class ConversationFSM { private void updateState(Message message) { String stateTransitionTask = "Decide the next conversation state based on this message: " + message.getContent() + "\nCurrent state: " + currentState + - "\nParticipants: " + participants; + "\nParticipants: " + participants + + "\nProvide the next conversation state (" + + "DISCUSSION," + + "RESEARCH," + + "RESEARCH_TASK," + + "TASK_GATHERING_INFO," + + "TASK," + + "TASK_PLANNING," + + "TASK_ASSIGNMENT," + + "EXECUTION," + + "CONCLUSION" + + "\n)\nOnly give the single word answer in all caps only from the given options."; String reasoning = model.generate(stateTransitionTask, null); String decisionPrompt = "Based on this reasoning:\n" + reasoning + - "\nProvide the next conversation state (DISCUSSION,\n" + // - " TASK_GATHERING_INFO,\n" + // - " TASK,\n" + // - " TASK_PLANNING,\n" + // - " TASK_ASSIGNMENT,\n" + // - " EXECUTION,\n" + // - " CONCLUSION). Only give the single word answer in all caps only from the given options."; + "\nProvide the next conversation state (" + + "DISCUSSION," + + "RESEARCH," + + "RESEARCH_TASK," + + "TASK_GATHERING_INFO," + + "TASK," + + "TASK_PLANNING," + + "TASK_ASSIGNMENT," + + "EXECUTION," + + "CONCLUSION" + + "\n)\nOnly give the single word answer in all caps only from the given options."; String response = model.generate(decisionPrompt, null); ConversationState newState = ConversationState.valueOf(response.trim()); @@ -112,7 +127,10 @@ public class ConversationFSM { private void notifyNextSpeaker() { AgentInfo nextSpeaker = speakingQueue.poll(); if (nextSpeaker != null) { - nextSpeaker.notifyTurn(this); + // Instead of calling notifyTurn, we'll create a turn notification message + Message turnNotification = new Message(this.conversationId, "SYSTEM", + "It's " + nextSpeaker.getName() + "'s turn to speak."); + broadcastMessage(turnNotification); speakingQueue.offer(nextSpeaker); } } diff --git a/src/main/java/com/ioa/conversation/ConversationManager.java b/src/main/java/com/ioa/conversation/ConversationManager.java index 81a2079..d843f5d 100644 --- a/src/main/java/com/ioa/conversation/ConversationManager.java +++ b/src/main/java/com/ioa/conversation/ConversationManager.java @@ -3,23 +3,23 @@ package com.ioa.conversation; import com.ioa.agent.AgentInfo; import com.ioa.model.BedrockLanguageModel; import com.ioa.service.WebSocketService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.*; -import java.util.concurrent.*; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; @Component public class ConversationManager { - private final Map conversations; + private final Map conversations = new ConcurrentHashMap<>(); private final BedrockLanguageModel model; private final WebSocketService webSocketService; - private final ScheduledExecutorService executorService; + @Autowired public ConversationManager(BedrockLanguageModel model, WebSocketService webSocketService) { - this.conversations = new ConcurrentHashMap<>(); this.model = model; this.webSocketService = webSocketService; - this.executorService = Executors.newScheduledThreadPool(1); } public String createConversation() { @@ -30,6 +30,21 @@ public class ConversationManager { return conversationId; } + public void joinConversation(String conversationId) { + ConversationFSM conversation = conversations.get(conversationId); + if (conversation != null) { + // Logic to join a conversation (e.g., add participant) + webSocketService.sendUpdate("conversation_joined", conversationId); + } + } + + public void postMessage(String conversationId, String senderId, String content) { + ConversationFSM conversation = conversations.get(conversationId); + if (conversation != null) { + conversation.postMessage(new Message(conversationId, senderId, content)); + } + } + public ConversationFSM getConversation(String conversationId) { return conversations.get(conversationId); } @@ -47,21 +62,6 @@ public class ConversationManager { conversation.removeParticipant(agent); } } - - public void postMessage(String conversationId, String senderId, String content) { - System.out.println("DEBUG: Posting message - ConversationId: " + conversationId + ", SenderId: " + senderId + ", Content: " + content); - ConversationFSM conversation = conversations.get(conversationId); - if (conversation != null) { - if (content == null) { - Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' ); - System.out.println("WARNING: Attempting to post null content message"); - return; - } - conversation.postMessage(new Message(conversationId, senderId, content)); - } else { - System.out.println("WARNING: Conversation not found for id: " + conversationId); - } - } public void startConversation(String conversationId, String initialMessage) { ConversationFSM conversation = conversations.get(conversationId); @@ -69,7 +69,7 @@ public class ConversationManager { conversation.postMessage(new Message(conversationId, "SYSTEM", initialMessage)); // Start a timer to end the conversation after 10 minutes - executorService.schedule(() -> { + Executor.schedule(() -> { if (!conversation.isFinished()) { conversation.finish("Time limit reached"); } diff --git a/src/main/java/com/ioa/conversation/ConversationState.java b/src/main/java/com/ioa/conversation/ConversationState.java index 37fc097..6990ccb 100644 --- a/src/main/java/com/ioa/conversation/ConversationState.java +++ b/src/main/java/com/ioa/conversation/ConversationState.java @@ -2,6 +2,8 @@ package com.ioa.conversation; public enum ConversationState { DISCUSSION, + RESEARCH, + RESEARCH_TASK, TASK_GATHERING_INFO, TASK, TASK_PLANNING, diff --git a/src/main/java/com/ioa/model/BedrockLanguageModel.java b/src/main/java/com/ioa/model/BedrockLanguageModel.java index 3b3fc30..e7dab75 100644 --- a/src/main/java/com/ioa/model/BedrockLanguageModel.java +++ b/src/main/java/com/ioa/model/BedrockLanguageModel.java @@ -17,6 +17,7 @@ import org.springframework.stereotype.Component; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; +import java.util.function.Consumer; @Component public class BedrockLanguageModel { @@ -36,33 +37,7 @@ public class BedrockLanguageModel { public String generate(String prompt, String imagePath) { System.out.println("DEBUG: Generating response for prompt: " + prompt); try { - ObjectNode requestBody = objectMapper.createObjectNode(); - requestBody.put("anthropic_version", "bedrock-2023-05-31"); - ArrayNode messages = requestBody.putArray("messages"); - ObjectNode message = messages.addObject(); - message.put("role", "user"); - requestBody.put("max_tokens", 20000); - requestBody.put("temperature", 0.7); - requestBody.put("top_p", 0.9); - - ArrayNode content = message.putArray("content"); - - if (imagePath != null && !imagePath.isEmpty()) { - byte[] imageBytes = Files.readAllBytes(Paths.get(imagePath)); - String base64Image = Base64.getEncoder().encodeToString(imageBytes); - - ObjectNode imageNode = content.addObject(); - imageNode.put("type", "image"); // Add type field - ObjectNode imageContent = imageNode.putObject("image"); - imageContent.put("format", "png"); - ObjectNode source = imageContent.putObject("source"); - source.put("bytes", base64Image); - } - - ObjectNode textNode = content.addObject(); - textNode.put("type", "text"); // Add type field - textNode.put("text", prompt); - + ObjectNode requestBody = createRequestBody(prompt, imagePath); String jsonPayload = objectMapper.writeValueAsString(requestBody); InvokeModelRequest invokeRequest = InvokeModelRequest.builder() @@ -100,4 +75,77 @@ public class BedrockLanguageModel { return "Error: " + e.getMessage(); } } + + public void generateStream(String prompt, String imagePath, Consumer chunkConsumer) { + System.out.println("DEBUG: Generating streaming response for prompt: " + prompt); + try { + ObjectNode requestBody = createRequestBody(prompt, imagePath); + String jsonPayload = objectMapper.writeValueAsString(requestBody); + + InvokeModelRequest invokeRequest = InvokeModelRequest.builder() + .modelId(modelId) + .contentType("application/json") + .accept("application/json") + .body(SdkBytes.fromUtf8String(jsonPayload)) + .build(); + + InvokeModelResponse response = bedrockClient.invokeModel(invokeRequest); + String responseBody = response.body().asUtf8String(); + System.out.println("DEBUG: Raw response from Bedrock: " + responseBody); + + JsonNode responseJson = objectMapper.readTree(responseBody); + JsonNode contentArray = responseJson.path("content"); + + if (contentArray.isArray() && contentArray.size() > 0) { + for (JsonNode content : contentArray) { + String chunk = content.path("text").asText(); + chunkConsumer.accept(chunk); + } + } else { + System.out.println("WARNING: Unexpected response format. Full response: " + responseBody); + chunkConsumer.accept("Unexpected response format"); + } + } catch (Exception e) { + System.out.println("ERROR: Failed to generate streaming text with Bedrock: " + e.getMessage()); + e.printStackTrace(); + chunkConsumer.accept("Error: " + e.getMessage()); + } + } + + private ObjectNode createRequestBody(String prompt, String imagePath) { + ObjectNode requestBody = objectMapper.createObjectNode(); + requestBody.put("anthropic_version", "bedrock-2023-05-31"); + requestBody.put("max_tokens", 20000); + requestBody.put("temperature", 0.7); + requestBody.put("top_p", 0.9); + + ArrayNode messages = requestBody.putArray("messages"); + ObjectNode message = messages.addObject(); + message.put("role", "user"); + + ArrayNode content = message.putArray("content"); + + if (imagePath != null && !imagePath.isEmpty()) { + try { + byte[] imageBytes = Files.readAllBytes(Paths.get(imagePath)); + String base64Image = Base64.getEncoder().encodeToString(imageBytes); + + ObjectNode imageNode = content.addObject(); + imageNode.put("type", "image"); + ObjectNode imageContent = imageNode.putObject("image"); + imageContent.put("format", "png"); + ObjectNode source = imageContent.putObject("source"); + source.put("bytes", base64Image); + } catch (Exception e) { + System.err.println("Error reading image file: " + e.getMessage()); + e.printStackTrace(); + } + } + + ObjectNode textNode = content.addObject(); + textNode.put("type", "text"); + textNode.put("text", prompt); + + return requestBody; + } } \ No newline at end of file diff --git a/src/main/java/com/ioa/service/WebSocketService.java b/src/main/java/com/ioa/service/WebSocketService.java index 60fe75f..28fdd59 100644 --- a/src/main/java/com/ioa/service/WebSocketService.java +++ b/src/main/java/com/ioa/service/WebSocketService.java @@ -1,81 +1,17 @@ package com.ioa.service; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.JsonNode; -import com.ioa.conversation.ConversationManager; -import com.ioa.conversation.Message; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; -import org.springframework.context.annotation.Lazy; -import org.springframework.web.socket.TextMessage; -import org.springframework.web.socket.WebSocketSession; @Service public class WebSocketService { private final SimpMessagingTemplate messagingTemplate; - private final ConversationManager conversationManager; - private final ObjectMapper objectMapper; - @Autowired - public WebSocketService(SimpMessagingTemplate messagingTemplate, @Lazy ConversationManager conversationManager) { + public WebSocketService(SimpMessagingTemplate messagingTemplate) { this.messagingTemplate = messagingTemplate; - this.conversationManager = conversationManager; - this.objectMapper = new ObjectMapper(); - } - - public void handleMessage(WebSocketSession session, TextMessage message) { - try { - String[] messageArray = objectMapper.readValue(message.getPayload(), String[].class); - if (messageArray.length > 0) { - String content = messageArray[0]; - // Assume we're using a default conversation ID for simplicity - String conversationId = "default"; - // Assume we're using a default user ID for simplicity - String userId = "user"; - conversationManager.postMessage(conversationId, userId, content); - } - } catch (Exception e) { - e.printStackTrace(); - } } public void sendUpdate(String topic, Object payload) { messagingTemplate.convertAndSend("/topic/" + topic, payload); } - - public void handleWebSocketMessage(String message) { - System.out.println("DEBUG: Received WebSocket message: " + message); - - // Parse the WebSocket frame - String[] parts = message.split("\n\n", 2); - if (parts.length < 2) { - System.out.println("DEBUG: Invalid WebSocket message format"); - return; - } - - String headers = parts[0]; - String payload = parts[1]; - - // Parse the JSON payload - try { - JsonNode jsonNode = objectMapper.readTree(payload); - - // Extract relevant information from the JSON - // Adjust this based on the actual structure of your WebSocket messages - String conversationId = jsonNode.path("conversationId").asText(); - String sender = jsonNode.path("sender").asText(); - String content = jsonNode.path("content").asText(); - - // Create a new Message object - Message parsedMessage = new Message(conversationId, sender, content); - - System.out.println("DEBUG: WebSocket message: " + payload); - // Process the message - conversationManager.postMessage(conversationId, sender, content); - } catch (Exception e) { - System.out.println("DEBUG: Error parsing WebSocket message: " + e.getMessage()); - e.printStackTrace(); - } - } } \ No newline at end of file diff --git a/src/main/java/com/ioa/task/Task.java b/src/main/java/com/ioa/task/Task.java index c6457fa..e18c84f 100644 --- a/src/main/java/com/ioa/task/Task.java +++ b/src/main/java/com/ioa/task/Task.java @@ -1,11 +1,8 @@ package com.ioa.task; import com.ioa.agent.AgentInfo; -import lombok.Data; - import java.util.List; -@Data public class Task { private String id; private String description; @@ -14,10 +11,28 @@ public class Task { private AgentInfo assignedAgent; private String result; + // Default constructor + public Task() {} + + // Existing constructor public Task(String id, String description, List requiredCapabilities, List requiredTools) { this.id = id; this.description = description; this.requiredCapabilities = requiredCapabilities; this.requiredTools = requiredTools; } + + // Getters and setters for all fields + public String getId() { return id; } + public void setId(String id) { this.id = id; } + public String getDescription() { return description; } + public void setDescription(String description) { this.description = description; } + public List getRequiredCapabilities() { return requiredCapabilities; } + public void setRequiredCapabilities(List requiredCapabilities) { this.requiredCapabilities = requiredCapabilities; } + public List getRequiredTools() { return requiredTools; } + public void setRequiredTools(List requiredTools) { this.requiredTools = requiredTools; } + public AgentInfo getAssignedAgent() { return assignedAgent; } + public void setAssignedAgent(AgentInfo assignedAgent) { this.assignedAgent = assignedAgent; } + public String getResult() { return result; } + public void setResult(String result) { this.result = result; } } \ No newline at end of file diff --git a/src/main/java/com/ioa/task/TaskAssignment.java b/src/main/java/com/ioa/task/TaskAssignment.java new file mode 100644 index 0000000..9d5788d --- /dev/null +++ b/src/main/java/com/ioa/task/TaskAssignment.java @@ -0,0 +1,14 @@ +package com.ioa.task; + +import java.util.List; + +public class TaskAssignment { + private String taskId; + private List agentIds; + + // Getters and setters + public String getTaskId() { return taskId; } + public void setTaskId(String taskId) { this.taskId = taskId; } + public List getAgentIds() { return agentIds; } + public void setAgentIds(List agentIds) { this.agentIds = agentIds; } +} \ No newline at end of file diff --git a/src/main/java/com/ioa/task/TaskManager.java b/src/main/java/com/ioa/task/TaskManager.java index 979026f..49d3fc1 100644 --- a/src/main/java/com/ioa/task/TaskManager.java +++ b/src/main/java/com/ioa/task/TaskManager.java @@ -1,37 +1,84 @@ package com.ioa.task; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Component; import com.ioa.agent.AgentInfo; import com.ioa.agent.AgentRegistry; import com.ioa.conversation.ConversationFSM; import com.ioa.conversation.ConversationManager; +import com.ioa.conversation.Message; import com.ioa.model.BedrockLanguageModel; import com.ioa.service.WebSocketService; +import com.ioa.team.TeamFormation; import com.ioa.tool.ToolRegistry; import com.ioa.util.TreeOfThought; -import com.ioa.conversation.Message; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; @Component public class TaskManager { - private Map tasks = new HashMap<>(); + private Map tasks = new ConcurrentHashMap<>(); + private final SimpMessagingTemplate messagingTemplate; private AgentRegistry agentRegistry; private BedrockLanguageModel model; private ToolRegistry toolRegistry; private TreeOfThought treeOfThought; private ConversationManager conversationManager; + private WebSocketService webSocketService; - public TaskManager(AgentRegistry agentRegistry, BedrockLanguageModel model, ToolRegistry toolRegistry, - TreeOfThought treeOfThought, ConversationManager conversationManager) { + @Autowired + private TeamFormation teamFormation; + + @Autowired + public TaskManager(AgentRegistry agentRegistry, + BedrockLanguageModel model, + ToolRegistry toolRegistry, + TreeOfThought treeOfThought, + ConversationManager conversationManager, + WebSocketService webSocketService, + SimpMessagingTemplate messagingTemplate) { this.agentRegistry = agentRegistry; this.model = model; this.toolRegistry = toolRegistry; this.treeOfThought = treeOfThought; this.conversationManager = conversationManager; + this.webSocketService = webSocketService; + this.messagingTemplate = messagingTemplate; + } + + public String createTask(Task task) { + String taskId = UUID.randomUUID().toString(); + task.setId(taskId); + tasks.put(taskId, task); + messagingTemplate.convertAndSend("/topic/tasks", "New task created: " + taskId); + + // Automatically assign agents and execute the task + List team = teamFormation.formTeam(task); + if (!team.isEmpty()) { + executeTask(taskId, team); + } else { + System.out.println("No suitable agents found for task: " + taskId); + } + + return taskId; + } + + public void assignTask(String taskId, List agentIds) { + Task task = tasks.get(taskId); + if (task != null) { + List team = agentIds.stream() + .map(agentRegistry::getAgent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + executeTask(taskId, team); + messagingTemplate.convertAndSend("/topic/tasks/" + taskId, "Task assigned to: " + String.join(", ", agentIds)); + } } public void addTask(Task task) { @@ -54,9 +101,13 @@ public class TaskManager { conversation.postMessage(new Message(conversationId, "SYSTEM", "Let's work on the task: " + task.getDescription())); - // Allow agents to interact for a maximum of 10 minutes + // Use the LLM to generate a plan for the task + String planPrompt = "Generate a step-by-step plan to accomplish the following task: " + task.getDescription(); + String plan = model.generate(planPrompt, null); + conversation.postMessage(new Message(conversationId, "SYSTEM", "Here's the plan: " + plan)); + + // Allow agents to interact for a maximum of 40 minutes long startTime = System.currentTimeMillis(); - //while (!conversation.isFinished() && (System.currentTimeMillis() - startTime) < TimeUnit.MINUTES.toMillis(10)) { while (!conversation.isFinished() && (System.currentTimeMillis() - startTime) < TimeUnit.MINUTES.toMillis(40)) { try { Thread.sleep(1000); // Check every second @@ -72,8 +123,10 @@ public class TaskManager { String result = conversation.getResult(); task.setResult(result); System.out.println("Task completed. Result: " + result); + messagingTemplate.convertAndSend("/topic/tasks/" + taskId, "Task completed: " + result); } + public Task getTask(String taskId) { return tasks.get(taskId); } diff --git a/src/main/java/com/ioa/task/TaskResult.java b/src/main/java/com/ioa/task/TaskResult.java new file mode 100644 index 0000000..6600720 --- /dev/null +++ b/src/main/java/com/ioa/task/TaskResult.java @@ -0,0 +1,31 @@ +package com.ioa.task; + +public class TaskResult { + private String taskId; + private String result; + + // Constructors + public TaskResult() {} + + public TaskResult(String taskId, String result) { + this.taskId = taskId; + this.result = result; + } + + // Getters and setters + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } +} \ No newline at end of file diff --git a/src/main/java/com/ioa/tool/ToolInfo.java b/src/main/java/com/ioa/tool/ToolInfo.java new file mode 100644 index 0000000..b796f33 --- /dev/null +++ b/src/main/java/com/ioa/tool/ToolInfo.java @@ -0,0 +1,29 @@ +package com.ioa.tool; + +public class ToolInfo { + private String agentId; + private String toolName; + + public ToolInfo() {} + + public ToolInfo(String agentId, String toolName) { + this.agentId = agentId; + this.toolName = toolName; + } + + public String getAgentId() { + return agentId; + } + + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + public String getToolName() { + return toolName; + } + + public void setToolName(String toolName) { + this.toolName = toolName; + } +} \ No newline at end of file diff --git a/src/main/java/com/ioa/websocket/AgentProcessingUpdate.java b/src/main/java/com/ioa/websocket/AgentProcessingUpdate.java new file mode 100644 index 0000000..63d5954 --- /dev/null +++ b/src/main/java/com/ioa/websocket/AgentProcessingUpdate.java @@ -0,0 +1,16 @@ +package com.ioa.websocket; + +import lombok.Data; + +@Data +public class AgentProcessingUpdate { + private String agentId; + private String responseId; + private String status; // "start" or "complete" + + public AgentProcessingUpdate(String agentId, String responseId, String status) { + this.agentId = agentId; + this.responseId = responseId; + this.status = status; + } +} diff --git a/src/main/java/com/ioa/websocket/AgentResponseUpdate.java b/src/main/java/com/ioa/websocket/AgentResponseUpdate.java new file mode 100644 index 0000000..04b31c4 --- /dev/null +++ b/src/main/java/com/ioa/websocket/AgentResponseUpdate.java @@ -0,0 +1,16 @@ +package com.ioa.websocket; + +import lombok.Data; + +@Data +public class AgentResponseUpdate { + private String agentId; + private String responseId; + private String chunk; + + public AgentResponseUpdate(String agentId, String responseId, String chunk) { + this.agentId = agentId; + this.responseId = responseId; + this.chunk = chunk; + } +} diff --git a/src/main/java/com/ioa/websocket/ChatController.java b/src/main/java/com/ioa/websocket/ChatController.java new file mode 100644 index 0000000..ff461de --- /dev/null +++ b/src/main/java/com/ioa/websocket/ChatController.java @@ -0,0 +1,50 @@ +package com.ioa.websocket; + +import com.ioa.conversation.ConversationManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.messaging.handler.annotation.SendTo; +import org.springframework.stereotype.Controller; + +@Controller +public class ChatController { + private final ConversationManager conversationManager; + + @Autowired + public ChatController(ConversationManager conversationManager) { + this.conversationManager = conversationManager; + } + + @MessageMapping("/chat/create") + @SendTo("/topic/rooms") + public String createRoom(String roomName) { + String roomId = conversationManager.createConversation(); + return "Room created: " + roomId; + } + + @MessageMapping("/chat/join") + @SendTo("/topic/rooms") + public String joinRoom(String roomId) { + conversationManager.joinConversation(roomId); + return "Joined room: " + roomId; + } + + @MessageMapping("/chat/message") + public void sendMessage(ChatMessage message) { + conversationManager.postMessage(message.getRoomId(), message.getSender(), message.getContent()); + } +} + +class ChatMessage { + private String roomId; + private String sender; + private String content; + + // Getters and setters + public String getRoomId() { return roomId; } + public void setRoomId(String roomId) { this.roomId = roomId; } + public String getSender() { return sender; } + public void setSender(String sender) { this.sender = sender; } + public String getContent() { return content; } + public void setContent(String content) { this.content = content; } +} \ No newline at end of file diff --git a/src/main/java/com/ioa/websocket/WebSocketHandler.java b/src/main/java/com/ioa/websocket/WebSocketHandler.java new file mode 100644 index 0000000..5f8d96f --- /dev/null +++ b/src/main/java/com/ioa/websocket/WebSocketHandler.java @@ -0,0 +1,91 @@ +package com.ioa.websocket; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Controller; + +import com.ioa.agent.AgentInfo; +import com.ioa.agent.AgentRegistry; +import com.ioa.model.BedrockLanguageModel; +import com.ioa.service.WebSocketService; +import com.ioa.task.Task; +import com.ioa.task.TaskAssignment; +import com.ioa.task.TaskManager; +import com.ioa.task.TaskResult; +import com.ioa.tool.ToolInfo; +import com.ioa.tool.ToolRegistry; +import com.ioa.util.TreeOfThought; + +@Controller +public class WebSocketHandler { + + private final AgentRegistry agentRegistry; + private final TaskManager taskManager; + private final SimpMessagingTemplate messagingTemplate; + private final TreeOfThought treeOfThought; + private final WebSocketService webSocketService; + private final ToolRegistry toolRegistry; + private final BedrockLanguageModel model; + + @Autowired + public WebSocketHandler(AgentRegistry agentRegistry, TaskManager taskManager, + SimpMessagingTemplate messagingTemplate, TreeOfThought treeOfThought, + WebSocketService webSocketService, ToolRegistry toolRegistry, + BedrockLanguageModel model) { + this.agentRegistry = agentRegistry; + this.taskManager = taskManager; + this.messagingTemplate = messagingTemplate; + this.treeOfThought = treeOfThought; + this.webSocketService = webSocketService; + this.toolRegistry = toolRegistry; + this.model = model; + } + + @MessageMapping("/agent/register") + public void registerAgent(@Payload AgentInfo agentInfo) { + // Initialize dependencies + agentInfo.setDependencies(treeOfThought, webSocketService, toolRegistry, model); + + agentRegistry.registerAgent(agentInfo); + messagingTemplate.convertAndSend("/topic/agents", "New agent registered: " + agentInfo.getId()); + } + + @MessageMapping("/tool/register") + public void registerTool(@Payload ToolInfo toolInfo) { + AgentInfo agent = agentRegistry.getAgent(toolInfo.getAgentId()); + if (agent != null) { + agent.getTools().add(toolInfo.getToolName()); + messagingTemplate.convertAndSend("/topic/tools", "New tool registered: " + toolInfo.getToolName()); + } + } + + @MessageMapping("/task/create") + public void createTask(@Payload Task task) { + System.out.println("Creating task: " + task.getId()); + String taskId = taskManager.createTask(task); + messagingTemplate.convertAndSend("/topic/tasks", "New task created: " + taskId); + } + + @MessageMapping("/agent/unregister") + public void unregisterAgent(@Payload String agentId) { + agentRegistry.unregisterAgent(agentId); + messagingTemplate.convertAndSend("/topic/agent/" + agentId, "Unregistration successful"); + } + + @MessageMapping("/task/assign") + public void assignTask(@Payload TaskAssignment assignment) { + taskManager.assignTask(assignment.getTaskId(), assignment.getAgentIds()); + messagingTemplate.convertAndSend("/topic/tasks/" + assignment.getTaskId(), "Task assigned"); + } + + @MessageMapping("/task/result") + public void handleTaskResult(@Payload TaskResult result) { + Task task = taskManager.getTask(result.getTaskId()); + if (task != null) { + task.setResult(result.getResult()); + messagingTemplate.convertAndSend("/topic/tasks/" + result.getTaskId(), "Task completed: " + result.getResult()); + } + } +} \ No newline at end of file diff --git a/target/classes/com/ioa/IoASystem.class b/target/classes/com/ioa/IoASystem.class index 727102019043ee7dc2d7135a59a990790f627e70..b340577fd5189d18ee3a49935f6357ff60182d3c 100644 GIT binary patch literal 4387 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 ph{;i@_F8Xehtx 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 Pl|1kc5($wMbFutUxR!R1 literal 5473 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 PpsZ+sf5e~hS9Jax2PWI_ diff --git a/target/classes/com/ioa/config/WebSocketConfig.class b/target/classes/com/ioa/config/WebSocketConfig.class index 1ea6b6a86a680c8a411ba13f6e3611e1be24581e..568c8a930fbaa6524f162b02dcad32f31dae11f5 100644 GIT binary patch literal 3804 zcmbtXYgZFj6x}zV!DQ+K1)o@{lqNi!YFld?Ujcl837|nJ+SU%?5(bi)>C6OVt^SPu zjDBf9=(4W%2lPjEb>EpuNLXW#3X9C#tb6x4XPnitahCX;s!-qb9d) zcT?Y%E4mk)ZvYyWW&4J2+SV?1QF@+HkrS@HDc#Ue-IcDu;hUyq`nLtTGTB9e?n!%9 zrqG47h9r6fjulKx&em%y(p@lCs#2i0V3&>RqT!lq9evsDubZC0r9$W6asvHf*tFi} zlfYD_5Eox9@SGv*o>_AmF}9t3A}glnyF0n;ViG6Y*em&ptse9-Qr)*5vz)?doK514 zz?}~?r{NsVlMiVrB1-hG8WAk8oOxc@&0*+8E_;9gTj8Skf|TZZFu*kFhU2J6KGtvv zg93w|^z)8WHOs-SDe3v96}-;7a?N}xnViKB^(mfoG8?8;Ab)@W-v!q12HBKu$+v6H zJ!{pmP0OeIkK*;wQU7fiEi&oBXH>kt?WK{$Xc8j=_v6%XaBvM{7#BzztE&y)1vcKF z`TZ>}HR?qJe~&zL0Wp%sReX`eHG$Iqi>sp*4PUAt&nVGVtM;~Bopa5KY0VqHFI|hQ zUd43{U*m>AYTNYJRe_r+3Cw2V??C6M)nTtB-7T{$+kzG73Dx562t14xUuWc2i8bXR zaBgpnV#VB&E@Pt(PiDfKUH8qZUSQ$LWuFNgDVY^sIF>bmxxG7X#=5p!*=R0=*P~m} zw3oY0^d#;IJc!FVf(@zE^$}U%4S5f$3NZ;~Xw_ z77BYcZ&#RScIWqoeYaXv_irB_sEBBQDC~*qgRYFg02$$M#p^g(H7VL@YsIcxtCQ;- zj%1bE-!HGN!$x$ft@Nl-gNeHlr}$m6y}IMruCGT3)4V`#SvtP$Cb7nGsq?fnbTtKu zbv22Zyc?PQhAXA%P1KTLfVcK>tYwyp2~UFsTR>yyZ8%Kj{lYf359~YRJ<#wI;}Nx^ zMYTQ{YdF5`=S$}h379I`b*AIKsm9t<&5p;*M(JEp*Hz%`le*=zcrBWq$tf@2oUO^n z^;i$6JYT-_^_DR_M6A2v1jhyud$41xx)%(YO&^P`^St6_n!0u;tA^*PQ7=8q0kA05 z)b3#rEHnH&#D78#@yWTKpGUaT`4sBgk=IE5&X)u90!OYk``+Wi-Lm%DmTm0qELsj<4i)y1V<(4+JLI8UGp{2d6u`$K>ToKW}#mkBR0 zgij+gtC5+Z2Jmp{4KfKtMz3)7c>-_nl|YNNUUbviAo_?nK+MZTRN;gchng0L@D08V zEaq^N-rVAz1a1cb{>nFnGW-^ImR}=Ze2WP_r)J0hz`a*^G&cSUbE9K#P)cB_>o@M~ z3g|mW0)Y%!&XTSXPU)kJc#Iy52R@91s7)V+N#!&8(1VM3j_+ypIQ{$qKN9Z+k-`+H zT|Wh$8d!8Cd;nvsBhi71gUm*-k8_Oj?U1_p8s;FDc zpXAS$6z1^AmQ7F>RIDQ;-!o^0V*W6MOM^|=rICnYSr>!d`pHP>-|93fb}O@AEc%yP zTw-|oz_@G=(k8gf`Kdz(oi<%Aak>?2Vs6nnb4vd;FCq@TBy5r{ee^4`)nZa_SaJPf z<>WsHOAUS2uwv7%m2%4gYqfB6TzV|)KgNyT3+(7?=jDn712UIlNQN{;Wj2W;l4V4d zXdrcmD$BtjCDAW~Lt3KyeSuNNBvXu6Oul(nK!#{MZ9QS{n$h~~EzWi=Ym%&ayUbOM z8kXkBn!-frqNzgnz6n*ju$W*{x+tcYmgx6culDh3`>0WLfin aY%lc>?(u^eff~$KOmobO`nCnppYR2?Yek3v diff --git a/target/classes/com/ioa/conversation/ConversationFSM$ConversationStateUpdate.class b/target/classes/com/ioa/conversation/ConversationFSM$ConversationStateUpdate.class index ee81057f56eda813e3210d088687d407e3547850..f00dd7ad24609b225d94210ce816c2ed6dbb1712 100644 GIT binary patch delta 471 zcmX9)%TB^j5IwgSXo0I#RElrVicns<7EKHrO^hy#E={U5T0&Yw8#XTd0XL*yVj_~b z@B=h4ZjJv!oR-bZnKN_F%)NigL{UE{?;ik;(3BxDw1PdZ2fCEc$%rwiU2|YId!}>O zJiqB$xBl=~4`gr|&Y9PD4dzpCQq*9os)-Fv}4aJhKCS9^qo}BQ=az+wE9M zFk}VN5Gimh2+UxSftM>+DQH-dkta{G3?=cnz%o{bZXwICCJ;v=ly3;gP=asv6-*>u z6(^2k_1itu^DIwBEokt{lh$^ffz|g+-*%k~-}J4^hYm#s<;?Q@W7qRhATLgD=ak8s z5DSedCJ9SOscLv<#DngfC2rcuKqc0rI!0MDsw2!9W6T@1H{?cGH6H6DtiMo?(-t5b z&ApPE20=3zqey%q+OJ^~TU3z~bZnDrh)Q$`#|~jZ7fqS)%Q(tZNvOb}oT45>6?I}7 H5nufW^Mgr* delta 428 zcmX9(%TB^T6g@KqT1tU}BKSaxRvs1qz-SB`UHC|Rtc*!bCy_*3Lnm&D8~08Bz{dx; zKob{!fPRAiLcE1p+;eiyy>srJXn$JuXY%z8U=KYV9EysRfiyDFaiyNw9{2;f!=QA! z7dkX#Rp;A9y0Z zM>Qt=}1D&=A1xv(y>P!)qolh{Q_W^Z` zyt6gN+&ifXmJ@F@ZF#2p0t2t~@f%jiu&9A-)UisKum)*Kd>Ks&Rj@|fm_{Z_jg)m# g@-$|eL}qWcnN8*f2^=l7r`Ul*sDo*AR0o^j|0KIUDF6Tf diff --git a/target/classes/com/ioa/conversation/ConversationFSM.class b/target/classes/com/ioa/conversation/ConversationFSM.class index 734d2c7a27c943e460455ae527ca24143ea93349..7a59bf4c34054b4aadff6f9a7049eaf8e8e4f44c 100644 GIT binary patch literal 8733 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 diff --git a/target/classes/com/ioa/conversation/ConversationManager.class b/target/classes/com/ioa/conversation/ConversationManager.class index 26669a30f937ee6296c3e467c68962e1a8320140..fb96b7755c1787975f81a653416cc8070b4b5f3f 100644 GIT binary patch literal 3311 zcmbtWYf}?f7=D&S6V@eaKrRY4Dpd%Vtu5XNqKH~)2`UjRz1bx>z(TT{?r!k%EBaIH zj6y9lZ9n;;zp2ydb9R?xfq0qeFeH1m;MlscY3OCcTGj6_uZyCmpe<_XDmXgppQ(9fS%V^vCM zw6}r;H5|fW`E*J{D^&T^r{M@RnPSrtbG6E{a2^?CuOK~Z7mf0w;h1tAZpOVeli_6R zibN}=S&1=#bkPxpC&;T_j0!pi1`pPWicfJNf%6JdjnEbrW^QX3z@P%vF|3kZkvoLl zMexf~?&YNYkcMHLQ;_uRp!yORWj%dN1*#aqXHw*peEM9&7Z{^cSt_PcHeXPb69WfX z4=x_TWn4|*3OlF4o62jrhH)mWT4PgPjhY6XmWzOeJ5g1_EvgY!d8Qs$Pa#Oj#Ead^uTaDvuIWgi9gx|tqw-9I7p`C=Zv*tlckL52MyoiN6OHM z>EJ<*aDS82=ACc~jys}aZ;A*b>7b~=kPeQ!9;xn){sSctNz^LEYt+Ua$FZFxOa3V8O};o#R@iLEsSwu>`UalaBJoLEwxMkU|UOFYzm?z;V=!`0q;boIq zv1=BqNG;ekrzq~4a*TIJPlfmXsMJSJ@n)Bj>j_8L-t(&9Jg-!3i&c=r8Qv8!{>F$Q zEiVzS5?r+)$u+MMKBwhH!f$!2aD?*RQLg04WBfkO|20}mjFZ`Iq_aCXv9yh@*XYg; zz2@HVYxMrgw=Fo$&rW&)IuIwyQC?sj-049VKH+XAK;icpu88L|Q2Zy!p@lxr;v7Gv z*Js3#UbDZUe~U5iU}P!#iVk0)cN=D8S5$f?&V(} zZ=%x?7TJ(Rg8p)tpwBL}<2ojN7B?^!vZ#fz_xYaQ;ARW{!bpDjE!rfJ^lh@ZE5ncZ z;ipL&3?fC?G;g(DT!=XBtB2kfI!#fe!09aQl2HCZZ-S+xa170b6n(g$caod&vg&buZoZ2)pqFKM_C0!k2Ny8gX?6aTy=WV|hQ138G#n zk4f^l`M-ITAVNLH!U9xxu(Fh1+s68zR3|9&K-+u1H_g{s4Wm|2MkPdWcsgib*(}i# xPEt_oW%_5Ct!Vu|WGwTHrNCGgeDs5@8#GOdZM(02eI;Aq`Yb)xP%untz<(5z6mkFn literal 5185 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 diff --git a/target/classes/com/ioa/conversation/ConversationState.class b/target/classes/com/ioa/conversation/ConversationState.class index 4396d11e218516a58da27f802695c7fb070e4e3f..58fd8c30c9d2970d24dab53ad1d9c592f4dbeac0 100644 GIT binary patch literal 1508 zcmb7@ZEq4m5Xb*pCkGek;Wn z8jZ%+ekkM2f-Q+Lsk~tJw>vXC^S{}jzrK72P{0!nLjqT7&7G{@bhEW)W7li7-N0`) zvgQEDzzsYNVS&+Ych}9<-NshdYIJr4^u?kyt5O!rwm_ zs1)Q=fun3TmJ5{?YprN6ZxrpNvOu_Z7*~hSN(I}dGl4P11u9_KUbXCsK+Jk>nbnFa zNH@#2S*rG`8?o%_>ZSEUscK1q^o#!}Heajz4L_I{2&K~NRE*ht z@_m}-0iio03&1jb9vnp?HOs5VnmX18;H9QnZ42ZDT4!j)$kFY@B$8ELTy;}3_oYp5u(78;PFhY$EoJ zZVq)ZA)Rm+Q_>mk;;eKcU0jfk*2QJ%M7u~yCqY}&WN2@O3~kQJkC^*F)eqq|{b%UW zaDQ=9Y?6AuN{Zd0ZVU9XY&v^M?`WHz&pT4~j*8+)ddPh(W@(=_*D}*npK$jeafBSu z4>HtR!#x(265q#ze)t`_mcx@>%sEd(neR@XTU!mC`i$JQ_jJ-LvzJZmmk^@@ANO-) b$cOLJ$3^Bd%pVZ{jvK;~%DIdcWsAQ7rqV*m literal 1465 zcma)5ZBNrs6n^gB+STIbkO_!yfUtowry$BEGRByTqa$`(Tr?qNR4CcnWb63szwmG9 zNQ7uKeD+5f&%MkzgC=Xzo<8U0x%WKx+#f%`d)uSw)aD43{(d%bk3t{37?NpyhW8 z+GdHzFR4&@+{feGaal!(JBCETb}^%Al+PnqR77|rBqABwOAPb$VfB{dp}XyJv8fXO2HJSCEQgpgIVhAPeRV_G->@KqtP)-?--V1ebw29 z(Qc>u9J<@G?EO^#3Yo*|I7Y|C9`i1t(UDhu(d48KCH$7KX%s4_w_A~Hr~ zjB@vqipN;yiij<>8RlbyYeK94F7subJ(43-v}{xBG_}v1?(hU)oZi29M z0feP-7nVj_SQ=&^JkF<=82nWC1k1$tl+Ywu{wQ6Hea4M5-26z0VTHZ{5%W_13{voj z{6(_7LW!`sQ%s(L@qEu;`DyZ~=UI4$RYK3{^;6k=XU| zk4eHB??NyIJ=6~U)0+_`>tTftA}z^VD!@lyAQ_gvfz`ZSc=ejE3rVl}yQFq4(8Z8m zle!4&HMxsny%r`{RKM7{j4alBv>$r3^{+%4x#vB>{bP6qSnvrT36Ss$pa}3FAi$6S zNlAdP01ssWh6Q*OKF^DuV(}PbT!`}{n1oFKJ`B;ZjgtVgkg!O;3>}IF1#d||Pfvvn JZ0#60NeoAaB#E-%y|g z5v`+D`~E{epdh+$Mk=Jm+m)qoGGM5Y1FLs0{MsG`blbd&CpGBAbd_G3+`yy(}FMpi>cT=I-A|Ku31 zv%BI-Ns4EFp#@dU`%w@pd{t~J^?kA;4F#t3A!JGyHy2q|rN4Lxawi9T}6V~6|Mk$>5feQb{$=_kkjB`1E!JMJ8`L90`xy>w_T z9Yh|G1b(GVcPR;qNqWQ-O)~jM*6dBBV8)$$7IT#SG_6Hn9!09;Q!HQ+ONf61Nu@)P delta 604 zcmZvYyGjE=6o&uV$zHN<%yo^qm?&s2o5VydL=2+V7TWj%nj#_*G=*KP?Ure5^cfU3 z2r0A|d8C8% zm=U+Et87%nD_azAEa^TQ?#G=7DNSymB*J_>9@S7WQH7(UCXu?>RLUyDO=VA9@q)Nk zF2y!KIWTBgfRho8Ls>#j;YYHjsDjZ+(>+VCQ|b;;OgWEWPHhO?sSgox8bib$sIDL* zzIbksrQ8{JB8NP^i18hmpGgnto01EXJHs3bzaCABvP*S5==YS6DBYT0j6zCV_PEMrf1N0b<1>y8Wc;OFj`+Lw2I$n$Z#iMWW5E~&01f}x-q!Mxqv9H>8 SnYLO&gZ48iTSg13$ov3MkUp*e diff --git a/target/classes/com/ioa/model/BedrockLanguageModel.class b/target/classes/com/ioa/model/BedrockLanguageModel.class index 752c35bdd5a273a5e46d42564105293664df94ff..aa0f0b9f315ba9bd83f84fc6a9681c7b5c2434db 100644 GIT binary patch literal 8750 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 P`e>%ZNkN)TbKw6E>7Baa diff --git a/target/classes/com/ioa/service/WebSocketService.class b/target/classes/com/ioa/service/WebSocketService.class index a8718c23e91dbf6fe2f84e018d868ec18dde46bb..36e70d6dccffae39e0e8bc957de41f0bc523792d 100644 GIT binary patch delta 505 zcmYL^O-~w86o%hBz@3@v;2^D70jY{3U$)~%?FJ+gB8f>8<3jhS#DEB<&~E(;HFw!x z(WD=V3wOGxzrdaUqlxilXxf{cd(OG{J3PV0Dh)!ugmWTo9}532%OdfQ6q^N5!%914W%{gakL2onxWP#4M<4s8fb zI*35(+sJ{wlbb5eMhOQqc%{FH9hpShL`px3a>T(LGCF0H^&eT)Da+GInP!iQrBFc0 zL{U%MIm%|RqAT{-oGX#H;0sv(uz%4$_Jx46+v~MH*1OHYpfxbDF5u~!?MV~w1nD(9 zbIBDx^!sO@F0jDyLYzk+KAMq{!Ptbw+h*2aZqTdZFIwpbqTd3I%X>1YR0v~&S_d({ zCB|w@kvBRjpbFAn;N@TD{v``XP2J*mL`&D023CGz_CHw#6qg-h0d;;X|3`K48uO$P l!3`Fv4kOFVz!E%q$-ia#9Bs788`@i}GE#*=O(TKk5Jg literal 3403 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 L6oNPwSLww+8Ek|6 literal 4771 zcmb_g-E$jP75}Zg(yru{EIYQ-P14d2H?d{A3ZxK_lhD-7hd@r!*rd=ex|TQg#){UF zR)O$YC@nL*08exnUKnPYm&^b&I4~WCftNDFBTvlm#1sESO8K3=D`_QfGAYB1w0rJ3 zzjN+6=bn4+mHzgh_x}XoG=7*v3L^$|3u$CD6t6iqopQrzZk8{uUvuk$hRg}C=>?}W zjLgnm$-+d|K+eJ_EDhsz|9aW;opRu`x65mMXh?Y*8YXIeL#si{Yi=%yYQe&o=#6f; z?Rv}G2|T|k{Ba8t*r#E#<=*IcEq7zt*>Tprh8K8ln_ekvoxp39YhF7DZB1F27M*-o zXU+E;ZL#)<1sew_aoTNfv*~V}-gKLc#IAMSb%aq4+12J%KeTtq!lU9_rscLfjUY!u zpRn*ap3q>{o#vSv9jBpTYBm;`O3~8X%L0DN!VI3)klu8IDpN2yI~RjSNsx3Ou`nxE zGmO<~v_-dMVP13#)P13!8WAm8cm`z+`zgAdn4O94ME(4T;wLS9N)(GR#V|!8eAdFJ z@fjsNJ(#6~G~FYXy;O7fJf1Uf+QRc# z9w;xB5Dmsnr_pgQUe$0oDYbi3IKjd_W8o~$F)7!bZFkvk)}7!bFW|h*cHlGvmdu-R zV^Q+=+WLQS5>}cCT4nJ$L8rxB%&3`qD|BM-%%_$#ockDF_iQZ<*r|Ke?8qv zU3X}QS8mnswCe6zPxe(-PQPd5)Z_X- z@B2YJXgND8Zm{KVv`u_N!)t<=^)^mw3y;U#l3|itaenBQFb3RG2yyGAHaC{Rw{rM4 zzGL9K(jDJq)9IhVUh}5E?Ut42s$rgW>Ve<7rQzN9HjaSG@AFP`qv5t^YQDeS*@^m0 zcsYo+Qml&&D6X+dB*0&Z;k##Nj1`$!b{dUUFL2pA{D!BV9r4@V?I{{YmM}=@|XG zH(z=WY5mUpUts5)70e}=iTP`Zo9!Xb$#FD&p;(HH-UQCt52?=XJV_2TRNuF6ZVvhU$Fyw0pm z;otZwyIzWY>K}N6yb+Y}cQ~YUoWm~GNu{|vevLY*3>x?eHb@z0;YV;unfNKTag|gS zKO<+8R1SA}Om2}H#UJq;JW>|^$(6cBDvy8RAa!16CvMQ+8m0{M9tsA`4>4^Z#gD0d zh({Ee{a7UZ=I=^X5o{j(&CD6nQVNoq`)&Ge&n1)zk<@7Nn@gEVou^)w+V2&YPUt7Y z@;Ovo+G6pT#rfMX7Vo0+hVbVqx(IANl9*CbO0-Z(hay%}sASsduIOkb6N)lD5o=6o z9jh3jh~*V&8C}uwiW!Q`o`^+9twYHr@T!U+DuEIF3fIwOd};iWzs;MBFvmmHXY3<* z3U6VDl#Wwe#2cj2Y%D8Waw&m;r$U>QfgfW(M^XY@M(s&hACaLOFg1-!2Tl8k#`@!w zFs6|10=gJ|kQKo)F<2it%#FatAh?fD5JW2G9+kdUvMf^Me>5sU;^Ut%US0meNfuL` z`R?@2vlp35xey$Yf|BClci|5>#n(~wI;LL7-^UBU@QJ6+2z3q|=`HKcu*koLuk&rv U{5Sc%h3|2cBlUg!0Pn#5FaAr$KmY&$ diff --git a/target/classes/com/ioa/task/TaskManager.class b/target/classes/com/ioa/task/TaskManager.class index d00726a33a917b001e642199890d4d54078bcbf4..16900f283490a6bae7d231c8dced028313135517 100644 GIT binary patch literal 7673 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 delta 2212 zcmY*aX>?OX6#k}JCV8EvNxJb^Q*29{QiGyYQ?0EPq_qX1wNMr0Q66n*nn2zwid*z3 zdfcsp8}2LO3TOi@BJQ{g?#nrPJpRyMdi>!z>hXwoUXe<2GBbB(?!Di=-<_L38#d20 z-}`6m6#&inRzn_K9Bu&*ybQs0#zrHSG*W%B#jDquy*7jQv_vXlH!`@YYq~jn3?b*z zkex`z78+K6hp}D*hs%$A2#x}Q016o<$*bLyh8rhqYCj|pM$zyua~!EepcG|tI*U1? zE-)EWWCyEr#AyQ4F+*N@lnSQiZp zo<7rVUBggZUDG}hOQ)Slr1~22QH$9ebpppD#!xU32gM-o^E7Mf#t8x^Vy>Lzk461B z8S^;m1x~@K$7H8-lVzKOl$7)k<*1}x{=kd!8^V;-27%LXy8Od4KmQCgaWo5@i5B@C zFAXs8^#sIDrbwk)8ihrnZVmIXfa7d|g({|M87e5R>M&A9pP69@_hwAPHe1rEjb_F& z>_j@H6xsyNLA(4(ESb6pi#g5}Sc0Vtfr*IP6P7KT3aa8=IFF-SU>TN^y@?C0wwW>P zG&$k@hPBANgyJBI&(B8}&KI}<7s~4jBJP!pnEI`_ET~}>435T>WWsXLwJ8*v1TIyNuJPk?T)}ar zKo(cY1;L0M2+r%K&1(fV<2nYPo&L{^ySlBW%|lGl$Mv&@8*vlI%>uXJ)?+B{>ZjaO zq#i42n(G;q9zB5D<*$Y1Gc??WI|QV9G=&bSowm_C(3LTIO&{)*`-5f8t8ll#J!qkH ztaWfI@LL7$Q$+izP?wt4P|{XOdO+Yob#9H(-* zucz$QW8xiuBn(Y5#b?SvFYl7G9ZK0mLU+PStWKKEsZ`o_>d=z);UC8YRor>7~W<;TjN0<*E$;G8pLxo-()Nlx&aD1ws$!9Vfp5>Q zY$J)hIaryqQfO5~wWxVDMeQh}E-agX zrJ6cWMUZAW?n}q-A9WwZ(|Cr=F+7Xs=!_D z5C?K-+?l2GNDgPk-D;t`b7+lwW{;wSA@0?^qv&L~7rI*YFfy?s&UKH@bGT^R;U9I+ zUYI?)JKR^7Lt+d`U^fPHSic8$y;t|-aLHEGkWlJ1cj2;PT%E%;Tkc0`F|OZ(8@3(( zKA!dIz8r?P9sc~tbxrq#x8!h_67P-s>eTW51X=fu;h}NN6zCRg#RK$a-B7%(bSflD z6{MJ$P5G{)jL)IJl@l`vdAh+#!-E~z=@iVNqf8vaF1$$aDDQX)Bg933Y$$eI z1ZF$geUTu~rRK03d&t5jWS3(UV?@?Isun88u`52kSJ z=UBzj^%rLRjcM*)j@$f!BTwfwQhlAgjz5SqNnKS>;FvntK|6U)>UzD7r$zrOtiaK5 u0!PAe<4s55Exb*$(l|i#JM=52z&rshOwro_ diff --git a/target/classes/com/ioa/team/TeamFormation.class b/target/classes/com/ioa/team/TeamFormation.class index e3c2e2eb0f7f571fdea38bdad62c019a00c8b842..45a41aefcdb6072dfd55425303b850a554393c61 100644 GIT binary patch delta 3826 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 diff --git a/target/classes/com/ioa/tool/ToolRegistry.class b/target/classes/com/ioa/tool/ToolRegistry.class index d424916c0ffc685dc5697e7146e86915191a5c92..2fc2ba2d857b55f81bd127298b11c08654a545c6 100644 GIT binary patch literal 1546 zcma)+ZBNrs6vzK}4@|mlFc1__d<3?ER1py!Vt~Y$I3ZzVM&6Zq9T&ECY40@qPQK7Y zL(s(d+7D$sx9zsF&BQnD?&&$d^FI%FzyEyy31ADG2}BsCDt6rvwrNP)t{DgP*ymN@ zN~e`TjA8V|{9qb2)2bSKM<=`@8RE**Wf&=X-zT2!Hap%B1s*#|vqFpg-Wz!Mr92jHrSWqc5{aV^xAVs?4b%aP%I72r3 zU$x}QNlfEf0y7M$u3!?Y<2q)kzDAR}xgMtZEiQ!kfhE^(qSjbu-7Bm+qoB3)O$~`* zyuUCiC{g9ouVo>eJqXSXh*71?>sUaRbW=3Ld^qyoDig@ly!s|h8jelZ*Dw(#wKW{7 zjLSL<+-FEuY)hKLa$oTl!v+6#=0h4e>DsE*6m*vwLu1WkgT8q?TH=ywpX;>^*v!p> z%Kk{l8dhi_PkD=CNk%t8AKbqH>lff;8vq~BUA6XF$!z>ygl+(c~kkX$Sf|MV=9U_U6@7^6jCRY0^RhT0}zGb2HBLL z6qRtByczD`ZUEn=vls8d&oLLlFXTRxcLYkRDiav<$dkTjhnx<`42xI_c+Ue~GT_~d z;8PE5G6YL@V95^b0agg&_x7RJ(N%&g8JdEgW0j#-;B=^mTBnDPvECs)@kmBMiYrnt WWHtne2apJ!dh!d{pttJAGvF_#t5ItJ literal 1542 zcmZ{kZBG+H5Xb-92Ts~+OF>Y;2M~d_Am<~Zhc!rIOstSlQX}tAd>!W2fEvI2@ z?;qNA$uP9e9WKiZ@j|ht;SxjMcj`#qG+tTW!5gccf`<4o($FJI!G&c= zA)3Z6EjxCDd(u5-NGhAhkgHsv2xF#^$Eb!e9hWiAkm>nK3fdhKv{vXwg;bh@mg1mE z(XZ&Zib+B>Y(gzWpdtb_OjFeZ^(fwT9XD{3Azc@aw7BEFwyD1HDDIx}pVe^-bJW!% z`?#tk8HTI8;aIZc+6=3`Em{wiRh2Gx8fIlcm{}%BVpF`Q_*{iM_Ex90 zZ@atJev>St6;ZdEHOu8{9~cwzfYU&x2VrMZBc$&76C@IikD(B*^8aFrH4@`kEkE_e z`3eH)n>q{(V}q$FrABk=W?PKNR*a50u)JCGu=(u(JC0Aq0D|KhhUr~LdJGIksByZU@?s1yk zhT{lnNiH1HQmP2IVR&tICO)`S)hFQ|8J@IVTgcF#H{y8MFmyqQwny98HRpgQ=#6a0#vg*{DkIi{0v&d9CKG~Txv4w4cx*BrFOeYS*liN`@T2+nsy~rEblxV6$UQ@mnKF||j$k6Yc zkj_(`Bjph?!c6lO=F4(mHk0@Y)I_dHeh4Iu;EVkaTG{y?>Oq$cq fUxu7!WbK&|6r$>St>jWf11++d#CEWYJyd=G)NL{| delta 389 zcmY*U%}&B#5S%U0)>7n0K~aoN6!|k&;>{SN!Mg{HHxnyVEP;Lmt5@UEBl(W{5PH&Z z@Bw@SPQHn8izdd)%+BuYY<8kg^z)Ce@jHM+)D0+zXo#AKK_#TR&aGqj9KT~9Uv%A8 zKv4HQ-wXB$k#gl!hfW~NfPuIM(?kNZ|F)XJ(DOU8K}|JfB8`lEq6QzBA0_IA93kBj zecKa`9SG60PZ$W%hG@H^2Pr@4Y)8jBp>Q}D2+t4tt{+&}tt+>E({tO_r5Ns7lvJ@{ zpoFr9N_e6wkCc)eD37up>E6xpLxe1U7cxJ^xWLM0Cgxc674$M4FEWN>ZX(ZU{?wI E4K1}k2LJ#7 diff --git a/target/classes/com/ioa/tool/common/DistanceCalculatorTool.class b/target/classes/com/ioa/tool/common/DistanceCalculatorTool.class index 066e3d99410748fbdba09ad25cf468698228a1dc..203945d154f85f9656ce751e15746ef2958c42ba 100644 GIT binary patch delta 367 zcmXv}%TB^T6g@L7ov~DTR8V|k6e(b=?A2)4`iRlEaaAcXZIH&KG49k)XlCPQ=t?Eg z5AY9I`6tE;=;l1`$cEmn=XSl`m3w>{cG|Ik z!H{c5*KQDbZX88j_l$tS*baI@yvv|DwQ~l&75N<#8qyX7q&i}WEnzdH%3jYen{J<^oC9^EEva{YCo%?BCB1cr zuc)RL-qU4JJpF?c(@nw&axO6=PSsywzKq%yp)oFElC<@wr;s7{h%9nc87}Wp7#~jL r^Nlx5_b~@NljpSapCLyX>Ed`06rw8na>1d98X7calG?x~wov*7tLHPX delta 394 zcmY+9y-vbl6o%i^LR(9bf`XzLF^c>dKiM3NQHh(01IER~qyoV<*e0ZLB~H%d8}%Y| z(lB@d-T{+$Vmw6?;_{yJo}cIBOpJ*!{QMq&060d&gaTDZ%t9O*!SF~6%Jg#M~HcW>l02ZXESQ^))}Y0ocd320r?39wr!azI)?312^b9M;Cst z8);A(%x-w)c%kb=VK{J(2^iEJFYuyW2F0$OFeKXHWlx8Kv;hr59L_4Q zL-AjFC%X26zJU_Tqw|isWMCQ9(Q8|NvQwdB9h(|9axWvva0w)dIK1e^cPM{*9lXk9AZYCtUp74nvM-Zb=E|NYU8(_LzdJnaxkeAFYi$p tj~)4Z;{^+2RDeg)oOb>)#55yaoEbqO(oC!rY>KF%K{lPLCbrN*`3DO>H!=VK delta 351 zcmYL@JxjxI5XPTN(j=y-eY2@mixFS?N~?o|BBB)BL_rYOf72)lB?T#6MQ|4CfAmY} zq;zoW;_lZGFI8~4=bpRge%#cYnx~)NlMevL*s-8MHK5r@Kqq8EF%s>*h;G_v-O%@j z1pOe0g5e=St=2A0m;`bySV$VMZKNHG%45Si6h3!98sM}xx_cTKdgjnWU|OE3li diff --git a/target/classes/com/ioa/tool/common/FitnessClassFinderTool.class b/target/classes/com/ioa/tool/common/FitnessClassFinderTool.class index f6a7aa1aedfa059ad0d6599828d20a9dd7eddc7e..8de31baa045495556f2cd53b1cab89e59920184f 100644 GIT binary patch delta 346 zcmY*TyH3ME5S%+d?rbI6Gh_oFP}w;)IG|WqfWkjNMSs8R4V=}7DiYCo=9`r`OA=#jDj;Y Xff})s`DDpCXx*No>nmAxwT&ze)8>G=RuExo^`5gEeI%ydE z0j`Yx7vn9O7?*SIxsP*mX6DSi`1qQ>131FI1qG^slno6!As2Xeo)~%Kp*Xn=2K|Vj zANXTGY7^9YN=g^`cvUJd}sj({nZ)O1q>Dd`U=!)4+(MNtHqqi`i>n>%Vh^QnJIgjd diff --git a/target/classes/com/ioa/tool/common/MovieRecommendationTool.class b/target/classes/com/ioa/tool/common/MovieRecommendationTool.class index 1cc6c646662513cf86e7155d2cca3ae4937cfa5d..0837a5ed230008ca6d7931f3f7a94288f6751805 100644 GIT binary patch delta 380 zcmY+8yHdhH6o&uZKz4~i5H)}oz-t0HB=(G#p|r4I#>zrehDnBrGY(_R_y}>f{W{cF=%_;t!HCG9&;1 delta 389 zcmY*U%TB^j5IxgEd#%M%R1`(QCoe;BZ&bnuxWKq_VFg0kK%1Dxt#RiT?@oV0R~i<6 zfFHolUolR>#JITU%$diTxf3xFSD)YG4**RZ8c?9>NSH`MBcy%z)^!GM(09(R{az;` zXh&Y)MaKlST)7Ys1S%RZFt5Wjk;1~isdjYZ1%271ww5+wBO{-v#S4~3sYX6aush+< z@j};$!f@c6GY}H3u-h9wJjyS+R0VdWr50>U!@hwM$~r2sQB^jTk{l|}vab4fi+na= zng0+opU$|#%3&tvWc3a7IxVj<#$`?-$7ue>YglJ>k32Rw6Az!VnG$zo^x8Y-#;|}F s)(ZYS#MI*?J8Q(uBsSedfo)V2rvqEqW)_^;0WpM!0P%1h2t$t$kOql@!iX9ZqR3Y8Nywr_l$6$$`~;){ zQt$!rPl0s;1e)@^~ME5t}U;-7Bu8-m=NliJ-Pxj3~bdx6>}z>f9Za5 z8^%2w^QfhlzOiUy3CrnwTYWKKSlGapiA{CFT|Jw)O7bVOXkcBSsn)ooEG@dH+hEY? z2Tql)5>Aows4}X0^A*<1cx)3IlO_tp?O#5PBB=+IP^M0{d`MwDb5ts=H_Q&P06dfC hwDXrC#u<5MVg!Y#k+xE;Q$zzTvRTBov4dUIegL?pHC+Gz delta 394 zcmY*UOHaaJ5S(qHt)F-F5(4;ar@siXv3167a2o1P5$F8&PRqT%2V z(Emi-qKWY`v$H!p$&9p-cK$gTe*iebt_}&Ziim+I6hfkH-`Q5j_FC4-MccUy2+F?e zxxoQJE?3SpXaq8K=!mH>49sHg-&Z5(x?W3I)KC%zl1Pb1sw*ny35CJ1u&N?UNM8Ea zmh0PA;QJlxlz|Yb`%P!ie-dBRsA||Cq>r8Zo_TxIv;(JSUisZUli~`BI!Y+3sD$xV zQItv%!b@2^OF7|5eWAzwX!Q*=oSt)x;hC4nGaA41B9>S^ zU>PgC37-!+ObQ(-wf2sgG2*~0YYBfD+B74U{V{?=#6(`pY;wdpYHZed+QK$=kpBku C4?Nlc diff --git a/target/classes/com/ioa/tool/common/PriceComparisonTool.class b/target/classes/com/ioa/tool/common/PriceComparisonTool.class index 17b3757038a53393462562511801c48f3241fdaf..016fcd926b382cca62630eb31741274bdb994427 100644 GIT binary patch delta 371 zcmY*UJx{_=6g}@1+D9ouQ4mm~i61Q=vA7$fVQ_G8z!(!3D-zNM+r%`k#6Ms{-s0qM z&`D*`iN)Q&quzoJF6Z2H@44r`HxUz&`S=>Y0ocd320r?39wr!azI)?312^b9M;Cst z8);A(%x-w)c%kb=VK{J(2^iEJFYuyW2F0$OFeKXHWlx8Kv;hr59L_4Q zL-AjFC%X26zJU_Tqw|isWMCQ9(Q8|NvQwdB9h(|9axWvva0w)dIK1e^cPM{*9lXk9AZYCtUp74nvM-Zb=E|NYU8(_LzdJnaxkeAFYi$p tj~)4Z;{^+2RDeg)oOb>)#55yaoEbqO(oC!rY>KF%K{lPLCbrN*`3DO>H!=VK delta 351 zcmYL@JxjxI5XPTN(&TTN+Be%;wHWcGuQWP1C?ZN{u^@0ua2D!+^h@ZZ zba3n9?$;47RdBiIp1bFM+*pjo!RPnr1He8uOejzdXciLC37NpXb)8E$yl@UrgPu1a z=sSMs4|WM^t$r*Z2xOZuku+dgNMTwoQC@D*k)E-TMNU3Zhlw-8REvtkZZV;CqO;!c z;Zc6kNn2orQ0n%5uV;JF)wSFAZ=%pXkNVp-rFE>CsG??|9jW|-8~ji;YobF$1o*MEh_btdq*% z;^vP+zk&`9_dLGG$#+L$BqCpv@dtnt9LV6q@7!sSA=WkS483RA9lhS{nk`p`#1L;e z*Sh5xy6ZSS{hWY7s#vz=Rv7|?;sryn=Cn-(0nDk8A-pPk$O|MHn5JM6OEOab(i?8y zvO6l$$P6zV(u#^zWQXrH?~~Pqf-UUG*!C(sAND(WhR1^U#M9n@53*4SIe`*G^2}^m zH>P&w+}drz{-MUa3GWW*DlmlTcbu5+AqaU(hl-xaH zh*QO1KBh44Pb3oMH!O^?3_O$PwDXrCrWr@6*&t>ie&`z3DJB4Iy0C#wV*jcFy&}rw L6jHm`!#*-U=_Ne% delta 401 zcmYL^%}&Bl5QWdQ&|YhiKLtU=Dk^`*%EpB;s9|ejBF23Km6Tv>2pSU?>cR&g-S`Bo zb){k9#+?sEoPvpqd(ND>GhZ?zF%s#Y$@mMv32GW7$SOiQ!cc~_GpzpXHzer6brX!Ao|3nQYE)FAwT#68HdDo`n zS?0j=dgcWSA=L2N_VD4w|E9Bwz$PJiZnvBp+qm*>-8O6gz@VstZ4E_~RFng9#m`E` zFyXay>euDG?@0IlMCv{!`2@le-xD~W!J6h|vJ-o_@&S6EelN2I-`qroRsXBASmE@H z99Fp#EFUvW3MLY2^%HYrM1eQX68;%t$~a2R1~G#K&^*={Bg2?3tYd>+aA%8O0aZ>K KS3B6n9x}hD8#ZbH diff --git a/target/classes/com/ioa/tool/common/ReminderTool.class b/target/classes/com/ioa/tool/common/ReminderTool.class index 658477f6a8e73e28c1276c56e030cace23052fb1..46786944a740fe805ffe45212275ccef0b0305d6 100644 GIT binary patch delta 381 zcmY*Uy-&h$5PjD|`?D1J5)_r#M3FCJbv4GIj1ERI&Q>U-1lj}}SL5W|bo5_f&`D)* zHSsTUQV-C<<=uOC?_TakVkF`pU*k6bhuBpi1>eQv2qD?CZY;BJxn1+*s%N)+6$&BM z@&=~kS*GuKee;}wpzJ%Y;~x;@a^->$X?Sg0gN&FC6(X$DeMulgAVWhIiz;&e(wqL! zal1N}kPj}K%8HIv6oS`A_)e!n!v;206vHE_6rD^;p(8yM5(?G@s)Wp$J#gH%Jv6Ru z-{^S5J%hrC+`Hv#K#1~J5?8*1agLSAmAFQ$&(NNxW1Uf%H4$g7|MGbxSluCs6n7@e xbqAf`u`bfk)O7@BC$mX+|tJGlE0HPkAj{=77kbc> z(t}sQALH4RxT%78nc3N$owsi+#^Ut-Yw`+UAKNArs0K6(8R&#U=wJEX(2oY*;aS-4 zB?NsZh=OF7pf+140)jwQ6DG0-EDJfz{@dy%mq9d;E_L;S1sg?qM;(4(ew3?M9D?18 zFT5c3y(Er@-Z29~>%`~%(e=H2qa#&dO@1hjo!7B$qJgG?RvOfnRiz;hln1G);msVM zO(^jnQs&bc7g%}B#GGkAgPx}2MaFc@O_Uj}-+BqltZq@k3U|`wJq}Y+N6~O!Ff&0O jcx0{MFGEZ-vd)hY93nr})l!`!YH-+XRYNv`(*DcHP&Y z5|VZA#&SGq`JUId&KU^mzT-On0U=ZH1ys+UvOu)3s%1&!k{A)VkxFK#1^f3Rk{{af+42mAFPquh3t{V}nthG!bKN{PJnU zS=}RnBzH#3ha9Gi9H~_K4YLC*0MD!y-ucTAne1K6B6L%J=q>U*F6u0QYwISDqTmL{; z8Ww&4Kj7aOPtnANPdcyaSS936-EQdgI!+LF?W=Y#Xxf46barh@s#rIWM?pg|aw~})DX$Qo z3gTJHid(5KmSw*`%^?UGP82Z*VVq@EVJ7BS=?(Nc9%mV&F*lK8G=J+k%(J?~0v5Rw x9Urop6m6un@;fGmNCGdcCH#5lV~@D?vj{d3ma>#tV~Z7(dD-A<16!yf_YL)xINbmM diff --git a/target/classes/com/ioa/tool/common/TranslationTool.class b/target/classes/com/ioa/tool/common/TranslationTool.class index b58e9a1f5ead2b5e69da66bb76e81f7c44854797..5cb2a164e2ff12f0e38dd6e63fb691595dcca5de 100644 GIT binary patch delta 376 zcmY*UKTpDN5PjD|`?Hk43W9$k32F-%tE(|a)5OKWfyUX2gp@#=VB>0B-I|Vmi8`qa zegG4{kx>uO!R6h1ckf>A5|N1P``6?RzzOzMNYS@>mLe1e?yYMLUB7RgUk!TQP=!J$ zc7u`S1+Ena!O(IT2+E=7d*Km5Hk%iOlpS36G|0&4P$6QQ9t?p+0@XE?v8K+9Yxieip<}hjM sD3#hTSejr3NLWj}^OqrJ8JWu52o8xq<&Cn*5lyt&rZL;WF7{CS0nH;hl>h($ delta 385 zcmY*U%}&B#5S(qH{Ve5IK~ab#h!ikZuErP*R}&8q&sHR)4Ym;*ujrK<`7S;No-`bM z02ANH7`JF*yv*$E&unHc=Hl}GYw-r)6m0_vR2?xBacG2$=iEE?$nl5v`IR^5hXn1& z_1*B8pjwR!0YRXO0Rssgrimm{|E{{>*!739OGf|_Ar$n)T;^X5K_IdEzFh*l;qR43e)|=R3^@tM6+=-4) v*i4Bwa(e3(D+{E7Ico)f9%AW{DEusfP2{J#ov*P)6)j#ixZ1-$4p96CtfV?< diff --git a/target/classes/com/ioa/tool/common/TravelBookingTool.class b/target/classes/com/ioa/tool/common/TravelBookingTool.class index 3382aa3bd75452426f004fbe47f9cd4f245ebc89..ca27d246b70abfb071a98707214cd7b9dbdd4b83 100644 GIT binary patch delta 382 zcmY*UOHaaJ5S%U0ewHE+0mTuf`Y+@#Mio2xkja(u#ZuX-GU7?_Nlc{s}#) zg!luz`G?d6^x$Q7W_Nb7I~HRR`}i8Y131CH24(nNJ_{2Po;|RwuHEZc=S|OP`5IJ0 zvL$aUSK5{@W!I`R5Y$7r=lVy4P_fh?gsZac=m;TdK!XTQ>7gL7Kp;~`28$Z9|I%xI z-|ck_EFm|%tf?yoR_EVamjjN>yHw9$^`HVy*DbUxt`wM6)v^I3y6^e5S||B~;j^Guy!~_K^DlWa2u| delta 345 zcmY*T%Syvg6r6MOx~8dp*rwJ83O?GV#puGFh|;|-3f;IdYAFd4L4sS+wFu!Z{Rv$u zrSt>b`9X>&RS-94&SPfIjOAFKzJHA-01mNZLqM~jJ1}4picxSA_?JOE^pDS?!FfV3 z_rf?#_6b_E)t8V2TD4&#XTfoh$Lv2tn>HF~T4-f5Px+#uPQ;U{XwmH)ha^-vafTd}YmFzLkr)l{ z74$Ma&vVVryhNR=^V=_Ak*7N>VVO6X_<+qs#wc6uH_VJs0G@dk`16ockDU8M1e++S UuT(eKVhwF3+uU`qg>BTo0h?_u*#H0l diff --git a/target/classes/com/ioa/tool/common/WeatherTool.class b/target/classes/com/ioa/tool/common/WeatherTool.class index 9e419d298e296edefb8aeff00de7ca119fb3c03a..bbc8f43be506fa238e3b7aa645ec865d0bcdbfb9 100644 GIT binary patch delta 363 zcmY*UyH3ME5S%;5_Tf0>0SO5ZfkeQ0AP#!OLy>4GKnkM9BvE85i6vywA{u(@N`Asr zKngkaut*|p#Ah9(S# zd^Z?LFK}fT1Ved2z+miqV=p{l(CUp#hEzM~^(|;f+b|*2A$xEH78uyNg(8+rl>Vi6 z!W(Zquu(=Oy6PA!HdaxMUfb%OoeK*!Y?;_pC*0AKiK9mR(aajy5NN70uPUMWcXS&J zI{m<@(pADaQj#j8syCluJx#|pp)qSBL)`x5^T?9AM-F-FB+Ew>#uG=O(0ak*1j|57 in$yl-hL~ogOEV)VM15*κ&?1{fY#Te+Mdb&Zn>9TE delta 348 zcmYL@F;Bu!6ot=yh4xvBP!JS_Xd(&)b>MB`qOkTyt{#>vF!;7;D?pQw|D z!Og|L;$JYvTQqSw_nv#t{c;nT$m5Ui=^KDU?Aj18EMy#HVG@d=f8(o>KOU-+%W%+- z3Fclf4&r@+(e^GRB!Sj!*vMIM9ON;tT`Fsj&dj0%7bX2bJti(p^38gc;P#_y6-2&@ zqiCegSqPb4bTydVKI(TmH6)t)Q#9OyiA@_Vv@LiksG}RArH{mumPUA2=06D)embrE zE9)XV#g({bJ1?N;*?NgJUGoq%R_Cu@#tOT8)Y0HcdVIhzktRx3_Z4$f6o7=iz&}II c7`f_i5Dd{@#%g7Q5$ou3*ye5v+t@+v2Qf%5OaK4? diff --git a/target/classes/com/ioa/tool/common/WebSearchTool.class b/target/classes/com/ioa/tool/common/WebSearchTool.class index 36d1c65508319a41f605b667900a16cd29917d45..b6a0f89cf61b4ea0cc56ba4111094b4beae3edf4 100644 GIT binary patch delta 371 zcmY*UJx>Br5S)D+caP(c4+TL{OjJINr@b)}N(vJ()}BbnUGOe37h7UyWkO!#zfcRJ zQrPQ{QWwy|W@cx1cJ{ro9LvP#*W?{Q6Z;0l=)2t32r19GaqNNP_wC~guh$I?=!A4P zxU${AvBMx3*ryBx{lN9z@Q@Ix*3Jl8E4b{Lh#+pkfK*Mot4J&oXv0Jn%La1)(mUa` z>-R0>Q5cN*tc~7U>Vr!?U=4kx|=JRZ9G3xUs5?ouq^#YQtZjnNoJJaPO4ii&HCewJu n(gZ8O6Klace;IO?5zozy;1ESxDO=@;8X9afx!S=l_E7i%ea<$H delta 363 zcmY*UO-sX25S&fYjow9+{(yoN&&FCxLQOz|N5zYHE$`@`&_hvr z@UH*HKOk9Sva38wTMcg)_-sOv z|By1D&bY+NVjm^Y8!t1aV{W3%X#LhJSY>qw7i-)}mk&8iNgV~F{ffCMa=;U7 g1%DZ0mXR&}7{MWuwDsa9M^w>fv&q#KcCd@`Hwqy%3jhEB diff --git a/target/classes/com/ioa/util/TreeOfThought.class b/target/classes/com/ioa/util/TreeOfThought.class index 72c0c5f40def69a8b7ce80c04434b47feba99c74..b01f4d3723bac8923b4bee2f9d40d49272461d14 100644 GIT binary patch literal 5907 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 aJNf*BeEvy3|AN0!N^He{$3O8BlK%tg#`FXL literal 6068 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