Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion dotnet/agent-framework-dotnet.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,34 @@
<Project Path="samples/02-agents/AGUI/Step05_StateManagement/Client/Client.csproj" />
<Project Path="samples/02-agents/AGUI/Step05_StateManagement/Server/Server.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/AGUI/Step06_WorkflowSequential/">
<Project Path="samples/02-agents/AGUI/Step06_WorkflowSequential/Client/Client.csproj" />
<Project Path="samples/02-agents/AGUI/Step06_WorkflowSequential/Server/Server.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/AGUI/Step07_WorkflowConcurrent/">
<Project Path="samples/02-agents/AGUI/Step07_WorkflowConcurrent/Client/Client.csproj" />
<Project Path="samples/02-agents/AGUI/Step07_WorkflowConcurrent/Server/Server.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/AGUI/Step08_WorkflowFailure/">
<Project Path="samples/02-agents/AGUI/Step08_WorkflowFailure/Client/Client.csproj" />
<Project Path="samples/02-agents/AGUI/Step08_WorkflowFailure/Server/Server.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/AGUI/Step09_WorkflowTools/">
<Project Path="samples/02-agents/AGUI/Step09_WorkflowTools/Client/Client.csproj" />
<Project Path="samples/02-agents/AGUI/Step09_WorkflowTools/Server/Server.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/AGUI/Step10_WorkflowNested/">
<Project Path="samples/02-agents/AGUI/Step10_WorkflowNested/Client/Client.csproj" />
<Project Path="samples/02-agents/AGUI/Step10_WorkflowNested/Server/Server.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/AGUI/Step11_WorkflowApproval/">
<Project Path="samples/02-agents/AGUI/Step11_WorkflowApproval/Client/Client.csproj" />
<Project Path="samples/02-agents/AGUI/Step11_WorkflowApproval/Server/Server.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/AGUI/Step12_WorkflowMultipleInputs/">
<Project Path="samples/02-agents/AGUI/Step12_WorkflowMultipleInputs/Client/Client.csproj" />
<Project Path="samples/02-agents/AGUI/Step12_WorkflowMultipleInputs/Server/Server.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/DevUI/">
<File Path="samples/02-agents/DevUI/README.md" />
<Project Path="samples/02-agents/DevUI/DevUI_Step01_BasicUsage/DevUI_Step01_BasicUsage.csproj" />
Expand Down Expand Up @@ -670,4 +698,3 @@
<Project Path="tests/Microsoft.Agents.AI.Workflows.UnitTests/Microsoft.Agents.AI.Workflows.UnitTests.csproj" />
</Folder>
</Solution>

