From cb5012a07767172436922f3c85f853281587114d Mon Sep 17 00:00:00 2001 From: Mahesh Kommareddi Date: Tue, 16 Jul 2024 22:10:36 -0400 Subject: [PATCH] Working tree-of-thought for agent selection --- src/main/java/com/ioa/IoASystem.java | 32 +++++------ src/main/java/com/ioa/agent/AgentInfo.java | 4 ++ .../java/com/ioa/agent/AgentRegistry.java | 24 ++++++-- src/main/java/com/ioa/team/TeamFormation.java | 52 +++++++----------- target/classes/com/ioa/IoASystem.class | Bin 9248 -> 7901 bytes target/classes/com/ioa/agent/AgentInfo.class | Bin 3640 -> 3640 bytes .../classes/com/ioa/agent/AgentRegistry.class | Bin 3829 -> 5472 bytes .../classes/com/ioa/team/TeamFormation.class | Bin 6565 -> 6054 bytes 8 files changed, 58 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/ioa/IoASystem.java b/src/main/java/com/ioa/IoASystem.java index 3ec8824..f306842 100644 --- a/src/main/java/com/ioa/IoASystem.java +++ b/src/main/java/com/ioa/IoASystem.java @@ -109,27 +109,27 @@ public class IoASystem { 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")), + 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("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("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("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("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")) + // 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")) ); diff --git a/src/main/java/com/ioa/agent/AgentInfo.java b/src/main/java/com/ioa/agent/AgentInfo.java index 55b156d..96628b1 100644 --- a/src/main/java/com/ioa/agent/AgentInfo.java +++ b/src/main/java/com/ioa/agent/AgentInfo.java @@ -16,4 +16,8 @@ public class AgentInfo { this.capabilities = capabilities; this.tools = tools; } + + public List getCapabilities() { + return this.capabilities; + } } \ 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 272f8f4..5ea4d42 100644 --- a/src/main/java/com/ioa/agent/AgentRegistry.java +++ b/src/main/java/com/ioa/agent/AgentRegistry.java @@ -3,9 +3,7 @@ package com.ioa.agent; import com.ioa.tool.ToolRegistry; import org.springframework.stereotype.Component; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; @Component @@ -32,12 +30,28 @@ public class AgentRegistry { } public List searchAgents(List capabilities) { + return searchAgents(capabilities, 1.0); // Default to exact match + } + + public List searchAgents(List capabilities, double matchThreshold) { return agents.values().stream() - .filter(agent -> agent.getCapabilities().containsAll(capabilities)) + .filter(agent -> calculateMatchScore(agent.getCapabilities(), capabilities) >= matchThreshold) + .sorted(Comparator.comparingDouble((AgentInfo agent) -> calculateMatchScore(agent.getCapabilities(), capabilities)).reversed()) .collect(Collectors.toList()); } + public List searchAgentsPartial(List capabilities) { + return searchAgents(capabilities, 0.0); // Return all agents with any matching capability + } + + private double calculateMatchScore(List agentCapabilities, List requiredCapabilities) { + long matchingCapabilities = requiredCapabilities.stream() + .filter(agentCapabilities::contains) + .count(); + return (double) matchingCapabilities / requiredCapabilities.size(); + } + public List getAllAgents() { - return List.copyOf(agents.values()); + return new ArrayList<>(agents.values()); } } \ No newline at end of file diff --git a/src/main/java/com/ioa/team/TeamFormation.java b/src/main/java/com/ioa/team/TeamFormation.java index 19b30d4..d0c19b5 100644 --- a/src/main/java/com/ioa/team/TeamFormation.java +++ b/src/main/java/com/ioa/team/TeamFormation.java @@ -4,76 +4,62 @@ import com.ioa.agent.AgentInfo; import com.ioa.agent.AgentRegistry; import com.ioa.model.BedrockLanguageModel; import com.ioa.task.Task; +import com.ioa.util.TreeOfThought; import org.springframework.stereotype.Component; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @Component public class TeamFormation { private AgentRegistry agentRegistry; - private BedrockLanguageModel model; + private TreeOfThought treeOfThought; public TeamFormation(AgentRegistry agentRegistry, BedrockLanguageModel model) { this.agentRegistry = agentRegistry; - this.model = model; + this.treeOfThought = new TreeOfThought(model); } public List formTeam(Task task) { List requiredCapabilities = task.getRequiredCapabilities(); List requiredTools = task.getRequiredTools(); - List potentialAgents = agentRegistry.searchAgents(requiredCapabilities); + List potentialAgents = agentRegistry.searchAgentsPartial(requiredCapabilities); System.out.println("DEBUG: Potential agents: " + potentialAgents); - String initialPrompt = "Task: " + task.getDescription() + "\n" + - "Required capabilities: " + String.join(", ", requiredCapabilities) + "\n" + - "Required tools: " + String.join(", ", requiredTools) + "\n" + - "Available agents:\n" + formatAgentDetails(potentialAgents) + "\n" + - "Instructions: Analyze the task requirements and the available agents. " + - "Form the best team by selecting agents whose combined capabilities and tools meet the task requirements. " + - "Consider the following steps:\n" + - "1. Identify which capabilities and tools are crucial for the task.\n" + - "2. Match these requirements with the available agents.\n" + - "3. Consider how agents can complement each other's skills and tools.\n" + - "4. Aim to cover all required capabilities and tools with the smallest effective team.\n" + - "5. If a perfect match isn't possible, prioritize the most important requirements.\n" + - "Provide your reasoning for each step, then conclude with a final team selection in this format: 'Selected Team: agent1, agent2, ...'"; + String teamFormationTask = "Form the best team for this task: " + task.getDescription() + + "\nRequired capabilities: " + requiredCapabilities + + "\nRequired tools: " + requiredTools + + "\nAvailable agents and their tools: " + formatAgentTools(potentialAgents) + + "\nAnalyze the task, evaluate agents, and propose a team composition. " + + "Conclude with a final team selection in the format: 'Final Team Selection: agent1, agent2, ...'"; - System.out.println("DEBUG: Sending initial prompt to language model: " + initialPrompt); - - String reasoning = model.generate(initialPrompt, null); - System.out.println("DEBUG: Language model reasoning:\n" + reasoning); + String reasoning = treeOfThought.reason(teamFormationTask, 3, 2); + System.out.println("DEBUG: Tree of Thought reasoning:\n" + reasoning); return parseTeamComposition(reasoning, potentialAgents); } - private String formatAgentDetails(List agents) { - StringBuilder sb = new StringBuilder(); - for (AgentInfo agent : agents) { - sb.append(agent.getId()).append(":\n") - .append(" Capabilities: ").append(String.join(", ", agent.getCapabilities())).append("\n") - .append(" Tools: ").append(String.join(", ", agent.getTools())).append("\n\n"); - } - return sb.toString(); + private String formatAgentTools(List agents) { + return agents.stream() + .map(agent -> agent.getId() + " (capabilities: " + agent.getCapabilities() + ", tools: " + agent.getTools() + ")") + .collect(Collectors.joining(", ")); } private List parseTeamComposition(String reasoning, List potentialAgents) { - // Extract the team selection from the reasoning String[] lines = reasoning.split("\n"); String selectedTeamLine = ""; for (String line : lines) { - if (line.startsWith("Selected Team:")) { - selectedTeamLine = line.substring("Selected Team:".length()).trim(); + if (line.startsWith("Final Team Selection:")) { + selectedTeamLine = line.substring("Final Team Selection:".length()).trim(); break; } } if (selectedTeamLine.isEmpty()) { System.out.println("DEBUG: No team selection found in the response."); - return Collections.emptyList(); + return List.of(); } List selectedIds = Arrays.asList(selectedTeamLine.split(",\\s*")); diff --git a/target/classes/com/ioa/IoASystem.class b/target/classes/com/ioa/IoASystem.class index 525f66ab205e17b38dcd5dc34c6e6f5b128bf334..10fd1b84a26a96de4dcfa723d3ee41a13a61a746 100644 GIT binary patch delta 1582 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 LPvU8Op0fW1zC6MW diff --git a/target/classes/com/ioa/agent/AgentInfo.class b/target/classes/com/ioa/agent/AgentInfo.class index 6ac0c102a38bcc05a28fd982920d1f80cd630a19..2431e20d7be3524e82a7e2a7f1b3f47b123f20e9 100644 GIT binary patch delta 26 icmdlXvqNSB6UXEl4s}M+$uBu%Co^$WZ9d3R&I$l@ya;Ci delta 26 icmdlXvqNSB6UStCj;hH_9O{f*leIWxHy`9EX9WOjmIr76 diff --git a/target/classes/com/ioa/agent/AgentRegistry.class b/target/classes/com/ioa/agent/AgentRegistry.class index 8cf70e1b2721afa89e5aa1b7932bcaef5fcc8e43..e17b46fc64a62259a68d3ba921651b46a4366d84 100644 GIT binary patch delta 2324 zcmZuzYj6`)6#i}=-E?!CmbMha)8f!JDNxW+XAGUO5DG0&9<5NSP_|)dgK1JW8x(v5 z6-2=Yx+-c#e1i%Cf~76K6;yn`AAq3v*1!I79LIBaLlR3TlihpIJ@-4``OdjF`D^rP zzkKZ9{#O9h;LrW?YiaD#4HA+=N4@auzgyVW3 z=o@HpV<_r5W@C=gYA1BlEMjozYFuY%s4y0|ijCztxrGCP zf9eV5e@0#STx{98$uFRaHv?xP@G9;daScc(G)$VG31BLNjTbm7PmS(^OY&Is&nA8 z)gZuR3egPP!4bwP2A8I;QMI_bf?;^YfDIY{W<)qT5oO4U$247dPs!$xp&Q7?i0hiF zbXGN*uRxxRF07WIam1k;TO9SSW~|}38rK*n9W~YSWL%5uBwWvN1A+`gGIGpoTcw6X z%{`jBIuX{?hFG*A5s4JSj`gC3HyWqx7d1BHW{wTm$lwgc5>cwCy~0=TMkzLN+=|<% z(DCp(Dh!$HBy3?Q%EYMAG-a)5BN>}<2Zs}PGI)*2&f&R>WQ@dCj=PQJ&f;3pk_N}U zxR3USlt?HMQFL{#qK7&fLotou&+W{C?c@s{*yY^Lj3()LiKkO+ZR*g}ctaYQ&w>VXOH4;tfmS@lC?D};ld z9(uZwPoH8Gpqnfuvxv~#6#DbRD|$IXDklH5&0OX)o{qFX!_qnorA+6DyMKGZR4g}Ds=%8Gt8f+mY? zH0j4upchIX+J(baHk!oxkg(x3lxBF95Ew9?r;8+|$~MwOq*6Yi4{I4Jm-J%Y z;(n2ZDM%k~VwhICnO1LM*c97Ku2yBNMx6{7rjQC3U=%Ji`6NYu5nej`a=c)cN!Sk1 z$VRSi9K?$RBy_MkTX+eMme+3bvTE2vwnG@3VjG}6!e_`~Y+jPC<00HGDq}M{CTX?I zB_k)j1Y!#tNx z*orQrpBIS#E;hVM4Jyt{4a4g+c!R!WwD=9>`6f delta 1004 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