test
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
Python - Merge - Tests / paths-filter (push) Has been cancelled
Python - Merge - Tests / Python Tests - Core (integration, ubuntu-latest, 3.10) (push) Has been cancelled
Python - Merge - Tests / Python Tests - Azure AI (integration, ubuntu-latest, 3.10) (push) Has been cancelled
Python - Merge - Tests / python-integration-tests-check (push) Has been cancelled
Python - Lab Tests / paths-filter (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.10) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.11) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.12) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.13) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.14) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.10) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.11) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.12) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.13) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.14) (push) Has been cancelled
Check .md links / markdown-link-check (push) Has been cancelled
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
Python - Merge - Tests / paths-filter (push) Has been cancelled
Python - Merge - Tests / Python Tests - Core (integration, ubuntu-latest, 3.10) (push) Has been cancelled
Python - Merge - Tests / Python Tests - Azure AI (integration, ubuntu-latest, 3.10) (push) Has been cancelled
Python - Merge - Tests / python-integration-tests-check (push) Has been cancelled
Python - Lab Tests / paths-filter (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.10) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.11) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.12) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.13) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.14) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.10) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.11) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.12) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.13) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.14) (push) Has been cancelled
Check .md links / markdown-link-check (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.Workflows;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
namespace WorkflowAsAnAgentSample;
|
||||
|
||||
/// <summary>
|
||||
/// This sample introduces the concepts workflows as agents, where a workflow can be
|
||||
/// treated as an <see cref="AIAgent"/>. This allows you to interact with a workflow
|
||||
/// as if it were a single agent.
|
||||
///
|
||||
/// In this example, we create a workflow that uses two language agents to process
|
||||
/// input concurrently, one that responds in French and another that responds in English.
|
||||
///
|
||||
/// You will interact with the workflow in an interactive loop, sending messages and receiving
|
||||
/// streaming responses from the workflow as if it were an agent who responds in both languages.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Pre-requisites:
|
||||
/// - Foundational samples should be completed first.
|
||||
/// - This sample uses concurrent processing.
|
||||
/// - An Azure OpenAI endpoint and deployment name.
|
||||
/// </remarks>
|
||||
public static class Program
|
||||
{
|
||||
private static async Task Main()
|
||||
{
|
||||
// Set up the Azure OpenAI client
|
||||
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
|
||||
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||
var chatClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetChatClient(deploymentName).AsIChatClient();
|
||||
|
||||
// Create the workflow and turn it into an agent
|
||||
var workflow = WorkflowFactory.BuildWorkflow(chatClient);
|
||||
var agent = workflow.AsAgent("workflow-agent", "Workflow Agent");
|
||||
var thread = await agent.GetNewThreadAsync();
|
||||
|
||||
// Start an interactive loop to interact with the workflow as if it were an agent
|
||||
while (true)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.Write("User (or 'exit' to quit): ");
|
||||
string? input = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(input) || input.Equals("exit", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
await ProcessInputAsync(agent, thread, input);
|
||||
}
|
||||
|
||||
// Helper method to process user input and display streaming responses. To display
|
||||
// multiple interleaved responses correctly, we buffer updates by message ID and
|
||||
// re-render all messages on each update.
|
||||
static async Task ProcessInputAsync(AIAgent agent, AgentThread thread, string input)
|
||||
{
|
||||
Dictionary<string, List<AgentResponseUpdate>> buffer = [];
|
||||
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(input, thread))
|
||||
{
|
||||
if (update.MessageId is null || string.IsNullOrEmpty(update.Text))
|
||||
{
|
||||
// skip updates that don't have a message ID or text
|
||||
continue;
|
||||
}
|
||||
Console.Clear();
|
||||
|
||||
if (!buffer.TryGetValue(update.MessageId, out List<AgentResponseUpdate>? value))
|
||||
{
|
||||
value = [];
|
||||
buffer[update.MessageId] = value;
|
||||
}
|
||||
value.Add(update);
|
||||
|
||||
foreach (var (messageId, segments) in buffer)
|
||||
{
|
||||
string combinedText = string.Concat(segments);
|
||||
Console.WriteLine($"{segments[0].AuthorName}: {combinedText}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net10.0</TargetFrameworks>
|
||||
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.AI.OpenAI" />
|
||||
<PackageReference Include="Azure.Identity" />
|
||||
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Workflows\Microsoft.Agents.AI.Workflows.csproj" />
|
||||
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.Workflows;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
namespace WorkflowAsAnAgentSample;
|
||||
|
||||
internal static class WorkflowFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a workflow that uses two language agents to process input concurrently.
|
||||
/// </summary>
|
||||
/// <param name="chatClient">The chat client to use for the agents</param>
|
||||
/// <returns>A workflow that processes input using two language agents</returns>
|
||||
internal static Workflow BuildWorkflow(IChatClient chatClient)
|
||||
{
|
||||
// Create executors
|
||||
var startExecutor = new ChatForwardingExecutor("Start");
|
||||
var aggregationExecutor = new ConcurrentAggregationExecutor();
|
||||
AIAgent frenchAgent = GetLanguageAgent("French", chatClient);
|
||||
AIAgent englishAgent = GetLanguageAgent("English", chatClient);
|
||||
|
||||
// Build the workflow by adding executors and connecting them
|
||||
return new WorkflowBuilder(startExecutor)
|
||||
.AddFanOutEdge(startExecutor, [frenchAgent, englishAgent])
|
||||
.AddFanInEdge([frenchAgent, englishAgent], aggregationExecutor)
|
||||
.WithOutputFrom(aggregationExecutor)
|
||||
.Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a language agent for the specified target language.
|
||||
/// </summary>
|
||||
/// <param name="targetLanguage">The target language for translation</param>
|
||||
/// <param name="chatClient">The chat client to use for the agent</param>
|
||||
/// <returns>A ChatClientAgent configured for the specified language</returns>
|
||||
private static ChatClientAgent GetLanguageAgent(string targetLanguage, IChatClient chatClient) =>
|
||||
new(chatClient, instructions: $"You're a helpful assistant who always responds in {targetLanguage}.", name: $"{targetLanguage}Agent");
|
||||
|
||||
/// <summary>
|
||||
/// Executor that aggregates the results from the concurrent agents.
|
||||
/// </summary>
|
||||
private sealed class ConcurrentAggregationExecutor() :
|
||||
Executor<List<ChatMessage>>("ConcurrentAggregationExecutor"), IResettableExecutor
|
||||
{
|
||||
private readonly List<ChatMessage> _messages = [];
|
||||
|
||||
/// <summary>
|
||||
/// Handles incoming messages from the agents and aggregates their responses.
|
||||
/// </summary>
|
||||
/// <param name="message">The messages from the agent</param>
|
||||
/// <param name="context">Workflow context for accessing workflow services and adding events</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests.
|
||||
/// The default is <see cref="CancellationToken.None"/>.</param>
|
||||
public override async ValueTask HandleAsync(List<ChatMessage> message, IWorkflowContext context, CancellationToken cancellationToken = default)
|
||||
{
|
||||
this._messages.AddRange(message);
|
||||
|
||||
if (this._messages.Count == 2)
|
||||
{
|
||||
var formattedMessages = string.Join(Environment.NewLine, this._messages.Select(m => $"{m.Text}"));
|
||||
await context.YieldOutputAsync(formattedMessages, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask ResetAsync()
|
||||
{
|
||||
this._messages.Clear();
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user