76 changes: 76 additions & 0 deletions dotnet/samples/02-agents/AGUI/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,82 @@ cd Step05_StateManagement/Server
dotnet run
```

### Step06_WorkflowSequential

A two-agent sequential workflow hosted over AG-UI. The client displays executor `STEP_STARTED` and
`STEP_FINISHED` events alongside the writer and reviewer text.

```bash
cd Step06_WorkflowSequential
dotnet run --project Server --urls http://localhost:8888
dotnet run --project Client
```

### Step07_WorkflowConcurrent

A concurrent workflow that runs a researcher and critic together. The client displays each executor's steps
and both streamed responses.

```bash
cd Step07_WorkflowConcurrent
dotnet run --project Server --urls http://localhost:8888
dotnet run --project Client
```

### Step08_WorkflowFailure

A deterministic failing workflow. The client shows the failed executor step closing before terminal
`RUN_ERROR`.

```bash
cd Step08_WorkflowFailure
dotnet run --project Server --urls http://localhost:8888
dotnet run --project Client
```

### Step09_WorkflowTools

A workflow containing a backend-tool-enabled agent. The client displays executor steps, tool calls, tool
results, and text without duplication.

```bash
cd Step09_WorkflowTools
dotnet run --project Server --urls http://localhost:8888
dotnet run --project Client
```

### Step10_WorkflowNested

Two parallel subworkflows whose local executor IDs are both `Analyze`. The sample characterizes the
currently ambiguous AG-UI step names tracked by issue #7763.

```bash
cd Step10_WorkflowNested
dotnet run --project Server --urls http://localhost:8888
dotnet run --project Client
```

### Step11_WorkflowApproval

An expense workflow that pauses with an AG-UI approval interruption and resumes on the same persisted thread.

```bash
cd Step11_WorkflowApproval
dotnet run --project Server --urls http://localhost:8888
dotnet run --project Client
```

### Step12_WorkflowMultipleInputs

A travel workflow that emits three input interruptions in one turn, accepts partial and out-of-order
responses, and completes after the remaining input arrives.

```bash
cd Step12_WorkflowMultipleInputs
dotnet run --project Server --urls http://localhost:8888
dotnet run --project Client
```

The server runs on port 8888 by default.

#### Client (`Step05_StateManagement/Client`)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AGUI.Client" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.

using AGUI.Abstractions;
using AGUI.Client;
using Microsoft.Extensions.AI;

string serverUrl = Environment.GetEnvironmentVariable("AGUI_SERVER_URL") ?? "http://localhost:8888";
using HttpClient httpClient = new() { Timeout = TimeSpan.FromSeconds(60) };
using IChatClient chatClient = CreateChatClient(httpClient, serverUrl);

Console.Write("Request: ");
string request = Console.ReadLine() ?? "Write a short welcome message for a developer conference.";

await foreach (ChatResponseUpdate update in chatClient.GetStreamingResponseAsync(
[new ChatMessage(ChatRole.User, request)]))
{
switch (update.RawRepresentation)
{
case StepStartedEvent started:
Console.WriteLine($"\n[Step started: {started.StepName}]");
break;
case StepFinishedEvent finished:
Console.WriteLine($"\n[Step finished: {finished.StepName}]");
break;
}

foreach (TextContent text in update.Contents.OfType<TextContent>())
{
Console.Write(text.Text);
}
}

Console.WriteLine();

static IChatClient CreateChatClient(HttpClient httpClient, string serverUrl)
=> new AGUIChatClient(new(httpClient, serverUrl));
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Sequential Workflow over AG-UI

This sample hosts a two-agent sequential workflow over AG-UI. The `Writer` drafts a response and the
`Reviewer` produces the final answer. The client prints AG-UI step lifecycle events alongside streamed text.

## Run

Set `AZURE_OPENAI_ENDPOINT` and `AZURE_OPENAI_DEPLOYMENT_NAME`, then:

```powershell
dotnet run --project Server --urls http://localhost:8888
dotnet run --project Client
```

Expected step events include `STEP_STARTED` and `STEP_FINISHED` for `Writer` followed by `Reviewer`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.

using AGUI.WorkflowSequential;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore;
using Microsoft.Agents.AI.Workflows;
using OpenAI.Chat;

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient().AddLogging();
builder.Services.AddAGUIServer();

string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"]
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
string deploymentName = builder.Configuration["AZURE_OPENAI_DEPLOYMENT_NAME"]
?? throw new InvalidOperationException("AZURE_OPENAI_DEPLOYMENT_NAME is not set.");

ChatClient chatClient = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetChatClient(deploymentName);

AIAgent writer = chatClient.AsAIAgent(
name: "Writer",
instructions: "Draft a concise answer to the user's request.");
AIAgent reviewer = chatClient.AsAIAgent(
name: "Reviewer",
instructions: "Review the draft and return an improved final answer.");

AIAgent workflowAgent = SequentialWorkflow.Create(writer, reviewer).AsAIAgent(name: "SequentialWorkflow");

WebApplication app = builder.Build();
app.MapAGUIServer("/", workflowAgent);
await app.RunAsync();
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Microsoft. All rights reserved.

using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;

namespace AGUI.WorkflowSequential;

/// <summary>
/// Creates the sequential workflow used by the sample and its integration test.
/// </summary>
public static class SequentialWorkflow
{
/// <summary>
/// Creates a workflow that asks one agent to draft content and another to review it.
/// </summary>
/// <param name="writer">The writer agent.</param>
/// <param name="reviewer">The reviewer agent.</param>
/// <returns>The sequential workflow.</returns>
public static Workflow Create(AIAgent writer, AIAgent reviewer)
=> new SequentialWorkflowBuilder(writer, reviewer).Build();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" />
<PackageReference Include="Azure.Identity" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Hosting.AGUI.AspNetCore\Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.csproj" />
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.OpenAI\Microsoft.Agents.AI.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.Workflows\Microsoft.Agents.AI.Workflows.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AGUI.Client" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.

using AGUI.Abstractions;
using AGUI.Client;
using Microsoft.Extensions.AI;

string serverUrl = Environment.GetEnvironmentVariable("AGUI_SERVER_URL") ?? "http://localhost:8888";
using HttpClient httpClient = new() { Timeout = TimeSpan.FromSeconds(60) };
using IChatClient chatClient = CreateChatClient(httpClient, serverUrl);

Console.Write("Request: ");
string request = Console.ReadLine() ?? "Assess the tradeoffs of adopting a new framework.";

await foreach (ChatResponseUpdate update in chatClient.GetStreamingResponseAsync(
[new ChatMessage(ChatRole.User, request)]))
{
switch (update.RawRepresentation)
{
case StepStartedEvent started:
Console.WriteLine($"\n[Step started: {started.StepName}]");
break;
case StepFinishedEvent finished:
Console.WriteLine($"\n[Step finished: {finished.StepName}]");
break;
}

foreach (TextContent text in update.Contents.OfType<TextContent>())
{
Console.Write(text.Text);
}
}

Console.WriteLine();

static IChatClient CreateChatClient(HttpClient httpClient, string serverUrl)
=> new AGUIChatClient(new(httpClient, serverUrl));
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Concurrent Workflow over AG-UI

This sample runs a `Researcher` and `Critic` concurrently. The AG-UI client displays each executor's
step lifecycle and the output from both agents.

## Run

Set `AZURE_OPENAI_ENDPOINT` and `AZURE_OPENAI_DEPLOYMENT_NAME`, then:

```powershell
dotnet run --project Server --urls http://localhost:8888
dotnet run --project Client
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) Microsoft. All rights reserved.

