From fd66c81027cdb7b7b072b33b6fb2ab2ceff31749 Mon Sep 17 00:00:00 2001 From: Mahesh Kommareddi Date: Thu, 18 Jul 2024 13:07:25 -0400 Subject: [PATCH] Agent to agent hub communications. Conversation stalls because they ask questions now. --- src/main/java/com/ioa/IoASystem.java | 72 ++--------- src/main/java/com/ioa/agent/AgentInfo.java | 113 ++++-------------- .../com/ioa/conversation/ConversationFSM.java | 111 +++++++++-------- .../ioa/conversation/ConversationManager.java | 6 + .../ioa/conversation/ConversationState.java | 2 + .../com/ioa/service/WebSocketService.java | 1 + src/main/java/com/ioa/task/TaskManager.java | 93 +++++++------- target/classes/com/ioa/IoASystem.class | Bin 12205 -> 9489 bytes target/classes/com/ioa/agent/AgentInfo.class | Bin 6368 -> 3746 bytes ...versationFSM$ConversationStateUpdate.class | Bin 1115 -> 1115 bytes .../ioa/conversation/ConversationFSM.class | Bin 8766 -> 8361 bytes .../conversation/ConversationManager.class | Bin 4700 -> 5185 bytes .../ioa/conversation/ConversationState.class | Bin 1351 -> 1465 bytes .../com/ioa/service/WebSocketService.class | Bin 3342 -> 3403 bytes target/classes/com/ioa/task/TaskManager.class | Bin 5599 -> 4357 bytes .../compile/default-compile/createdFiles.lst | 26 ++-- .../compile/default-compile/inputFiles.lst | 22 +++- 17 files changed, 170 insertions(+), 276 deletions(-) diff --git a/src/main/java/com/ioa/IoASystem.java b/src/main/java/com/ioa/IoASystem.java index febcebe..beefa21 100644 --- a/src/main/java/com/ioa/IoASystem.java +++ b/src/main/java/com/ioa/IoASystem.java @@ -52,7 +52,7 @@ public class IoASystem { } @Bean - public ConversationManager conversationManager(BedrockLanguageModel model, @Lazy WebSocketService webSocketService) { + public ConversationManager conversationManager(BedrockLanguageModel model, WebSocketService webSocketService) { return new ConversationManager(model, webSocketService); } @@ -122,36 +122,38 @@ public class IoASystem { 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, conversationManager)); + treeOfThought, webSocketService, toolRegistry, model)); agentRegistry.registerAgent("agent2", new AgentInfo("agent2", "Travel Expert", Arrays.asList("travel", "booking"), Arrays.asList("bookTravel", "calculateDistance", "findRestaurants"), - treeOfThought, webSocketService, toolRegistry, conversationManager)); + 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, conversationManager)); + 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, conversationManager)); + 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, conversationManager)); + 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, conversationManager)); + 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, conversationManager)); + treeOfThought, webSocketService, toolRegistry, model)); // Create all tasks List tasks = Arrays.asList( @@ -196,66 +198,18 @@ public class IoASystem { ); - // Create a thread pool - ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); - 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()) { - // Create a conversation for the team - String conversationId = conversationManager.createConversation(); - - // Add team members to the conversation - for (AgentInfo agent : team) { - conversationManager.addParticipant(conversationId, agent); - } - - // Create a CountDownLatch to wait for all agents to complete their tasks - CountDownLatch latch = new CountDownLatch(team.size()); - - // Assign the task to all team members and execute in parallel - for (AgentInfo agent : team) { - executorService.submit(() -> { - try { - Task agentTask = new Task(task.getId() + "_" + agent.getId(), task.getDescription(), task.getRequiredCapabilities(), task.getRequiredTools()); - agentTask.setAssignedAgent(agent); - taskManager.addTask(agentTask); - taskManager.executeTask(agentTask.getId(), conversationId); - } finally { - latch.countDown(); - } - }); - } - - // Start the conversation - conversationManager.startConversation(conversationId, "Let's work on the task: " + task.getDescription()); - - // Wait for all agents to complete their tasks - try { - latch.await(40, TimeUnit.MINUTES); // Wait for up to 5 minutes - } catch (InterruptedException e) { - e.printStackTrace(); - } - - // Get the result - String result = conversationManager.getConversationResult(conversationId); - System.out.println("Task result: " + result); + 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."); } } - - // Shutdown the executor service - executorService.shutdown(); - try { - if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) { - executorService.shutdownNow(); - } - } catch (InterruptedException e) { - executorService.shutdownNow(); - } } } diff --git a/src/main/java/com/ioa/agent/AgentInfo.java b/src/main/java/com/ioa/agent/AgentInfo.java index 86f1b50..472635c 100644 --- a/src/main/java/com/ioa/agent/AgentInfo.java +++ b/src/main/java/com/ioa/agent/AgentInfo.java @@ -1,13 +1,12 @@ package com.ioa.agent; +import com.ioa.conversation.ConversationFSM; import com.ioa.conversation.Message; -import com.ioa.util.TreeOfThought; +import com.ioa.model.BedrockLanguageModel; import com.ioa.service.WebSocketService; import com.ioa.tool.ToolRegistry; -import com.ioa.conversation.ConversationFSM; -import com.ioa.conversation.ConversationManager; +import com.ioa.util.TreeOfThought; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -19,11 +18,11 @@ public class AgentInfo { private TreeOfThought treeOfThought; private WebSocketService webSocketService; private ToolRegistry toolRegistry; - private final ConversationManager conversationManager; + private BedrockLanguageModel model; public AgentInfo(String id, String name, List capabilities, List tools, - TreeOfThought treeOfThought, WebSocketService webSocketService, - ToolRegistry toolRegistry, ConversationManager conversationManager) { + TreeOfThought treeOfThought, WebSocketService webSocketService, + ToolRegistry toolRegistry, BedrockLanguageModel model) { this.id = id; this.name = name; this.capabilities = capabilities; @@ -31,95 +30,29 @@ public class AgentInfo { this.treeOfThought = treeOfThought; this.webSocketService = webSocketService; this.toolRegistry = toolRegistry; - this.conversationManager = conversationManager; - } - - public void sendMessage(String conversationId, String content) { - conversationManager.postMessage(conversationId, this.id, content); + this.model = model; } public void receiveMessage(Message message) { // Process the received message - Map reasoningResult = treeOfThought.reason("Respond to message: " + message.getContent(), 2, 2); - String response = (String) reasoningResult.get("response"); // Assuming the response is stored under the key "response" - // Send the response back to the conversation - sendMessage(message.getConversationId(), response); + String prompt = "You are " + name + " with capabilities: " + capabilities + + "\nYou received a message: " + message.getContent() + + "\nHow would you respond or what actions would you take based on this message?"; + String response = model.generate(prompt, null); + System.out.println("DEBUG: " + name + " processed message: " + message.getContent()); + System.out.println("DEBUG: " + name + " response: " + response); } - public List getCapabilities() { - return this.capabilities; + 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)); } - public String getId() { - return this.id; - } - - public List getTools() { - return this.tools; - } - - @Override - public String toString() { - return "AgentInfo{id='" + id + "', name='" + name + "'}"; - } - - public String executeTask(String taskDescription) { - System.out.println("DEBUG: Agent " + id + " executing task: " + taskDescription); - webSocketService.sendUpdate("agent_task", Map.of("agentId", id, "task", taskDescription)); - - // Use Tree of Thought to decide on tools and actions - Map reasoning = treeOfThought.reason("Select tools and actions for task: " + taskDescription + - "\nAvailable tools: " + tools, 2, 2); - String reasoningString = formatReasoning(reasoning); - System.out.println("DEBUG: Agent " + id + " reasoning:\n" + reasoningString); - webSocketService.sendUpdate("agent_reasoning", Map.of("agentId", id, "reasoning", reasoningString)); - - // Extract tool selection from reasoning - List selectedTools = extractToolSelection(reasoningString); - System.out.println("DEBUG: Agent " + id + " selected tools: " + selectedTools); - webSocketService.sendUpdate("agent_tools_selected", Map.of("agentId", id, "tools", selectedTools)); - - // Execute actions using selected tools - StringBuilder result = new StringBuilder(); - for (String tool : selectedTools) { - String actionResult = executeTool(tool, taskDescription); - result.append(actionResult).append("\n"); - } - - String finalResult = result.toString().trim(); - System.out.println("DEBUG: Agent " + id + " task result: " + finalResult); - webSocketService.sendUpdate("agent_task_result", Map.of("agentId", id, "result", finalResult)); - - return finalResult; - } - - private String formatReasoning(Map reasoning) { - // Implement a method to format the reasoning tree into a string - // This is a placeholder implementation - return reasoning.toString(); - } - - private List extractToolSelection(String reasoning) { - // Implement a method to extract tool selection from reasoning - // This is a placeholder implementation - return new ArrayList<>(tools); - } - - private String executeTool(String tool, String context) { - System.out.println("DEBUG: Agent " + id + " executing tool: " + tool); - webSocketService.sendUpdate("agent_tool_execution", Map.of("agentId", id, "tool", tool)); - - // Placeholder for tool execution - // In a real implementation, you would call the actual tool method from the ToolRegistry - String result = "Simulated result of using " + tool + " for context: " + context; - - System.out.println("DEBUG: Agent " + id + " tool result: " + result); - webSocketService.sendUpdate("agent_tool_result", Map.of("agentId", id, "tool", tool, "result", result)); - - return result; - } - - public void voteToFinish(String conversationId) { - conversationManager.postMessage(conversationId, this.id, "/vote"); - } + // 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/conversation/ConversationFSM.java b/src/main/java/com/ioa/conversation/ConversationFSM.java index 1547e48..e118dae 100644 --- a/src/main/java/com/ioa/conversation/ConversationFSM.java +++ b/src/main/java/com/ioa/conversation/ConversationFSM.java @@ -1,6 +1,5 @@ package com.ioa.conversation; -import java.util.stream.Collectors; import com.ioa.agent.AgentInfo; import com.ioa.model.BedrockLanguageModel; import com.ioa.service.WebSocketService; @@ -8,9 +7,8 @@ import org.springframework.stereotype.Component; import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; @Component public class ConversationFSM { @@ -19,31 +17,42 @@ public class ConversationFSM { private final WebSocketService webSocketService; private final Queue messageQueue; private final List participants; + private final Queue speakingQueue; private final Map votes; private final AtomicBoolean finished; private String result; - private final ScheduledExecutorService executorService; + private String conversationId; public ConversationFSM(BedrockLanguageModel model, WebSocketService webSocketService) { - this.executorService = Executors.newScheduledThreadPool(1); this.currentState = ConversationState.DISCUSSION; this.model = model; this.webSocketService = webSocketService; this.messageQueue = new ConcurrentLinkedQueue<>(); this.participants = new ArrayList<>(); + this.speakingQueue = new ConcurrentLinkedQueue<>(); this.votes = new HashMap<>(); this.finished = new AtomicBoolean(false); this.result = ""; } + public void initialize(String conversationId) { + this.conversationId = conversationId; + } + + public String getConversationId() { + return conversationId; + } + public void addParticipant(AgentInfo agent) { participants.add(agent); + speakingQueue.offer(agent); votes.put(agent.getId(), false); webSocketService.sendUpdate("conversation_participants", participants); } public void removeParticipant(AgentInfo agent) { participants.remove(agent); + speakingQueue.remove(agent); votes.remove(agent.getId()); webSocketService.sendUpdate("conversation_participants", participants); } @@ -61,64 +70,53 @@ public class ConversationFSM { } private void handleMessage(Message message) { - if (message == null) { - System.out.println("DEBUG: Received null message"); - return; - } - - String content = message.getContent(); - if (content == null) { - System.out.println("DEBUG: Message content is null"); - return; - } - - System.out.println("DEBUG: Received message: " + content); - - if (content.startsWith("/vote")) { + if (message.getContent().startsWith("/vote")) { handleVote(message.getSender()); } else { - String stateTransitionTask = "Decide the next conversation state based on this message: " + content + - "\nCurrent state: " + currentState + - "\nParticipants: " + participants + - "\nPossible states: " + Arrays.toString(ConversationState.values()); - - String reasoning = model.generate(stateTransitionTask, null); - - String decisionPrompt = "Based on this reasoning:\n" + reasoning + - "\nProvide the next conversation state. Choose from: " + - Arrays.toString(ConversationState.values()) + - "\nResponse format: STATE: "; - String response = model.generate(decisionPrompt, null); - - ConversationState newState = parseStateFromResponse(response); - transitionTo(newState); - - // Broadcast the message to all participants - for (AgentInfo agent : participants) { - if (!agent.getId().equals(message.getSender())) { - agent.receiveMessage(message); - } - } - - webSocketService.sendUpdate("conversation_message", message); + broadcastMessage(message); + updateState(message); + notifyNextSpeaker(); } } - private ConversationState parseStateFromResponse(String response) { - String[] parts = response.split(":"); - if (parts.length > 1) { - String stateName = parts[1].trim().toUpperCase(); - try { - return ConversationState.valueOf(stateName); - } catch (IllegalArgumentException e) { - System.out.println("Invalid state name: " + stateName + ". Defaulting to DISCUSSION."); - return ConversationState.DISCUSSION; + private void broadcastMessage(Message message) { + for (AgentInfo agent : participants) { + if (!agent.getId().equals(message.getSender())) { + agent.receiveMessage(message); } } - System.out.println("Could not parse state from response: " + response + ". Defaulting to DISCUSSION."); - return ConversationState.DISCUSSION; + webSocketService.sendUpdate("conversation_message", message); } - + + private void updateState(Message message) { + String stateTransitionTask = "Decide the next conversation state based on this message: " + message.getContent() + + "\nCurrent state: " + currentState + + "\nParticipants: " + participants; + + 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."; + String response = model.generate(decisionPrompt, null); + + ConversationState newState = ConversationState.valueOf(response.trim()); + transitionTo(newState); + } + + private void notifyNextSpeaker() { + AgentInfo nextSpeaker = speakingQueue.poll(); + if (nextSpeaker != null) { + nextSpeaker.notifyTurn(this); + speakingQueue.offer(nextSpeaker); + } + } + private void handleVote(String agentId) { votes.put(agentId, true); checkVotes(); @@ -152,8 +150,7 @@ public class ConversationFSM { } private List getPossibleTransitions() { - // This is a simplified version. You might want to implement more complex logic. - return Arrays.asList(ConversationState.values()).stream() + return Arrays.stream(ConversationState.values()) .map(Enum::name) .collect(Collectors.toList()); } diff --git a/src/main/java/com/ioa/conversation/ConversationManager.java b/src/main/java/com/ioa/conversation/ConversationManager.java index e2782ff..81a2079 100644 --- a/src/main/java/com/ioa/conversation/ConversationManager.java +++ b/src/main/java/com/ioa/conversation/ConversationManager.java @@ -25,10 +25,15 @@ public class ConversationManager { public String createConversation() { String conversationId = UUID.randomUUID().toString(); ConversationFSM conversation = new ConversationFSM(model, webSocketService); + conversation.initialize(conversationId); conversations.put(conversationId, conversation); return conversationId; } + public ConversationFSM getConversation(String conversationId) { + return conversations.get(conversationId); + } + public void addParticipant(String conversationId, AgentInfo agent) { ConversationFSM conversation = conversations.get(conversationId); if (conversation != null) { @@ -48,6 +53,7 @@ public class ConversationManager { 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; } diff --git a/src/main/java/com/ioa/conversation/ConversationState.java b/src/main/java/com/ioa/conversation/ConversationState.java index 470d24d..37fc097 100644 --- a/src/main/java/com/ioa/conversation/ConversationState.java +++ b/src/main/java/com/ioa/conversation/ConversationState.java @@ -3,6 +3,8 @@ package com.ioa.conversation; public enum ConversationState { DISCUSSION, TASK_GATHERING_INFO, + TASK, + TASK_PLANNING, TASK_ASSIGNMENT, EXECUTION, CONCLUSION diff --git a/src/main/java/com/ioa/service/WebSocketService.java b/src/main/java/com/ioa/service/WebSocketService.java index a593391..38ce9c8 100644 --- a/src/main/java/com/ioa/service/WebSocketService.java +++ b/src/main/java/com/ioa/service/WebSocketService.java @@ -52,6 +52,7 @@ public class WebSocketService { // 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) { diff --git a/src/main/java/com/ioa/task/TaskManager.java b/src/main/java/com/ioa/task/TaskManager.java index 8f8fd64..979026f 100644 --- a/src/main/java/com/ioa/task/TaskManager.java +++ b/src/main/java/com/ioa/task/TaskManager.java @@ -2,15 +2,19 @@ package com.ioa.task; import com.ioa.agent.AgentInfo; import com.ioa.agent.AgentRegistry; +import com.ioa.conversation.ConversationFSM; +import com.ioa.conversation.ConversationManager; import com.ioa.model.BedrockLanguageModel; import com.ioa.service.WebSocketService; import com.ioa.tool.ToolRegistry; import com.ioa.util.TreeOfThought; -import com.ioa.conversation.ConversationManager; +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 { @@ -21,7 +25,8 @@ public class TaskManager { private TreeOfThought treeOfThought; private ConversationManager conversationManager; - public TaskManager(AgentRegistry agentRegistry, BedrockLanguageModel model, ToolRegistry toolRegistry, TreeOfThought treeOfThought, ConversationManager conversationManager) { + public TaskManager(AgentRegistry agentRegistry, BedrockLanguageModel model, ToolRegistry toolRegistry, + TreeOfThought treeOfThought, ConversationManager conversationManager) { this.agentRegistry = agentRegistry; this.model = model; this.toolRegistry = toolRegistry; @@ -33,61 +38,43 @@ public class TaskManager { tasks.put(task.getId(), task); } - public void executeTask(String taskId, String conversationId) { + public void executeTask(String taskId, List team) { Task task = tasks.get(taskId); - AgentInfo agent = task.getAssignedAgent(); - - System.out.println("DEBUG: Executing task: " + taskId + " for agent: " + agent.getId()); - - conversationManager.postMessage(conversationId, agent.getId(), "Starting task: " + task.getDescription()); - - String executionPlanningTask = "Plan the execution of this task: " + task.getDescription() + - "\nAssigned agent capabilities: " + agent.getCapabilities() + - "\nAvailable tools: " + agent.getTools(); - - System.out.println("DEBUG: Generating execution plan for task: " + taskId); - Map reasoningResult = treeOfThought.reason(executionPlanningTask, 3, 2); - String reasoning = (String) reasoningResult.get("reasoning"); - - System.out.println("DEBUG: Execution plan generated: " + reasoning); - - if (reasoning == null || reasoning.isEmpty()) { - System.out.println("WARNING: Empty execution plan generated for task: " + taskId); - reasoning = "No execution plan generated. Proceeding with a general approach to organize execution plan."; + if (task == null) { + System.out.println("ERROR: Task with ID " + taskId + " not found."); + return; } - - conversationManager.postMessage(conversationId, agent.getId(), "Task execution plan:\n" + reasoning); - - String executionPrompt = "Based on this execution plan:\n" + reasoning + - "\nExecute the task using the available tools and provide the result."; - Map executionResult = treeOfThought.reason(executionPrompt, 1, 1); - String response = (String) executionResult.get("reasoning"); - - if (response == null || response.isEmpty()) { - System.out.println("WARNING: Empty response generated for task execution: " + taskId); - response = "Unable to execute the task due to technical difficulties. Please try again or seek assistance."; + + String conversationId = conversationManager.createConversation(); + ConversationFSM conversation = conversationManager.getConversation(conversationId); + + for (AgentInfo agent : team) { + conversation.addParticipant(agent); } - - String result = executeToolsFromResponse(response, agent); - - if (result == null || result.isEmpty()) { - result = "No specific actions were taken based on the execution plan. Please review the plan and provide more detailed instructions if necessary."; - } - - task.setResult(result); - - conversationManager.postMessage(conversationId, agent.getId(), "Task result: " + result); - } - - private String executeToolsFromResponse(String response, AgentInfo agent) { - StringBuilder result = new StringBuilder(); - for (String tool : agent.getTools()) { - if (response.contains(tool)) { - Object toolInstance = toolRegistry.getTool(tool); - // Execute the tool (this is a simplified representation) - result.append(tool).append(" result: ").append(toolInstance.toString()).append("\n"); + + conversation.postMessage(new Message(conversationId, "SYSTEM", "Let's work on the task: " + task.getDescription())); + + // Allow agents to interact for a maximum of 10 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 + } catch (InterruptedException e) { + e.printStackTrace(); } } - return result.toString(); + + if (!conversation.isFinished()) { + conversation.finish("Time limit reached"); + } + + String result = conversation.getResult(); + task.setResult(result); + System.out.println("Task completed. Result: " + result); + } + + public Task getTask(String taskId) { + return tasks.get(taskId); } } \ No newline at end of file diff --git a/target/classes/com/ioa/IoASystem.class b/target/classes/com/ioa/IoASystem.class index 93d8cbc1cac67f6c345fa32a9fb7fc1606f8f942..727102019043ee7dc2d7135a59a990790f627e70 100644 GIT binary patch delta 1991 zcmbVNX>3$g6#mYg<#pb?*J)<}J5<`~bT6$)3l>J8P%LGsSlJ6A78tOW(%LDqR5C8O z)Q!MRQQ!x0iI^A@kfhKyQ82_rRD=*rP5dFCEDCOjN)_sPw?kWq{_)Rw=iYP9cfNDZ zz4yJhWXp8@$n}m708FA)d-XD%4$D&>pWI~@%2s`;JT^3WUy{31m~NcL84ceW_zq`f zXMC~yJT7SX-oOvID6hq5$DPNI27bcNGT)P;>j>ai1DEle+&DPhbm4dWq2W&hSJ5r! zdq!#a+rTwkms>sgP8dWa#n8Kje2PDm(rng+#_M>Z!Emx8&F z*B~D*6118~SzSZZdL3Of*q|Y}PH?OYH%(j46e!6cKMf_g!|TG!)-;9ZR7YwFnXwX` zvRT&yx$~^p+YK6K#kx3lRyeX|Rg)Kj5Jv&I$G3Xl(ZStL**L6O=A=YrLuzB?B7#q^ zY^+}vjznr!uM9LXawtG?w3rY-rM|H)ygbkpuC7yiOL)&p9cWa@yytOJwN6WEnMTX4 z>cg@&@R6JtOte32@p~eeqGwdp*VnFT(C87lF*tgv8(bKiAWGwDjo=mW*O9j$w3ih@ zL6&T`jFisO=yjkB%H$PM7G=XmX|g+*Jg?ukNcjd}V;?={YiT)@tKxOaqv4F6&vq+$ z0Ylxvx=Sd~5lZIKo$Qh(Ytxg<`=Q7D2lPlPj6r8n(aq4DU=)p3SYM|n7xiO}A5c<^ z=0HjucNZ0_xV(&k97_KehcPr(VZD@*616z!u&OQR?+k@Efm;EXeeE(SM0cy2Oy)68 zd7IquB3NxTRSWGLZKLrt0ghXkm(WBj8++D5Q^=l91geJT7x?Y|sAE5Zd)PK`z?B17 zc=}j)XbhuU2f#yCk1fs~#mr*iQOxX0vqpL=i%C=(W3hxeIM~nZL}rzICo_Ig{~YG3 z%%ghkeVNU^%>Q1$#m0V1)ghX!dYqVboPzR9R{6+u&N)P}J{Uue!-3w;-W2Pid#H>j zo+cM%=gqdbd12Mnz})Tm9t%gm!{G*?vM{on$Fiku>KsLx3B>F zIT(lsY^ky9S0;2;u1E;%x1EV*QDP6^9*bEdJpqGU;~rMD<~B6lY1!Mw>) z-LJRf6d~mHyW4S&upJRgyF?7v6*73PMjL*4A6KmJUmfTH+Q?SGD~b!5*1mawj1Edr z`+l>X5(zsHRDm?eZ?@5Gz0s81K`F{>Hw@nLQEFS1Y`c3}tXIKKR(p=3h~;Bk-db+W zI%Hx!3b6qtXhsDdM-?_=1)f9{PoWi0<4xAz#xwX3&*CIE=nU&;(L#2-K&g0<-+&gr z@GsL$yh1hDOlw)+fGzYIw$eUGiXP&{VYJd|Y@=&g* z<8`qaZ-{NI@5Cpf14qOmd@7FPGw~HZ7Z>n_xQt_>2ghw*oUkS1q%8$ss@ZOW$v&kt zgDP0-KsDXVgbZtb(HjTTmKqzlVe_dYDv)H;XcFBA8!|;Vl~5%gokDR*T@D9I#5d~N zI#D4`sH3N$N_?y?a2!^Mc6G5_Om-99&xv)K#hv9t8>2FtsqBQ;GR|S+TsDq_y+^zy zPZgvtNYrpz!+G$JuTDc3udX7ln@^#g=CP-s`E=u%UBJ(574Hq=H{&5bp9__IK*o1NXs>_HMB6Co_&O1M&$R!md~7$6WZm4ISZy4j4dlI+IaNdj72 zKoJn{Q5387s?b9%V4I6pt!dtpZgMs?hJfO+tvV?(es6zIS}r|2y97 z-a7Nqh5F889ZwKZ89vymm+RQ+oSK>A7t_H^%H}y#>-2S$6lNe_>JO*Upp*DgQ9&L;47m%@U$@;hH+DDiM!Z z$z(i{1gV8Z6*~Qk{;ko+27N*YK=~{u6)tYHqjklRcr4PGNLVquxO}M3&FRhmhM=sy~LYS3r&Imj>VmQ0n=qz&>! zZRdb*XyzAmM5Chy{g=LU2Kh&MzMx|U9S1qH{P{jF6sQ_p1~TAw9`aAn;4$EZ?(FlA zbsGkJ@H@dkxi^S@8nO&zJC_DVy89a#fPv2Sfiv8ufjpezJR3M8Ww1%eH!y_01ZmM^ zd3}SuOeX_F4HQ5JWkuLg+nO4WHCc&d*p9|yVtcrO5%d7N5U#DQ3McGnB-#*;*&0TH zhMjP$2Z~eU9KLho&9Ta`9a${Y78xiUEdu09Mz6GVjKo-jGBA!87}5Dzq@dWK<@gRe z?yT_VIJe}QPQ!parz|))^^KBCd!<861imyAr{Q!B6AXM8-vbTr)5NYocZLh(PBzxm zM>#O37oMDBu?i{m8^S)V(QZswrCFrH5MZ5Ypai9y%SoG|>Io%iRF5jqQbqGKxI)CI z(2Gf!tf9=n6ifvT?$hFGu7`OsVWBp=V$Qtk^0}ZPX;XXWV%O190d%>6X_yYm2seiX z_prj5f~$|@?`A8yNJB-sMmp=UB4%5OL}P<()s`=fSPe2aFaxs;RFWGMXh=k3_FOw0 zSyG({M=Sxw90TXU59-e)+!KiNtz=`J?a3k+3=htCt_j9cB4*VF<_TGz&79+1 zEu^~?xqs{(iim+)Q3DxlY(=e3>k-M~1YIObY%yqJ&(JxO136*Zi^~lx5gG=H9%Wt8 z7)@BUQ^O76nrL0rj#^0;jCunxaVFT~Of|O>x!GXg3M6Yy*vGa+3aGGuP&TFXB@fb)v>WBl=FolUo6w*W3vi zf9J!2%g+p?J%}f|%W!1hVtSQpsZ*P~vLL@MTwhZg9^Q~{^#X=uSuBlUayYk=6}?-@ z+5e}N%xB;vP(qG|-}7Z6>rmcDd?>z4LNm1VT2SE(yVdKQm&};)!~z zHe_4jdR_~XJK)CiIyK`31HZ!)9=r%LD=m9eGSnPTED6P9A$zfPLdI^EA=HP`7)iM= z^ZkW|U`cy)ysG1`8up5;e9hTxK0Te6|E}Y8yrE&Afj99MsNjUz(O6S_iB()Fahh$} z;mg7izTK8_?$r03J@4!`Yn-)tK6mx92CKBvxjJvKA|C@?V#TS<8;^IKtMW#>-s8T& z+xgD3c{wSAI048_z;f6k1ZiCY)Z3bP^4Oy;qAg{N$Dc|BiANI3~+i{0b;cOa|9~A-ANdP#V zpR=UAa~NGBUuO^nwE=fZ$9!zwUGlU~A|nFolTmRow~CFpn}gpYKCJD>xJPOmH#n3! zkuFs|GzGdf1=zN`rKW%kg0L$fwF^xFsof&5+efKgiRG!7Zfy!Q_oSSonaWnkh#Jj64NvhY(p%*bT(1+a;WOJRBqtreVH z3=S7w7LmHoIW%N}b7AOAc%0iplX!e7RKeq*p<=vDj$7n-bm$yjsVJD5^0v|b7W$x# z{#l}%-gY_&D#1)Se(B1Te>1jcz#Lo*-Zomwr<pwX9%+dgwGHRA z;M@x~lg?^cWoo84*Miw4LE%QQ169(8%_Q8-#`oFJ&Bs19^>*+JnW^Vs{x)3Ljvu(# zzf7@wDOer(7_`pGR#Ma^b(OjrGt@S9m-;fe`H5DEJetPQY~pA&Q!Xu~5wy%1H!P4! zQG!-*G*{9FO3_BThPKhQw1ZaDt4zPfkv>dokwxneqBR)CZ!cwZ11_c;aXHiVbTc=< zTd;|4#jlxeB?o)xb{wEPaEu%Ubf+?e?ouYvMrAhBRdlaXNB1eK=ze7#(>JAPhq94& zDsA+fvV)#icF_yUTlAvx5$#qE(kp6^_NXSkst%&p)UousI*Z;=Yv=>jqL0)j`dD2> z2i4W|iMoaks5j83>K*i%`XGI-K1_$z$LNTfBVR-X;rJqXisV(SSV4O{hW(EA}cIQI1x$@$J#hA?DKWG^&G*N}t-!4*r(+ z){yVG@*o)+HEXm&qf<0z)9`HnAq}T#^aaszx`2YtJ;Mj5I+rxstI;8iZkF3eY3Ns! zt6?P1j#BYL4Kv(FDEA0?j*^l;g{R)2F5X7cy@B56UZ}C!S=(vvg3&Fg8Pfu*1D6r; zMB{Iizjdv&uO!3F;Jx@*GouAb9#edHTnm~_R|~Eb8Sa*p>3)(koFz`A$vjS`De|ex zmw}Pw<+V4dfZn1)+E3&8$NNNjm(J$D04DQuIzMOfp8=xBiF>Ai2H;7Km+02BWaOA& zN@N1R$_i3MM3Iz80C5q_k_q6FXnILGO#I{ODKFR9)4ZwR58WO1k6d$q;eq2R%D{NyKpi@(9+bMGY6Bpuwocyi9%n|t5od6)aX?{9zH{{_JF_$G@D=&{gi zqYwQ8TW+~aZn5h6^To?^w`5rf^q=;8Pn{9y86KG(Kn4RAvNj%qE$~P=s1?1yExPm4 zSH-BXMjkr_HmXp{%Qt5hg2wy;f$y4Zp)(R@+HZ}h zT{d=O5A`g|x#^(1DAlwKm%OqR*q`u5@lo+g7mbnN*w}~t1g^onD(49@ToD*dxb=B) zrtQ+O4cRz|L$sk5RAg0PD4{n8#W7h4iD!~wXwb7$nyQq=Fh(pCY>eVaN2Frc3Rp{S zwLuRE92#!(d>qKqNZU~}7+D-c(ZX>XkKqIz*78?5@Rwv5xylRt;*^Xcf)L2gOEn(& ziZK@0Hk=|a$DDe?#*=u8sZnzmCCSUKy5gw??jq&-ieY`R9b6O1dTi@YQWR!!5~nOY zW21!Aj9SZp2fI-q!z7iVt7y^5e}p7O?*Pu=tcB-nKB2MBSgb@!*7#V02EDXBw!#aF zFEjfUjg@Y#l!L%I?WWUNoW}(V7i~=7MS+LSbLpgJSnHa%>Qh__-jUfHpYXXHdT=g_ zOSo*|WgD;Pcn-DP(GgEZA_?yK=_!G&aa@zbiHgpPX%X@i%$x{>GkT)lmveL7f=&fr7qc} z1X@bfNbVk36%vZ|FF(0@aCREYd&l|S1vXE5zP!|^&B<`aovZRBHyM=O>Z}`j`hWAV zS1ovaRQW`DS1G1nc69Qs)LXp2{}+d)I={<_=`^i${J$K#DU@aDEy*Mgty-(L?Md91 znvm>*^)RT_`J^+UjOr|Aj7QcFly`GwrV;XOjyxczyPlhgu-&eN)jC~yHz)fAU+M(= zs>SsZdnc1bzuk_enQIm1wG7w&pjpI{!_)|w;;3}HVn$`BgGN}E=RKWzo08UkOxGxu zys;oqkqX`VlvE2rCCXq);P$nk;kco6gtN?|@3i;xXB?5$*UcbQ9M@^OU*B8|mYwCG zQLQ*DhDQ6i;sl|yyx=OwE$dbkwNWT`7iZ3mB#C@Szk!ytvl+ZAu>0H#W3OGHWQTz( zGt4AhQ4o4bi=&(Lfd*DQM=`K2+Mk1Z|=pJ*fXam+v zt9k^kIouU(UL`oYxgQ^8@i9KJ@Tu+!pRwSr%}t)a6fDYO+$Wh5?5F4HjzG^D-?qQs zCSe?oi>_a(%4ldZ2o@XlW{opr-TH>x!8pU}kV1Z=t>UK46HO80ZnZk?Dao2+Px$Pz z<5icQk1Tv4aB!VXX;3YEC9vnON%xT+x$n}dgLZ5z0)>oyHDu3nez2c+t+J$+Oj^g)3)`Sowm+0J8fSE zF84bU8P^jT*C`|R*&KD1ag|@~f$vD6rH>cx(C$0f@)Hh^-o?@TcpRAG!GR;f1k+8VN);V)t< z!!bxqMVhID5+gdEAUcj)Sftji#2zCWB)S%&Dmi2K6}jrr^=WP2Cl2U0hff*NacujV zqFIDenKyPbKb^|#BcP9U;Mz5B>1IBe!W>7xPGs+-3fa~z;)Qsjg75E}+1W|5Q1I~&ljr$%=9}Mryx(#6 zBa?RmSgR5#)S=!$gNa5Y6y{!Hjam7kRT|89@4Cb;_zH>DPRa4tDAccL>6?WlW*JDC zm<>~5VZj~FJFb<|G>CYpu2p=1r)GI5lN zH0CLo1#86GWUxqKj$gLz?%lmZ z?&#nU4L_!_B9b@8H97jEu+Piw(!XDf2vCCsl!B#jS;`M^5eE&2WEg@@S z2~MElV$3#skVcmGDJ+h-Wj@~<`>5HLnK%(ADau1t-q_6@l2684^u~K10#o;3{D$E{nJ%5YsdDN+J#)_GldLlC|eJPxbyn&~hcp6qQ z<~1#d^rQxDpMLl(6NULJT4w4KeB8*d#Ale!t@n@yYY8lF!OGsfN8Z zgr#sg&M?q!q64cH7FCR!Sr07pvTb>8N#VpAvO7CN>6&wkHPVp;J0e-Oy%Abv&&JtU zYhay;_1M5l)Ma0xW#`cCX+{U#)e$#3oHDR!N*@M|BXK^*M5hG#s33|_<#Z0D*aqjB z=)x9e*0W0kQN)+m@MdPzTl&&a=$5#juW^<1O=ZS+SYJKno!i8!VX+u;6f7@;bL}(j^tEA1!F|micHqgHB4>kOJb)& zN@LPa-}3e(VUbC{cMc>`AoR$zWX(3Q8-v6vcelchxU?`GF)yFQ%=B_e!NDa4_LwMw zVaQf0@v+c_=1Us4j|^Bo`|}7{tP~TwaU)z4BX}^@098tRO8rJ+8ql2tVX!&KK+ss^Ph!8qtmsu#U2fv}xPn+< z@Ab=8!566Pv5Q=Ih=>Zy;t2`m$3v@Eg*2BgD!h_X!jw~px6{*NZ037`ffo}^rmsco zMxEk-T~6UD)X&D%c$tBhn|K9YsnAqyU{S$NcYM2S`7YskK?SyS5IV#8j@fuMt}*Z$ z6R*YVxb#&eR7jYTAy{ZR63|%LRU8kT@BI$sMcMG^AeK(+yT6(XE_sL`f z7w_RT5)$VR5P+(!wUZDyTJ)2+QA4OaOIsZ<@S#fg>Nu?}m#uvg%M@yV#xJ2|V$B`WwWu5|RQ9%ry*`J-h%FAL=BI7x_B$Ml6ozotXs?zr{g{7lMevN~qG zSD;6$o4P5AHXe@!OC1q~#D40=Ci--w%?H!V?4)3zdz1FTGXVP76 z!7BDyWk=q_$p(MO;j*8Jbm#)C?l&2o1ylLK^S)1nnBfL%VByR2TA*2WK2y#J=_zQe*8^GbrY{mTG>E)L%9H3M`74mh8jBE?8w76bxh4^B zB2Q%7u)+2UWoINtJ_@mo;udnI!q`iQ zj(-gFc3e2Kq{BLm8@b*p7JIlSV-K61rIKAn!KXU8#L&OIyWr{R6Z-iu=XpOd<(;<^`Wr7B^e?Xr_?wnH0REb! zZNw+Z_bI+Tz~5Q?U6nfsm1`Y`ky|;AIk~oR%*|yQ#xXyaX&lGGTqZG&#kq_zj^lHg zB5*$EMNd=iHY{!BV62?La`CQCdnY$mpyWANuC31o)RFZ~xJ$>B5^%S+Ug3-Q zQYifzN*CK(D0pG(1llI?bfB?u0;g?RnLhIn&Z@&-$*9PPQfsp|%_%gmib@S-#+iNgaE#T=P zwBU5@R**r1uFRRlR$#icvtrVkLVpy#jZ*_Dbxo`%c7mF73!W)e&^n2JU;@wL%i{F2 z)6bE~^sd(1F))E4zAThtnSVPDAmd#^H?CweU5g$ZKrc<%&c^6tuKRHxFIn!#1$YP-suV8P zi4YLDi%s<%)@hQ|3oy~(Cd@9N4f;W~Uz1H%E{aomXS zvqBkb(JxV6SK+?cQ183{;Y6DjpJSF2{wp*QCN^q1$ z5v&jtFj^1cgG!fH0DVEL6tqVH=ol62>5JH`q8=nWXYS!lP{co?NM1&SD$ZuNiVE`% z+_Xaq>mWWny@Z{Z9y8KoQmRBLkosdv;nAJ%V)(6$t-w!zwWtX&m7=~SO!#eKQMay~ zrbaFIsiVU|aU~R*RwhV;C_am v^LGsq@?om@g&u#U$KUAj0X_a+kAKwTgL-^OkAKzU-^Ff9Q2eV`jmZ25tUjK> diff --git a/target/classes/com/ioa/conversation/ConversationFSM$ConversationStateUpdate.class b/target/classes/com/ioa/conversation/ConversationFSM$ConversationStateUpdate.class index 2c2c0177625e437db79414a5fa5b884ccec96013..ee81057f56eda813e3210d088687d407e3547850 100644 GIT binary patch delta 25 hcmcc3ahqeqO=jLj3@i+b8F(0$FbFa%o&1cs6aa132mk;8 delta 25 hcmcc3ahqeqO=jMu3@i-G7z$NFXc;nH9nu2_Ef^(4yU$_0Fs? zq$T%#G;QNFkhV!vx9*X)Ng4#gZPF`go2K`bruTi{cj|_I-<#RpS&$6teMQ2_W9(o$qQE66EyA1+F9>_puV$f zVhN&H5<$#BGYrADw3AO}9W$AB>{+YmnqJnill`Gd$}>Gn5IZ!K>OYZ64ILX5bPnI& zvEC(U!LkTi4J=pOI_`OFFf}4D(xqb2vOUdOkyv41B_0qo=ADd{Bb^F=y^uU;Wr|LE zW|&%+%=6ZW+NF7~GO!wJXqAiBWQsd1FJ%>HvuP@{xkAJBmy##%*wY)qT0ue^wB%)T z%0_`?%0j_#IBU;XnWsxu$%^4Y)GK*67}$t770Fw!OM&!P!SdlMExkkzn*}SXt9`|y zd1*N7dNFMBNo_T-4G)o2!7O^&bhcpHo=b&7q||<`ZI^+BV!PBWSmsRDKChWXu$`={ zJdT*|^oUuAq1)$>G_Vs7)3~#aXOZ->5NYnCjE@Mqs^>#iFg+)qO(*;GpM#E*vrIdN zU3g4^akrqM^Rz--3m!M{1ojG|Q-q>BZDj=AAvX6Q*&D?^0TiJF2A;%gi0Pu`mU0Al zn@>gqKIIjuv^K>-1N~}W3rSaSJ(Ow200tvCY~Ton__eB)G9n|y%uuukIzvSLDC+Gx z-HfL&9KnczQFV4%^=#nYMrUfuD#kE|rz1FSAcb+ksxssW1KUgXsox=c%Avi_Tiy`4 zt?cXyu?uvFVFD*3c*ejfoG!ahD;bzs5ScY|CF|Ifpq*w8kqCD5HsdT_8^P-goWrw3 zMO9$BmAV#6)cElQbPdreYk&7r6qABAVe_5~Lo|jAtO%wIoX4~vUN*yG!Nv^ZT6X3{ zA*0jHLt(K3o7^o!*MxHD1p_n6Bg91BnYEOkE-2k?wN68C3)5O$p%~%yoPnasqRR@* zCyd<@KYm?B(=$-QEbX3k2l55)lFp~672KaUa7lfsr$^P!*Bkf-d?VpsaB|F6wGIvh zh~N!^b!DrB&6o_BDtX>y;LUgoeK&2|nVc1T5o}r{0|y&=yC!0|g0~rXyTV|Ma`ij5 zN9aZIP9iU=rD^MA(J?b=)Ad4TxMtuZ>SJ?B!$a2v zb?7?`e5Z2Pa@+B;QJ5Tu^rWgn=K@5VW2vnK@VGfFCjNNhNbj z(Mns{*|P7V_%sm__V>BG4>CpPGb-M%-y5=l{oB|A+%Rwx^Gq~(>P;`FO;0(DBYIEQ zilbrt-yKVfu7q<+uqlR@@naGExPi~&bF86d{4QRGX?~_WWq-QACfWRd__jgtlSoXj)T@y9MFYQpFR?6p zMbmb(s%si&s_9-NF6oU*71HR{5juunGVsgz6$Xh9;PFz?X05#sBJ7hii5C2tfnQfK z5KB*6=@}Jf%vNXdn+ARhzs;nms|3sX>Kf?xGc&O{q}T-i@8ByD{H}rD!|xNDRq$6g zk&f#XEi*4zTSLcRP0|hg*xSZl^bZaE5&l@&+)@=aUbB6wWNW6$v7(j95~>#2|0(_~ zf!%eU}-~xEH|W0R?vTDp^#(6-&kXv3ibvASSx_Z1BSHADk3Pax~y`_s|9Q2z~Weq z$r^buB5MsUF^U7&bx+ebHSDTMPO_N~G0L7KwR|N4u-a$sFrnBou9BOn0zyVO8zz@!;0EttQNToaz7#V@UyL zMb6AmX3UOiaqifu+Rz1X*2R0CFrZc}@QtFRoKi7u4Q3TmR)#Y?Gk%ZaO&1+!Ma$-` z2^xb4>a*EZ=m#C@l^Ax4=aX(h-H@k>X5PB!6lany3##RKmkJh(NS-F+6@gMWkFs`; zSPGjw+R8}qm=?^!h~-T?88<2^!P!GJdd7--(^gy=mN&d=j}zBEi%*)am5DnxH)Y*; z0D--6iS_#rJpMMd5Q2`&c~nk_;9$-1io^HDxWDMk-iv!@^~q{`EYAPN`%+JxJKQ&Z zWZ?MF=;3oiql3q)AF88sW5a!;qudc%>f_7T;n9(S(Q$uq;F*E`6XSdg^QZmCM*D|P zsK>Fcp7=34cPW0JEx)#nOM~aEIL)1jvsJuk72{buZsv0Fv{`Uz9B!T>ZuMq$%8ok) z)tI?Gtr%L?B+sb2eaes{GSn(VQ8_E9srd17=g<>Bu46*kldv^&74x>jS=K1$V)Cq* z5t%e3t-50W^+O|ez%H@1Yp{unRw2OHAK$an&{5SJt_~^x{e?20kIA%TBf_isO<}Zl zRD&aH&pI=f>KJJl;+Rd~pqb|FjOF#i;kXDk`j|VS@4s%xu;a{>3caBa37CdfY7UMQ z+Y4-8yc5v&2uSqPO)1_Ud#O@BCbl>cDH!scunXOMmrBDr)G4nyRaU4uAD(^b>#yFc z>R$8Fw`kZjHJ`QJ!p^vd7cI0 z)wiN9eWaOz1Ok-Q>0rb+xgqW z2Yc{=xdCfAT8CDwr>+|)|3<###<83B=)-1=U<+R!J7foU$9=h^N0OXTLTw+>BW0mF zYOoV81bQ6cT-mcp3Ex-ctn3Tgtr4A?YP-LyLbXXfwbCLY50is$lcbvSRAb^Z==&rG zz7kD(v0IZd{0#vakzMjgaQHICRxEe(a7Xt%4%Oi#hn*ZA^@ly(b2wIi6DQ_zre1$+ zZ!^{IIi#zCw^L*wNptN)J007po~HSltxV%9vAd$gZh2H5Q$ow`iX5|n9J>NJvQ;^9 zAvxxe_h*aCu$waMArYhZwYKMOiL(Rv{HukWdqEiP}Q8KT@;q1-Bu%M;YDPCai{tn5?Xt|-rg5qu4sIo>mei`TH)U%f2&30xUY z(B5x+>Gqcu*Ln>{-?j&-Q$GQBh_)Rd3fJGqj|xV%&*QrVSFweI?^AXd8{I+J z`I7zMHAHuC_`@&V{tAz@w|$BejXmE!zH})D={W6jf(Sf`NAL{xmOG z<3L5u10gvL)W3pQ1TSv=s7 zMt9tz?AY6&R@OAArM-=78t3rSH}QqNO^G#4bNKlxoHl5(XZi1D&oY}#(peXnTXKx> zJO*KF;g9&NDE+Hkp4=+?II8FQ^|GI%22xor2RLfv{}FkTj%(shKHvr_ zd0Iti5O&T(LvL)j`wLjnP0#-##V==oDhPZSK8K|Q_Hwv{qel?Th5)cRka8*i0r52| z#5Dk-kXNuN!gty_^-LW|Fh+UnXw;SD)zjTj%`bEK)vAU3fV;$CyUa@P`Vg;`6^pEt zK5D4~j*oKz^*067A5+xl@f(79d|6mN{s0{PNgaRwO7PBoYx$iJ{5#f|+>2O}X#1x* z{7Y43zDrQVD@^-uU{QD@9>tqOB0Ls|uo3NYQ2GOPDZ(pwRHbCTSOwyEfjHe{x2L{g z4*z}?n-XfKuyhOm4X^-l+TQj*{M}yzZ(oSF(T8s*jNd^ozbhm}cf}6fa!A=h+q|CD zk;4JZ1`_O2`Ifpwl?2Q>pWrxLC*G?``gI~2kQ5nQu*mGcv&eiPbht4%T&Esw1LkLl zVdd+Ms@g5pYX0xbxP2D5UPjin<#$tm$_3%En*S z9vmkdrRBPt61^$Sx1^QsmX&qvj91UghB^l4Kvj6(uveMQud&2`gvI`9NRf3uC-EDa z!>uuOD+m;-mfShne5Wa|gorfCQF)32HOer5>tsYm`B$Oz7$9RDH&Ec)@-#=C+%?57 p$Mx^HT6vvh#N}@F{(BoO!bp~qT$D>#^M7jhV-o-X literal 8766 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 N`1`axE6<_v{{Xg;ExiB$ diff --git a/target/classes/com/ioa/conversation/ConversationManager.class b/target/classes/com/ioa/conversation/ConversationManager.class index 07f856f57da4f8b75ed7a3e6fdc13f412f34e3c4..26669a30f937ee6296c3e467c68962e1a8320140 100644 GIT binary patch delta 1953 zcmbtVS#(oX6x}y3$xB~uUQ3GUAcf)pX_``@1A#IWN-H2#XbKe&YHULZgcOssKpg@& zPbgkR1wnAa8QNl?MX{)W)(MB@k1qf8L%;l%>8h1tTS_-(bA z!!Z~0#CoO5TF(h(q1dlfTNiOO()N<#vfqrwDwc38#Vz75rN+9PqZzjfuQ_C2i53-p zj#gBQBj(bChSg|OaT~`PtYygC9Ow;Hh69nV%GOQMV4#!1(a{r)1|#t+_v77V%dU>9 zlQ6e)tj7jQ=nBUD@j%Cx)@Yz3$WZDoTQ?>n`>HV<^lT+$%Dw{u6?bxY&~b%CPdpT^ zTo8>0cE%W{y4Q(m%0%(2MQzd$#6}fe9Geij5^YfS$D^T07lRrNZVMZ=UG9d4v2;@r zbvA4fKbvdVRx!>p*&aqWhXvahW{KT7H;NS&CofwqrxN9eAue`VYIAy}hT9pYP)NSm zWzKimu#>^+U*m6WT<(MkcXQl>d&S?D75Z-MQE@-V19*_3WZ(R2M8sNae;ALbc$DKY zJT8t~4>v!_u@~hGIV4z1FxC@}+we4ltD!s68;r&R@lbc9G}0X}-Pqj|>6Cn);ShLM zx+K;_Mu}|-(ts3q*;*U+i-T&B^#zU>Q9U@U`dEH0!H$JuWFX?s$_7VmKQT5ej%th9 zhvE-y#)OYG*fGK}fWcfVKGE0Eg|7$gJfE>kVv@td zz86a!bJYW6XA=&Jy^bP#4j8F<6Rj_a0Y?=(Bz|{Hsyj>(rBGW^m;xPBNeDMl@))=t<9T5Q zw=j(h6yhzsO;vSh26+YV5P}WtG741k2cu7bQJJ3hQ5@lmGkVU|92&0XP(g^(h(jfD znEt;x#IP+b=Wnpe(In75fTnV9#W0ouNv!yfy0gti<_oB*xQLR|Se3-O(`e80=4nZE zwo#gMGbQvFna?1+h9FKMlEhudkSh^~(PQ9c`|*%6a#}iS$ON@CshOCPfR8S-Fdwr~ zk2z?;JZzwy9AdTMo%W2_?HRG#@h&+`GShs5rxBB} zm>OvwGa+AwxGzK8hZ6>Io%|#%t|YQHq2Cf|lYVSZvyD=R@>CXQ*h;d?y<}H%>k}uO zPswvO*03vyP7BfTlUY_7R8r@n*7qF2`nK3@=WQTB=#LZ zj>q|263=Hf&<%P^=x{HEgZv|h##0#vI1FqB%t5N3q?aaqKpq24f#DQgPtzBLPL6_e c^kB$X&)_26e}uF2{|$v`^yXW9haXV%FF4A8i~s-t delta 1587 zcmbtUS$9)a7~Ll~%}sAk22*I$LNP72D{T^>b6RMTQIIAGt(H;|D@2L5MLRg45{jZg zaXgMFI15hD0aIGma>)a@mM{7PeDc*7e*jC}_a>_Yudb|n&dvSK_wBvEZ{K@8^v7Ms zum8;c1YiSZCyc*rZWn4%r=wn?0gb9g>u}a0Cee%*bw;amtdnR(o4TRZJMNZDYE%De zg|1E5tYeGBR@|e4_6EmxiF>g__1IIcI1)N`O5BHC>Nk5(NiCo`(V;X)gScNcJIZ7y zx+LRgu7Hpw_h#O@(lwK?3L)jgX*HA(Rj!#x?i9&q|VtZf==`bI6AsJI=96A zu;GBjK_msV!I1%hbs@FEs8k(#(3QgDI-Zc|L%%wzCp?Goq>iT~1~DWMRipY+^|uHp z-8ryyMB-_L1@a$D4)0D5jr0vW@vJ)SEM0p<;(5FvV5Ek&rUp_&hmr>g6{_0n#8Cl% zXR1FL>`V2hhJ%C2-UE!9=V%OB4&X|}=8JC3kR0ZTV@ww`iwadRU;KJ7uAK*i; z0~ZZ^gKu?wXNvq@U6waImkeCSxQ+>lNlZ;0cNYkIMxa9ZJVk2U;}ciabx&*fIEQD$ zOYrkozf8D=e^VW3L`;iT+8t)PO33)arzX(<|#fq z47(MpxQg-&LhaWO>8`#4AFn0TSQY1Pgd;Pk(a;qhXMznUxcZp}lt9NaQdo|aD8)Qb zg$cyCjukkKF+vr=gEM%I*@CXhd)-7=qrQT4lMO#3l8D}fGaAWY?F7@b1rTLSEGOJb zmZ-2Gsx9b14gv_|Ak4cr@FpQVFf1?)Z?PJ?atlQ|ha~7?3z<)k@Ej$mF<<`e9M<2? zA;gMRL>*S4o=+Ruju_%d zw^*9$O)f~x^))fq*96|?5N%de@lLafnd7uu9X6od!fJN-4i}ZZgLiZK&QqUhlh`6b z=Bz_eOMw632oJUWR(GZ@H2*SwNKi(D&}v~dvYY4?q2V!KSwWepLV zBOaS09>aSUaSzX!bQc(+DQk%Lu^;K|GzO{Ad`n6ev5iOQOd4}|-2aSe|ApS%K|1ZE z6Q?hBT2!*{S;-ugk{lHeWX}GJ9O*O6Z$diPuI(fs2;r&D;JLHNulB!~L3+Li9*f>4 zzEzvy<_Fl+F0&a{aahC9Al&TwSq5$R2p@BI@X$H#=XnKK6kC?^`ivI(>qz&2t diff --git a/target/classes/com/ioa/conversation/ConversationState.class b/target/classes/com/ioa/conversation/ConversationState.class index ce8022f73bf901f9c2bf5d6002a2bf54253670a1..4396d11e218516a58da27f802695c7fb070e4e3f 100644 GIT binary patch delta 680 zcmZXR%T6Le6o&umrm5V* z=F2-a7(PgJBgoLDHh%5z<~^_EZL3U=M7aJxGWSuUPbuu;QL#`tEbVzJJ0KBJyG~)x zE9_Rvo$W!1A;juW%b{U>;)qF%AmLB5L@0$(jxmWe#{FYf5h-LOvY7N+EECTN*aA|Z zTOcgZClGPykOhfFEH$6mUuLDqh4BBF6SeiIx)4B-t^l}$>P$*ou(6CKDqJB-QdGlf zAbN@TJ%-PT7*^>U)H##%X{^D}`gw|~!U?nN6_WR0N^iW;f2Ez8Y|HQs-wA)vw5aYx zX~_>v-7QDaq!iCi##)%Tpym5k?M@u)%7*S_8{~)9H1oP-!*$df(2>eh2?215$hq7< z4J2w+(Lisx>INI=FTeLEP{2l~_Ka%P_l9wH85nugM**+CPv5ECW@pou=NU5fmU+> delta 614 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