mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Round 2 of cleanup for agent runtime and orchestrations (#164)
- Moved InProcessRuntime type into abstractions package and deleted InProcess package. - Moved several members of IAgentRuntime to be extension methods instead, e.g. multiple GetActorAsync overloads. - Added synchronous RegisterMessageHandler overloads and used them to avoid unnecessary async usage at call sites. - Removed unnecessary surface area from InProcessRuntime, e.g. StopAsync, RunUntilIdleAsync, etc. - Fixed spin loop in InProcessRuntime that would consume an entire core for the duration of the orchestration's operation. - Removed a bunch of allocation from InProcessRuntime. - Made a runtime optional for orchestrations, defaulting to using a temporary InProcessRuntime if none is provided. - Removed custom delegate types from orchestrations. - Consolidated namespaces. - Used records to simplify message classes. - Tweaked naming on AgentActor to make purpose of protected methods more clear. - Removed invocation in AgentActor.InvokeAsync of empty update / isFinal parameter. - Changed OrchestrationHandoffs to avoid needing to pass in agents duplicatively. - Made various extension methods, such as those on OrchestrationHandoffsExtensions, into instance methods.
This commit is contained in:
@@ -159,11 +159,8 @@ public class AgentSample(ITestOutputHelper output) : BaseSample(output)
|
||||
|
||||
private async Task AzureAIAgentsPersistentAgentCleanUpAsync(ChatClientAgent agent, AgentThread? thread, CancellationToken cancellationToken)
|
||||
{
|
||||
var persistentAgentsClient = agent.ChatClient.GetService<PersistentAgentsClient>();
|
||||
if (persistentAgentsClient is null)
|
||||
{
|
||||
var persistentAgentsClient = agent.ChatClient.GetService<PersistentAgentsClient>() ??
|
||||
throw new InvalidOperationException("The provided chat client is not a Persistent Agents Chat Client");
|
||||
}
|
||||
|
||||
await persistentAgentsClient.Administration.DeleteAgentAsync(agent.Id, cancellationToken);
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.Orchestration;
|
||||
using Microsoft.Agents.Orchestration.Concurrent;
|
||||
using Microsoft.Extensions.AI.Agents;
|
||||
using Microsoft.Extensions.AI.Agents.Runtime.InProcess;
|
||||
|
||||
namespace Orchestration;
|
||||
|
||||
@@ -42,20 +40,14 @@ public class ConcurrentOrchestration_Intro(ITestOutputHelper output) : Orchestra
|
||||
StreamingResponseCallback = streamedResponse ? monitor.StreamingResultCallback : null,
|
||||
};
|
||||
|
||||
// Start the runtime
|
||||
await using InProcessRuntime runtime = new();
|
||||
await runtime.StartAsync();
|
||||
|
||||
// Run the orchestration
|
||||
string input = "What is temperature?";
|
||||
Console.WriteLine($"\n# INPUT: {input}\n");
|
||||
OrchestrationResult<string[]> result = await orchestration.InvokeAsync(input, runtime);
|
||||
OrchestrationResult<string[]> result = await orchestration.InvokeAsync(input);
|
||||
|
||||
string[] output = await result.GetValueAsync(TimeSpan.FromSeconds(ResultTimeoutInSeconds));
|
||||
string[] output = await result;
|
||||
Console.WriteLine($"\n# RESULT:\n{string.Join("\n\n", output.Select(text => $"{text}"))}");
|
||||
|
||||
await runtime.RunUntilIdleAsync();
|
||||
|
||||
this.DisplayHistory(monitor.History);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-11
@@ -2,10 +2,7 @@
|
||||
|
||||
using System.Text.Json;
|
||||
using Microsoft.Agents.Orchestration;
|
||||
using Microsoft.Agents.Orchestration.Concurrent;
|
||||
using Microsoft.Agents.Orchestration.Transforms;
|
||||
using Microsoft.Extensions.AI.Agents;
|
||||
using Microsoft.Extensions.AI.Agents.Runtime.InProcess;
|
||||
using Microsoft.Shared.Samples;
|
||||
|
||||
namespace Orchestration;
|
||||
@@ -43,20 +40,14 @@ public class ConcurrentOrchestration_With_StructuredOutput(ITestOutputHelper out
|
||||
ResultTransform = outputTransform.TransformAsync,
|
||||
};
|
||||
|
||||
// Start the runtime
|
||||
await using InProcessRuntime runtime = new();
|
||||
await runtime.StartAsync();
|
||||
|
||||
// Run the orchestration
|
||||
const string resourceId = "Hamlet_full_play_summary.txt";
|
||||
string input = Resources.Read(resourceId);
|
||||
Console.WriteLine($"\n# INPUT: @{resourceId}\n");
|
||||
OrchestrationResult<Analysis> result = await orchestration.InvokeAsync(input, runtime);
|
||||
OrchestrationResult<Analysis> result = await orchestration.InvokeAsync(input);
|
||||
|
||||
Analysis output = await result.GetValueAsync(TimeSpan.FromSeconds(ResultTimeoutInSeconds * 2));
|
||||
Analysis output = await result;
|
||||
Console.WriteLine($"\n# RESULT:\n{JsonSerializer.Serialize(output, s_options)}");
|
||||
|
||||
await runtime.RunUntilIdleAsync();
|
||||
}
|
||||
|
||||
#pragma warning disable CA1812 // Avoid uninstantiated internal classes
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.Orchestration;
|
||||
using Microsoft.Agents.Orchestration.GroupChat;
|
||||
using Microsoft.Extensions.AI.Agents;
|
||||
using Microsoft.Extensions.AI.Agents.Runtime.InProcess;
|
||||
|
||||
namespace Orchestration;
|
||||
|
||||
@@ -68,17 +66,10 @@ public class GroupChatOrchestration_Intro(ITestOutputHelper output) : Orchestrat
|
||||
StreamingResponseCallback = streamedResponse ? monitor.StreamingResultCallback : null,
|
||||
};
|
||||
|
||||
// Start the runtime
|
||||
await using InProcessRuntime runtime = new();
|
||||
await runtime.StartAsync();
|
||||
|
||||
string input = "Create a slogon for a new eletric SUV that is affordable and fun to drive.";
|
||||
Console.WriteLine($"\n# INPUT: {input}\n");
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(input, runtime);
|
||||
string text = await result.GetValueAsync(TimeSpan.FromSeconds(ResultTimeoutInSeconds * 3));
|
||||
Console.WriteLine($"\n# RESULT: {text}");
|
||||
|
||||
await runtime.RunUntilIdleAsync();
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(input);
|
||||
Console.WriteLine($"\n# RESULT: {await result}");
|
||||
|
||||
this.DisplayHistory(monitor.History);
|
||||
}
|
||||
|
||||
+2
-11
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.Orchestration;
|
||||
using Microsoft.Agents.Orchestration.GroupChat;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.AI.Agents;
|
||||
using Microsoft.Extensions.AI.Agents.Runtime.InProcess;
|
||||
|
||||
namespace Orchestration;
|
||||
|
||||
@@ -132,17 +130,10 @@ public class GroupChatOrchestration_With_AIManager(ITestOutputHelper output) : O
|
||||
ResponseCallback = monitor.ResponseCallback,
|
||||
};
|
||||
|
||||
// Start the runtime
|
||||
await using InProcessRuntime runtime = new();
|
||||
await runtime.StartAsync();
|
||||
|
||||
// Run the orchestration
|
||||
Console.WriteLine($"\n# INPUT: {topic}\n");
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(topic, runtime);
|
||||
string text = await result.GetValueAsync(TimeSpan.FromSeconds(ResultTimeoutInSeconds * 3));
|
||||
Console.WriteLine($"\n# RESULT: {text}");
|
||||
|
||||
await runtime.RunUntilIdleAsync();
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(topic);
|
||||
Console.WriteLine($"\n# RESULT: {await result}");
|
||||
|
||||
this.DisplayHistory(monitor.History);
|
||||
}
|
||||
|
||||
+7
-27
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.Orchestration;
|
||||
using Microsoft.Agents.Orchestration.GroupChat;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.AI.Agents;
|
||||
using Microsoft.Extensions.AI.Agents.Runtime.InProcess;
|
||||
|
||||
namespace Orchestration;
|
||||
|
||||
@@ -68,18 +66,11 @@ public class GroupChatOrchestration_With_HumanInTheLoop(ITestOutputHelper output
|
||||
ResponseCallback = monitor.ResponseCallback,
|
||||
};
|
||||
|
||||
// Start the runtime
|
||||
await using InProcessRuntime runtime = new();
|
||||
await runtime.StartAsync();
|
||||
|
||||
// Run the orchestration
|
||||
string input = "Create a slogon for a new eletric SUV that is affordable and fun to drive.";
|
||||
Console.WriteLine($"\n# INPUT: {input}\n");
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(input, runtime);
|
||||
string text = await result.GetValueAsync(TimeSpan.FromSeconds(ResultTimeoutInSeconds * 3));
|
||||
Console.WriteLine($"\n# RESULT: {text}");
|
||||
|
||||
await runtime.RunUntilIdleAsync();
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(input);
|
||||
Console.WriteLine($"\n# RESULT: {await result}");
|
||||
|
||||
this.DisplayHistory(monitor.History);
|
||||
}
|
||||
@@ -97,23 +88,12 @@ public class GroupChatOrchestration_With_HumanInTheLoop(ITestOutputHelper output
|
||||
{
|
||||
string? lastAgent = history.LastOrDefault()?.AuthorName;
|
||||
|
||||
GroupChatManagerResult<bool> result;
|
||||
GroupChatManagerResult<bool> result =
|
||||
lastAgent is null ? new(false) { Reason = "No agents have spoken yet." } :
|
||||
lastAgent is "Reviewer" ? new(true) { Reason = "User input is needed after the reviewer's message." } :
|
||||
new(false) { Reason = "User input is not needed until the reviewer's message." };
|
||||
|
||||
if (lastAgent is null)
|
||||
{
|
||||
result = new GroupChatManagerResult<bool>(false) { Reason = "No agents have spoken yet." };
|
||||
}
|
||||
|
||||
if (lastAgent == "Reviewer")
|
||||
{
|
||||
result = new GroupChatManagerResult<bool>(true) { Reason = "User input is needed after the reviewer's message." };
|
||||
}
|
||||
else
|
||||
{
|
||||
result = new GroupChatManagerResult<bool>(false) { Reason = "User input is not needed until the reviewer's message." };
|
||||
}
|
||||
|
||||
return new ValueTask<GroupChatManagerResult<bool>>(result);
|
||||
return new(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.Orchestration;
|
||||
using Microsoft.Agents.Orchestration.Handoff;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.AI.Agents;
|
||||
using Microsoft.Extensions.AI.Agents.Runtime.InProcess;
|
||||
|
||||
namespace Orchestration;
|
||||
|
||||
@@ -65,11 +63,7 @@ public class HandoffOrchestration_Intro(ITestOutputHelper output) : Orchestratio
|
||||
.Add(triageAgent, statusAgent, returnAgent, refundAgent)
|
||||
.Add(statusAgent, triageAgent, "Transfer to this agent if the issue is not status related")
|
||||
.Add(returnAgent, triageAgent, "Transfer to this agent if the issue is not return related")
|
||||
.Add(refundAgent, triageAgent, "Transfer to this agent if the issue is not refund related"),
|
||||
triageAgent,
|
||||
statusAgent,
|
||||
returnAgent,
|
||||
refundAgent)
|
||||
.Add(refundAgent, triageAgent, "Transfer to this agent if the issue is not refund related"))
|
||||
{
|
||||
InteractiveCallback = () =>
|
||||
{
|
||||
@@ -84,18 +78,11 @@ public class HandoffOrchestration_Intro(ITestOutputHelper output) : Orchestratio
|
||||
StreamingResponseCallback = streamedResponse ? monitor.StreamingResultCallback : null,
|
||||
};
|
||||
|
||||
// Start the runtime
|
||||
await using InProcessRuntime runtime = new();
|
||||
await runtime.StartAsync();
|
||||
|
||||
// Run the orchestration
|
||||
Console.WriteLine($"\n# INPUT:\n{task}\n");
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(task, runtime);
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(task);
|
||||
|
||||
string text = await result.GetValueAsync(TimeSpan.FromSeconds(300));
|
||||
Console.WriteLine($"\n# RESULT: {text}");
|
||||
|
||||
await runtime.RunUntilIdleAsync();
|
||||
Console.WriteLine($"\n# RESULT: {await result}");
|
||||
|
||||
this.DisplayHistory(monitor.History);
|
||||
}
|
||||
|
||||
+3
-15
@@ -2,10 +2,8 @@
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Agents.Orchestration;
|
||||
using Microsoft.Agents.Orchestration.Handoff;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.AI.Agents;
|
||||
using Microsoft.Extensions.AI.Agents.Runtime.InProcess;
|
||||
|
||||
namespace Orchestration;
|
||||
|
||||
@@ -49,10 +47,7 @@ public class HandoffOrchestration_With_StructuredInput(ITestOutputHelper output)
|
||||
HandoffOrchestration<GithubIssue, string> orchestration =
|
||||
new(OrchestrationHandoffs
|
||||
.StartWith(triageAgent)
|
||||
.Add(triageAgent, dotnetAgent, pythonAgent),
|
||||
triageAgent,
|
||||
pythonAgent,
|
||||
dotnetAgent)
|
||||
.Add(triageAgent, dotnetAgent, pythonAgent))
|
||||
{
|
||||
LoggerFactory = this.LoggerFactory,
|
||||
ResponseCallback = monitor.ResponseCallback,
|
||||
@@ -83,18 +78,11 @@ public class HandoffOrchestration_With_StructuredInput(ITestOutputHelper output)
|
||||
Labels = []
|
||||
};
|
||||
|
||||
// Start the runtime
|
||||
await using InProcessRuntime runtime = new();
|
||||
await runtime.StartAsync();
|
||||
|
||||
// Run the orchestration
|
||||
Console.WriteLine($"\n# INPUT:\n{input.Id}: {input.Title}\n");
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(input, runtime);
|
||||
string text = await result.GetValueAsync(TimeSpan.FromSeconds(ResultTimeoutInSeconds));
|
||||
Console.WriteLine($"\n# RESULT: {text}");
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(input);
|
||||
Console.WriteLine($"\n# RESULT: {await result}");
|
||||
Console.WriteLine($"\n# LABELS: {string.Join(",", githubPlugin.Labels["12345"])}\n");
|
||||
|
||||
await runtime.RunUntilIdleAsync();
|
||||
}
|
||||
|
||||
private sealed class GithubIssue
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.Orchestration;
|
||||
using Microsoft.Agents.Orchestration.Sequential;
|
||||
using Microsoft.Extensions.AI.Agents;
|
||||
using Microsoft.Extensions.AI.Agents.Runtime.InProcess;
|
||||
|
||||
namespace Orchestration;
|
||||
|
||||
@@ -64,18 +62,11 @@ public class SequentialOrchestration_Intro(ITestOutputHelper output) : Orchestra
|
||||
StreamingResponseCallback = streamedResponse ? monitor.StreamingResultCallback : null,
|
||||
};
|
||||
|
||||
// Start the runtime
|
||||
await using InProcessRuntime runtime = new();
|
||||
await runtime.StartAsync();
|
||||
|
||||
// Run the orchestration
|
||||
string input = "An eco-friendly stainless steel water bottle that keeps drinks cold for 24 hours";
|
||||
Console.WriteLine($"\n# INPUT: {input}\n");
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(input, runtime);
|
||||
string text = await result.GetValueAsync(TimeSpan.FromSeconds(ResultTimeoutInSeconds));
|
||||
Console.WriteLine($"\n# RESULT: {text}");
|
||||
|
||||
await runtime.RunUntilIdleAsync();
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(input);
|
||||
Console.WriteLine($"\n# RESULT: {await result}");
|
||||
|
||||
this.DisplayHistory(monitor.History);
|
||||
}
|
||||
|
||||
+4
-13
@@ -1,9 +1,7 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.Orchestration;
|
||||
using Microsoft.Agents.Orchestration.Sequential;
|
||||
using Microsoft.Extensions.AI.Agents;
|
||||
using Microsoft.Extensions.AI.Agents.Runtime.InProcess;
|
||||
|
||||
namespace Orchestration;
|
||||
|
||||
@@ -26,29 +24,22 @@ public class SequentialOrchestration_With_Cancellation(ITestOutputHelper output)
|
||||
// Define the orchestration
|
||||
SequentialOrchestration orchestration = new(agent) { LoggerFactory = this.LoggerFactory };
|
||||
|
||||
// Start the runtime
|
||||
await using InProcessRuntime runtime = new();
|
||||
await runtime.StartAsync();
|
||||
|
||||
// Run the orchestration
|
||||
string input = "42";
|
||||
Console.WriteLine($"\n# INPUT: {input}\n");
|
||||
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(input, runtime);
|
||||
OrchestrationResult<string> result = await orchestration.InvokeAsync(input);
|
||||
|
||||
result.Cancel();
|
||||
await Task.Delay(TimeSpan.FromSeconds(3));
|
||||
|
||||
try
|
||||
{
|
||||
string text = await result.GetValueAsync(TimeSpan.FromSeconds(ResultTimeoutInSeconds));
|
||||
Console.WriteLine($"\n# RESULT: {text}");
|
||||
Console.WriteLine($"\n# RESULT: {await result}");
|
||||
}
|
||||
catch (AggregateException exception)
|
||||
catch (TimeoutException exception)
|
||||
{
|
||||
Console.WriteLine($"\n# CANCELLED: {exception.InnerException?.Message}");
|
||||
Console.WriteLine($"\n# CANCELED: {exception.Message}");
|
||||
}
|
||||
|
||||
await runtime.RunUntilIdleAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user