using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;

namespace AGUI.WorkflowConcurrent;

/// <summary>
/// Creates the concurrent workflow used by the sample and its integration test.
/// </summary>
public static class ConcurrentWorkflow
{
/// <summary>
/// Creates a workflow that runs all supplied agents concurrently.
/// </summary>
/// <param name="agents">The agents to run concurrently.</param>
/// <returns>The concurrent workflow.</returns>
public static Workflow Create(params AIAgent[] agents)
=> new ConcurrentWorkflowBuilder(agents).Build();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.

using AGUI.WorkflowConcurrent;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore;
using Microsoft.Agents.AI.Workflows;
using OpenAI.Chat;

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient().AddLogging();
builder.Services.AddAGUIServer();

string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"]
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
string deploymentName = builder.Configuration["AZURE_OPENAI_DEPLOYMENT_NAME"]
?? throw new InvalidOperationException("AZURE_OPENAI_DEPLOYMENT_NAME is not set.");

ChatClient chatClient = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetChatClient(deploymentName);

AIAgent researcher = chatClient.AsAIAgent(
name: "Researcher",
instructions: "Identify the important facts in the user's request.");
AIAgent critic = chatClient.AsAIAgent(
name: "Critic",
instructions: "Identify risks and missing considerations in the user's request.");

AIAgent workflowAgent = ConcurrentWorkflow.Create(researcher, critic).AsAIAgent(name: "ConcurrentWorkflow");

WebApplication app = builder.Build();
app.MapAGUIServer("/", workflowAgent);
await app.RunAsync();
Loading
Loading