Skip to content

Commit b2bde07

Browse files
Merge pull request #13 from flowdevs-io/coordinator-agent
Coordinator agent
2 parents 2780d7f + 34e9d1a commit b2bde07

3 files changed

Lines changed: 173 additions & 18 deletions

File tree

FlowVision/lib/Classes/AgentCoordinator.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
namespace FlowVision.lib.Classes
99
{
1010
/// <summary>
11-
/// Coordinates communication between the planner and executor agents
11+
/// Coordinates communication between the user, planner and executor agents
1212
/// </summary>
1313
public class AgentCoordinator
1414
{
@@ -19,6 +19,10 @@ public class AgentCoordinator
1919
private const string EXECUTION_RESPONSE = "EXECUTION_RESPONSE: {0}";
2020
private const string STATUS_UPDATE = "STATUS_UPDATE: {0}";
2121
private const string TASK_COMPLETE = "TASK_COMPLETE: {0}";
22+
private const string USER_REQUEST = "USER_REQUEST: {0}";
23+
private const string USER_RESPONSE = "USER_RESPONSE: {0}";
24+
private const string COORDINATION_REQUEST = "COORDINATION_REQUEST: {0}";
25+
private const string COORDINATION_RESPONSE = "COORDINATION_RESPONSE: {0}";
2226

2327
private List<AgentMessage> messageHistory;
2428

@@ -81,6 +85,26 @@ public string FormatTaskComplete(string summary)
8185
return string.Format(TASK_COMPLETE, summary);
8286
}
8387

88+
public string FormatUserRequest(string request)
89+
{
90+
return string.Format(USER_REQUEST, request);
91+
}
92+
93+
public string FormatUserResponse(string response)
94+
{
95+
return string.Format(USER_RESPONSE, response);
96+
}
97+
98+
public string FormatCoordinationRequest(string request)
99+
{
100+
return string.Format(COORDINATION_REQUEST, request);
101+
}
102+
103+
public string FormatCoordinationResponse(string response)
104+
{
105+
return string.Format(COORDINATION_RESPONSE, response);
106+
}
107+
84108
public void Clear()
85109
{
86110
messageHistory.Clear();
@@ -90,6 +114,7 @@ public void Clear()
90114
public enum AgentRole
91115
{
92116
User,
117+
Coordinator,
93118
Planner,
94119
Executor,
95120
All

FlowVision/lib/Classes/ToolConfig.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,24 @@ 5. Be precise and thorough in your execution
4747
4848
You have access to tools like CMD, PowerShell, screen capture, keyboard input, mouse control, and window selection.";
4949

50+
public string CoordinatorSystemPrompt { get; set; } = @"You are a coordinator agent responsible for managing the conversation between the user and the AI system.
51+
Your job is to:
52+
1. Understand the user's request
53+
2. Send appropriate tasks to the planning agent
54+
3. Receive and evaluate the final results from the planner
55+
4. Format responses back to the user in a helpful, conversational way
56+
5. Handle any follow-up questions from the user
57+
6. Maintain context throughout the conversation
58+
59+
You are the main interface between the human user and the AI system including the planning and execution agents.
60+
Focus on providing clear, helpful responses that address the user's needs completely.";
61+
5062
public bool UseCustomPlannerConfig { get; set; } = false;
5163
public bool UseCustomExecutorConfig { get; set; } = false;
64+
public bool UseCustomCoordinatorConfig { get; set; } = false;
5265
public string PlannerConfigName { get; set; } = "planner";
5366
public string ExecutorConfigName { get; set; } = "executor";
67+
public string CoordinatorConfigName { get; set; } = "coordinator";
5468

5569
public static string ConfigFilePath(string configName)
5670
{

FlowVision/lib/Classes/ai/MultiAgentActioner.cs

Lines changed: 133 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,20 @@
1313
namespace FlowVision.lib.Classes
1414
{
1515
/// <summary>
16-
/// Multi-agent actioner that coordinates between a planner agent and an execution agent
16+
/// Multi-agent actioner that coordinates between a coordinator, planner agent and an execution agent
1717
/// </summary>
1818
public class MultiAgentActioner
1919
{
20+
private IChatCompletionService coordinatorChat;
2021
private IChatCompletionService plannerChat;
2122
private IChatCompletionService executorChat;
23+
private ChatHistory coordinatorHistory;
2224
private ChatHistory plannerHistory;
2325
private ChatHistory executorHistory;
26+
private Kernel coordinatorKernel;
2427
private Kernel plannerKernel;
2528
private Kernel executorKernel;
29+
private AgentCoordinator agentCoordinator;
2630

2731
// Configuration constants
2832
private const string TOOL_CONFIG = "toolsconfig";
@@ -33,8 +37,10 @@ public class MultiAgentActioner
3337

3438
public MultiAgentActioner(Form1.PluginOutputHandler outputHandler)
3539
{
40+
coordinatorHistory = new ChatHistory();
3641
plannerHistory = new ChatHistory();
3742
executorHistory = new ChatHistory();
43+
agentCoordinator = new AgentCoordinator();
3844

3945
// Load tool configuration when the MultiAgentActioner is initialized
4046
toolConfig = ToolConfig.LoadConfig(TOOL_CONFIG);
@@ -73,20 +79,33 @@ public async Task<string> ExecuteAction(string actionPrompt)
7379
toolConfig = ToolConfig.LoadConfig(TOOL_CONFIG);
7480

7581
PluginLogger.NotifyTaskStart("Multi-Agent Action", "Planning and executing your request");
76-
PluginLogger.StartLoadingIndicator("planning");
82+
PluginLogger.StartLoadingIndicator("coordination");
7783

7884
try
7985
{
80-
// Configure planner first
86+
// Configure coordinator first
87+
coordinatorHistory.Clear();
88+
coordinatorHistory.AddSystemMessage(toolConfig.CoordinatorSystemPrompt);
89+
coordinatorHistory.AddUserMessage(actionPrompt);
90+
91+
// Configure planner for later use
8192
plannerHistory.Clear();
8293
plannerHistory.AddSystemMessage(toolConfig.PlannerSystemPrompt);
83-
plannerHistory.AddUserMessage(actionPrompt);
84-
94+
8595
// Configure executor for later use
8696
executorHistory.Clear();
8797
executorHistory.AddSystemMessage(toolConfig.ExecutorSystemPrompt);
8898

99+
// Clear agent coordinator message history
100+
agentCoordinator.Clear();
101+
agentCoordinator.AddMessage(AgentRole.User, AgentRole.Coordinator,
102+
"USER_REQUEST", actionPrompt);
103+
89104
// Load model configurations - use either custom configs or default
105+
APIConfig coordinatorConfig = toolConfig.UseCustomCoordinatorConfig
106+
? APIConfig.LoadConfig(toolConfig.CoordinatorConfigName)
107+
: APIConfig.LoadConfig(ACTIONER_CONFIG);
108+
90109
APIConfig plannerConfig = toolConfig.UseCustomPlannerConfig
91110
? APIConfig.LoadConfig(toolConfig.PlannerConfigName)
92111
: APIConfig.LoadConfig(ACTIONER_CONFIG);
@@ -95,6 +114,15 @@ public async Task<string> ExecuteAction(string actionPrompt)
95114
? APIConfig.LoadConfig(toolConfig.ExecutorConfigName)
96115
: APIConfig.LoadConfig(ACTIONER_CONFIG);
97116

117+
// Verify coordinator config
118+
if (string.IsNullOrWhiteSpace(coordinatorConfig.DeploymentName) ||
119+
string.IsNullOrWhiteSpace(coordinatorConfig.EndpointURL) ||
120+
string.IsNullOrWhiteSpace(coordinatorConfig.APIKey))
121+
{
122+
PluginLogger.NotifyTaskComplete("Multi-Agent Action", false);
123+
return "Error: Coordinator model not configured";
124+
}
125+
98126
// Verify planner config
99127
if (string.IsNullOrWhiteSpace(plannerConfig.DeploymentName) ||
100128
string.IsNullOrWhiteSpace(plannerConfig.EndpointURL) ||
@@ -113,6 +141,16 @@ public async Task<string> ExecuteAction(string actionPrompt)
113141
return "Error: Executor model not configured";
114142
}
115143

144+
// Setup the kernel for coordinator (no tools, only coordination capabilities)
145+
var coordinatorBuilder = Kernel.CreateBuilder();
146+
coordinatorBuilder.AddAzureOpenAIChatCompletion(
147+
coordinatorConfig.DeploymentName,
148+
coordinatorConfig.EndpointURL,
149+
coordinatorConfig.APIKey);
150+
151+
coordinatorKernel = coordinatorBuilder.Build();
152+
coordinatorChat = coordinatorKernel.GetRequiredService<IChatCompletionService>();
153+
116154
// Setup the kernel for planner (no tools, only planning capabilities)
117155
var plannerBuilder = Kernel.CreateBuilder();
118156
plannerBuilder.AddAzureOpenAIChatCompletion(
@@ -164,12 +202,18 @@ public async Task<string> ExecuteAction(string actionPrompt)
164202
executorKernel = executorBuilder.Build();
165203
executorChat = executorKernel.GetRequiredService<IChatCompletionService>();
166204

167-
// Get initial plan from planner agent
205+
// Get initial coordination from coordinator agent
168206
PluginLogger.StopLoadingIndicator();
169-
PluginLogger.LogPluginUsage("🧠 Planning approach...");
170-
PluginLogger.StartLoadingIndicator("planning");
207+
PluginLogger.LogPluginUsage("🗣️ Coordinating request...");
208+
PluginLogger.StartLoadingIndicator("coordination");
171209

172-
var planSettings = new OpenAIPromptExecutionSettings
210+
var coordinatorSettings = new OpenAIPromptExecutionSettings
211+
{
212+
Temperature = 0.2,
213+
// No tools for coordinator
214+
};
215+
216+
var plannerSettings = new OpenAIPromptExecutionSettings
173217
{
174218
Temperature = 0.2,
175219
// No tools for planner
@@ -183,15 +227,34 @@ public async Task<string> ExecuteAction(string actionPrompt)
183227
: ToolCallBehavior.EnableKernelFunctions
184228
};
185229

230+
// Get the initial coordination
231+
string coordinatorResponse = await GetAgentResponseAsync(coordinatorChat, coordinatorHistory, coordinatorSettings, coordinatorKernel);
232+
PluginLogger.LogPluginUsage("🎯 Coordinator Assessment:\n" + coordinatorResponse);
233+
234+
agentCoordinator.AddMessage(AgentRole.Coordinator, AgentRole.Planner,
235+
"COORDINATION_RESPONSE", coordinatorResponse);
236+
237+
// Send the task to the planner
238+
plannerHistory.AddUserMessage(coordinatorResponse);
239+
240+
PluginLogger.StopLoadingIndicator();
241+
PluginLogger.LogPluginUsage("🧠 Planning approach...");
242+
PluginLogger.StartLoadingIndicator("planning");
243+
186244
// Get the initial plan
187-
string plan = await GetAgentResponseAsync(plannerChat, plannerHistory, planSettings, plannerKernel);
245+
string plan = await GetAgentResponseAsync(plannerChat, plannerHistory, plannerSettings, plannerKernel);
188246
PluginLogger.LogPluginUsage("📝 Initial Plan:\n" + plan);
189247

248+
agentCoordinator.AddMessage(AgentRole.Planner, AgentRole.Executor,
249+
"PLAN_RESPONSE", plan);
250+
190251
// Now execute the plan step by step
191252
bool isComplete = false;
192253
int maxIterations = 10; // Safety limit
193254
int currentIteration = 0;
194255
string finalResult = "";
256+
// Store all execution results for final response
257+
List<string> executionResults = new List<string>();
195258

196259
while (!isComplete && currentIteration < maxIterations)
197260
{
@@ -201,15 +264,24 @@ public async Task<string> ExecuteAction(string actionPrompt)
201264
// Ask executor to perform the current step
202265
executorHistory.AddUserMessage($"Please execute the following step of our plan: {plan}");
203266

267+
agentCoordinator.AddMessage(AgentRole.Planner, AgentRole.Executor,
268+
"EXECUTION_REQUEST", plan);
269+
204270
PluginLogger.StopLoadingIndicator();
205271
PluginLogger.LogPluginUsage("🔧 Executing step...");
206272
PluginLogger.StartLoadingIndicator("executing");
207273

208274
// Get executor response with tools
209275
string executionResult = await GetAgentResponseAsync(executorChat, executorHistory, executorSettings, executorKernel);
210276

277+
// Store the execution result for the final response
278+
executionResults.Add(executionResult);
279+
211280
PluginLogger.LogPluginUsage("📊 Execution result:\n" + executionResult);
212281

282+
agentCoordinator.AddMessage(AgentRole.Executor, AgentRole.Planner,
283+
"EXECUTION_RESPONSE", executionResult);
284+
213285
// Add the execution result to the planner's history
214286
plannerHistory.AddUserMessage($"The executor agent performed the requested step. Here is the result:\n\n{executionResult}\n\nIs the task fully completed, or do we need additional steps? If additional steps are needed, provide just the next step to execute. If the task is complete, respond with 'TASK COMPLETED' followed by a summary of what was accomplished.");
215287

@@ -218,16 +290,39 @@ public async Task<string> ExecuteAction(string actionPrompt)
218290
PluginLogger.StartLoadingIndicator("planning");
219291

220292
// Get planner's evaluation of the result
221-
plan = await GetAgentResponseAsync(plannerChat, plannerHistory, planSettings, plannerKernel);
293+
plan = await GetAgentResponseAsync(plannerChat, plannerHistory, plannerSettings, plannerKernel);
294+
295+
agentCoordinator.AddMessage(AgentRole.Planner, AgentRole.Coordinator,
296+
"STATUS_UPDATE", plan);
222297

223298
// Check if the task is complete
224299
if (plan.Contains("TASK COMPLETED"))
225300
{
226301
isComplete = true;
227-
finalResult = plan;
302+
303+
// Extract the summary from the "TASK COMPLETED" message
304+
string taskSummary = plan.Replace("TASK COMPLETED", "").Trim();
305+
306+
// Send all execution results to the coordinator for final formatting
307+
string executionSummary = string.Join("\n\n", executionResults);
308+
309+
coordinatorHistory.AddUserMessage($"The task has been completed. Here are the detailed results from execution:\n\n{executionSummary}\n\nPlease provide a comprehensive response for the user that includes the actual results and information obtained during execution. Do not include phrases like 'TASK_COMPLETE' or similar tags.");
310+
311+
PluginLogger.StopLoadingIndicator();
312+
PluginLogger.LogPluginUsage("✅ Task completed, generating detailed response...");
313+
PluginLogger.StartLoadingIndicator("coordination");
314+
315+
// Get coordinator's final response with detailed results
316+
finalResult = await GetAgentResponseAsync(coordinatorChat, coordinatorHistory, coordinatorSettings, coordinatorKernel);
317+
318+
// Store this as a completed response but without the TASK_COMPLETE tag
319+
agentCoordinator.AddMessage(AgentRole.Coordinator, AgentRole.User,
320+
"USER_RESPONSE", finalResult);
321+
}
322+
else
323+
{
324+
PluginLogger.LogPluginUsage("🔍 Progress evaluation:\n" + plan);
228325
}
229-
230-
PluginLogger.LogPluginUsage("🔍 Progress evaluation:\n" + plan);
231326
}
232327

233328
PluginLogger.StopLoadingIndicator();
@@ -239,8 +334,24 @@ public async Task<string> ExecuteAction(string actionPrompt)
239334
}
240335
else
241336
{
337+
// Compile all execution results into a comprehensive response
338+
string allResults = string.Join("\n\n", executionResults);
339+
340+
// Get coordinator to explain the incomplete task status with the results
341+
coordinatorHistory.AddUserMessage($"The task could not be completed within {maxIterations} iterations, but here are the execution results so far:\n\n{allResults}\n\nPlease provide a detailed response for the user that contains all the information gathered, even though the task wasn't fully completed.");
342+
343+
PluginLogger.LogPluginUsage("⚠️ Maximum iterations reached, generating explanation with results...");
344+
PluginLogger.StartLoadingIndicator("coordination");
345+
346+
// Get coordinator's explanation with detailed results
347+
string resultWithExplanation = await GetAgentResponseAsync(coordinatorChat, coordinatorHistory, coordinatorSettings, coordinatorKernel);
348+
349+
agentCoordinator.AddMessage(AgentRole.Coordinator, AgentRole.User,
350+
"STATUS_UPDATE", resultWithExplanation);
351+
352+
PluginLogger.StopLoadingIndicator();
242353
PluginLogger.NotifyTaskComplete("Multi-Agent Action", false);
243-
return $"Task execution reached maximum iterations ({maxIterations}) without completion. Last status: {plan}";
354+
return resultWithExplanation;
244355
}
245356
}
246357
catch (Exception ex)
@@ -283,18 +394,23 @@ private async Task<string> GetAgentResponseAsync(
283394

284395
internal void SetChatHistory(List<LocalChatMessage> chatHistory)
285396
{
397+
// Set up coordinator history with system prompt
398+
coordinatorHistory.Clear();
399+
coordinatorHistory.AddSystemMessage(toolConfig.CoordinatorSystemPrompt);
400+
401+
// Set up planner history with system prompt
286402
plannerHistory.Clear();
287403
plannerHistory.AddSystemMessage(toolConfig.PlannerSystemPrompt);
288404

289405
foreach (var message in chatHistory)
290406
{
291407
if (message.Author == "You")
292408
{
293-
plannerHistory.AddUserMessage(message.Content);
409+
coordinatorHistory.AddUserMessage(message.Content);
294410
}
295411
else if (message.Author == "AI")
296412
{
297-
plannerHistory.AddAssistantMessage(message.Content);
413+
coordinatorHistory.AddAssistantMessage(message.Content);
298414
}
299415
}
300416
}

0 commit comments

Comments
 (0)