Agent to agent hub communications. Conversation stalls because they ask questions now.

This commit is contained in:
Mahesh Kommareddi 2024-07-18 13:07:25 -04:00
parent 6eadf28c66
commit fd66c81027
17 changed files with 170 additions and 276 deletions

View File

@ -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<Task> 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<AgentInfo> 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();
}
}
}

View File

@ -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<String> capabilities, List<String> tools,
TreeOfThought treeOfThought, WebSocketService webSocketService,
ToolRegistry toolRegistry, ConversationManager conversationManager) {
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<String, Object> 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<String> 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<String> 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<String, Object> 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<String> 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<String, Object> reasoning) {
// Implement a method to format the reasoning tree into a string
// This is a placeholder implementation
return reasoning.toString();
}
private List<String> 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<String> getCapabilities() { return capabilities; }
public List<String> getTools() { return tools; }
}

View File

@ -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<Message> messageQueue;
private final List<AgentInfo> participants;
private final Queue<AgentInfo> speakingQueue;
private final Map<String, Boolean> 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,63 +70,52 @@ 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());
broadcastMessage(message);
updateState(message);
notifyNextSpeaker();
}
}
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: <state_name>";
String response = model.generate(decisionPrompt, null);
ConversationState newState = parseStateFromResponse(response);
transitionTo(newState);
// Broadcast the message to all participants
private void broadcastMessage(Message message) {
for (AgentInfo agent : participants) {
if (!agent.getId().equals(message.getSender())) {
agent.receiveMessage(message);
}
}
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 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 notifyNextSpeaker() {
AgentInfo nextSpeaker = speakingQueue.poll();
if (nextSpeaker != null) {
nextSpeaker.notifyTurn(this);
speakingQueue.offer(nextSpeaker);
}
}
System.out.println("Could not parse state from response: " + response + ". Defaulting to DISCUSSION.");
return ConversationState.DISCUSSION;
}
private void handleVote(String agentId) {
votes.put(agentId, true);
@ -152,8 +150,7 @@ public class ConversationFSM {
}
private List<String> 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());
}

View File

@ -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;
}

View File

@ -3,6 +3,8 @@ package com.ioa.conversation;
public enum ConversationState {
DISCUSSION,
TASK_GATHERING_INFO,
TASK,
TASK_PLANNING,
TASK_ASSIGNMENT,
EXECUTION,
CONCLUSION

View File

@ -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) {

View File

@ -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<AgentInfo> 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<String, Object> 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 conversationId = conversationManager.createConversation();
ConversationFSM conversation = conversationManager.getConversation(conversationId);
String executionPrompt = "Based on this execution plan:\n" + reasoning +
"\nExecute the task using the available tools and provide the result.";
Map<String, Object> 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.";
for (AgentInfo agent : team) {
conversation.addParticipant(agent);
}
String result = executeToolsFromResponse(response, agent);
conversation.postMessage(new Message(conversationId, "SYSTEM", "Let's work on the task: " + task.getDescription()));
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.";
// 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();
}
}
if (!conversation.isFinished()) {
conversation.finish("Time limit reached");
}
String result = conversation.getResult();
task.setResult(result);
conversationManager.postMessage(conversationId, agent.getId(), "Task result: " + result);
System.out.println("Task completed. 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");
}
}
return result.toString();
public Task getTask(String taskId) {
return tasks.get(taskId);
}
}

View File

@ -1,13 +1,26 @@
com/ioa/tool/common/TranslationTool.class
com/ioa/tool/common/PriceComparisonTool.class
com/ioa/service/WebSocketService.class
com/ioa/tool/common/WebSearchTool.class
com/ioa/conversation/ConversationFSM.class
com/ioa/conversation/Message.class
com/ioa/util/TreeOfThought.class
com/ioa/tool/common/NewsUpdateTool.class
com/ioa/tool/common/RestaurantFinderTool.class
com/ioa/conversation/ConversationFSM$ConversationStateUpdate.class
com/ioa/IoASystem.class
com/ioa/tool/ToolRegistry.class
com/ioa/conversation/ConversationState.class
com/ioa/tool/common/FinancialAdviceTool.class
com/ioa/agent/AgentRegistry.class
com/ioa/team/TeamFormation.class
com/ioa/task/TaskManager.class
com/ioa/model/BedrockLanguageModel.class
com/ioa/tool/common/DistanceCalculatorTool.class
com/ioa/tool/common/MovieRecommendationTool.class
com/ioa/tool/common/AppointmentSchedulerTool.class
com/ioa/agent/AgentInfo.class
com/ioa/task/Task.class
com/ioa/config/WebSocketConfig.class
com/ioa/conversation/ConversationManager.class
com/ioa/tool/common/WeatherTool.class
@ -15,17 +28,4 @@ com/ioa/tool/common/TravelBookingTool.class
com/ioa/tool/common/FitnessClassFinderTool.class
com/ioa/tool/Tool.class
com/ioa/tool/common/ReminderTool.class
com/ioa/tool/common/TranslationTool.class
com/ioa/tool/common/PriceComparisonTool.class
com/ioa/tool/common/RestaurantFinderTool.class
com/ioa/IoASystem.class
com/ioa/tool/ToolRegistry.class
com/ioa/conversation/ConversationState.class
com/ioa/agent/AgentRegistry.class
com/ioa/task/TaskManager.class
com/ioa/model/BedrockLanguageModel.class
com/ioa/tool/common/DistanceCalculatorTool.class
com/ioa/tool/common/AppointmentSchedulerTool.class
com/ioa/agent/AgentInfo.class
com/ioa/task/Task.class
com/ioa/tool/common/RecipeTool.class

View File

@ -1,16 +1,30 @@
/Users/emkay/Projects/totioa/src/main/java/com/ioa/util/TreeOfThought.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/WeatherTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/conversation/ConversationFSM.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/model/BedrockLanguageModel.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/conversation/ConversationState.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/task/Task.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/FinancialAdviceTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/conversation/Message.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/service/WebSocketService.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/TravelBookingTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/agent/AgentInfo.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/DistanceCalculatorTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/TranslationTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/AppointmentSchedulerTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/agent/AgentRegistry.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/task/Task.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/MovieRecommendationTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/RestaurantFinderTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/conversation/ConversationManager.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/RecipeTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/service/WebSocketService.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/PriceComparisonTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/FitnessClassFinderTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/ReminderTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/Tool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/team/TeamFormation.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/ToolRegistry.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/CommonTools.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/task/TaskManager.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/IoASystem.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/agent/AgentRegistry.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/NewsUpdateTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/tool/common/WebSearchTool.java
/Users/emkay/Projects/totioa/src/main/java/com/ioa/config/WebSocketConfig.java