Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
158ea7f
Update AG-UI C# docs for MAF v1.14 package/API changes
danroth27 Jul 23, 2026
44152c3
Fix ASCII architecture diagram alignment after MapAGUIServer rename
danroth27 Jul 23, 2026
6cc3dbb
Fill missing C# AG-UI scenario coverage to match Python docs
danroth27 Jul 23, 2026
efdb056
AG-UI C# docs: verified parity additions and corrections
danroth27 Jul 23, 2026
97e2805
Rewrite HITL C# to the idiomatic, verified pattern
danroth27 Jul 23, 2026
2897adf
HITL: update Overview to the idiomatic native approval flow
danroth27 Jul 23, 2026
4077549
Audit fixes: state-management namespace + backend-tools type ordering
danroth27 Jul 23, 2026
26674e8
frontend-tools: fix AIFunction.Metadata.Name/Description -> AIFunctio…
danroth27 Jul 23, 2026
8db56a5
Merge Javier's idiomatic state docs: declarative AGUIStreamOptions + …
danroth27 Jul 23, 2026
f479683
getting-started: adopt idiomatic AddAIAgent wiring; fix WithInMemoryS…
danroth27 Jul 23, 2026
0fe813a
Simplify AG-UI server snippets to the direct MapAGUIServer overload (…
danroth27 Jul 23, 2026
c0766ab
Standardize AG-UI C# backend on AzureOpenAIClient (parity with Python…
danroth27 Jul 23, 2026
f43bcc6
getting-started: add Persisting Sessions subsection (when to enable a…
danroth27 Jul 23, 2026
455617c
Docs CI: fix xref-not-found (AGUI.Server), pivot-id-unused, code-bloc…
danroth27 Jul 23, 2026
e17645e
Review cleanup: fix errors, cut noise, tighten AG-UI C# docs
danroth27 Jul 23, 2026
d280c50
Simplify AG-UI C# getting-started client to match Python scope
danroth27 Jul 23, 2026
c3b882d
Use single-line if statements in AG-UI getting-started client
danroth27 Jul 23, 2026
435fdd4
Document conditional (argument-based) tool approval in AG-UI HITL
danroth27 Jul 24, 2026
9bebec2
Remove Persisting Sessions section from AG-UI getting-started
danroth27 Jul 25, 2026
79bc8f2
AG-UI HITL: reference generic tool-approval doc instead of duplicatin…
danroth27 Jul 25, 2026
be55375
Restore original AG-UI getting-started client sample and correct expe…
danroth27 Jul 25, 2026
306b587
getting-started: drop the always-null Thread from the client sample o…
danroth27 Jul 25, 2026
90128d4
Fold Predictive State Updates into state-management doc (drop separat…
danroth27 Jul 25, 2026
148bb19
Fold Predictive State Updates content into state-management doc + dro…
danroth27 Jul 25, 2026
e6e346d
Remove C# MCP Apps content from this PR (revert to coming-soon stub)
danroth27 Jul 25, 2026
0f7f3ee
Drop testing-with-dojo.md changes from this PR
danroth27 Jul 25, 2026
f9a98a6
workflows: trim C# zone to an honest, focused section
danroth27 Jul 25, 2026
77d4058
Address PR review comments: trim non-AG-UI content and noise
danroth27 Jul 25, 2026
a4f80de
backend-tool-rendering: remove generic Tool Implementation Best Pract…
danroth27 Jul 25, 2026
87a1912
frontend-tools: remove generic Troubleshooting section (C# zone)
danroth27 Jul 25, 2026
3050cbb
getting-started: remove generic Common Patterns section (C# zone)
danroth27 Jul 25, 2026
1101001
human-in-the-loop: remove the Blazor AI components TIP
danroth27 Jul 25, 2026
03f39fa
human-in-the-loop: simplify the approval resume (drop unnecessary boi…
danroth27 Jul 25, 2026
bfe57b5
Style pass: reduce em dashes and prose semicolons in AG-UI C# docs
danroth27 Jul 25, 2026
6538204
Fix stale illustrative output and mangled tool name in AG-UI C# docs
danroth27 Jul 26, 2026
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
75 changes: 38 additions & 37 deletions agent-framework/integrations/ag-ui/backend-tool-rendering.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,18 @@ Here's a complete server implementation demonstrating how to register tools with

using System.ComponentModel;
using System.Text.Json.Serialization;
using Azure.AI.Projects;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Options;
using OpenAI.Chat;

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient().AddLogging();
builder.Services.ConfigureHttpJsonOptions(options =>
options.SerializerOptions.TypeInfoResolverChain.Add(SampleJsonSerializerContext.Default));
builder.Services.AddAGUI();
builder.Services.AddAGUIServer();

WebApplication app = builder.Build();

Expand All @@ -63,33 +63,6 @@ string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"]
string deploymentName = builder.Configuration["AZURE_OPENAI_DEPLOYMENT_NAME"]
?? throw new InvalidOperationException("AZURE_OPENAI_DEPLOYMENT_NAME is not set.");

// Define request/response types for the tool
internal sealed class RestaurantSearchRequest
{
public string Location { get; set; } = string.Empty;
public string Cuisine { get; set; } = "any";
}

internal sealed class RestaurantSearchResponse
{
public string Location { get; set; } = string.Empty;
public string Cuisine { get; set; } = string.Empty;
public RestaurantInfo[] Results { get; set; } = [];
}

internal sealed class RestaurantInfo
{
public string Name { get; set; } = string.Empty;
public string Cuisine { get; set; } = string.Empty;
public double Rating { get; set; }
public string Address { get; set; } = string.Empty;
}

// JSON serialization context for source generation
[JsonSerializable(typeof(RestaurantSearchRequest))]
[JsonSerializable(typeof(RestaurantSearchResponse))]
internal sealed partial class SampleJsonSerializerContext : JsonSerializerContext;

// Define the function tool
[Description("Search for restaurants in a location.")]
static RestaurantSearchResponse SearchRestaurants(
Expand Down Expand Up @@ -137,23 +110,51 @@ AITool[] tools =
[
AIFunctionFactory.Create(
SearchRestaurants,
name: "search_restaurants",
serializerOptions: jsonOptions.SerializerOptions)
];

// Create the AI agent with tools
AIAgent agent = new AIProjectClient(
AIAgent agent = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetChatClient(deploymentName)
.AsAIAgent(
model: deploymentName,
name: "AGUIAssistant",
instructions: "You are a helpful assistant with access to restaurant information.",
tools: tools);

// Map the AG-UI agent endpoint
app.MapAGUI("/", agent);
app.MapAGUIServer("/", agent);

await app.RunAsync();

// Define request/response types for the tool
internal sealed class RestaurantSearchRequest
{
public string Location { get; set; } = string.Empty;
public string Cuisine { get; set; } = "any";
}

internal sealed class RestaurantSearchResponse
{
public string Location { get; set; } = string.Empty;
public string Cuisine { get; set; } = string.Empty;
public RestaurantInfo[] Results { get; set; } = [];
}

internal sealed class RestaurantInfo
{
public string Name { get; set; } = string.Empty;
public string Cuisine { get; set; } = string.Empty;
public double Rating { get; set; }
public string Address { get; set; } = string.Empty;
}

// JSON serialization context for source generation
[JsonSerializable(typeof(RestaurantSearchRequest))]
[JsonSerializable(typeof(RestaurantSearchResponse))]
internal sealed partial class SampleJsonSerializerContext : JsonSerializerContext;
```

> [!WARNING]
Expand Down Expand Up @@ -251,9 +252,9 @@ When the agent calls backend tools, you'll see:
```
User (:q or quit to exit): What's the weather like in Amsterdam?

[Run Started - Thread: thread_abc123, Run: run_xyz789]
[Run Started - Run: run_xyz789]

[Function Call - Name: SearchRestaurants]
[Function Call - Name: search_restaurants]
Parameter: Location = Amsterdam
Parameter: Cuisine = any

Expand All @@ -262,7 +263,7 @@ User (:q or quit to exit): What's the weather like in Amsterdam?

The weather in Amsterdam is sunny with a temperature of 22°C. Here are some
great restaurants in the area: The Golden Fork (Italian, 4.5 stars)...
[Run Finished - Thread: thread_abc123]
[Run Finished]
```

### Key Concepts
Expand Down Expand Up @@ -739,4 +740,4 @@ a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(m
> [!TIP]
> See the [AG-UI backend tools sample](https://github.com/microsoft/agent-framework-go/blob/main/examples/02-agents/agui/step02_backend_tools/server/main.go) for a complete runnable example.
Comment thread
danroth27 marked this conversation as resolved.

::: zone-end
::: zone-end
51 changes: 3 additions & 48 deletions agent-framework/integrations/ag-ui/frontend-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This tutorial shows you how to add frontend function tools to your AG-UI clients
Before you begin, ensure you have completed the [Getting Started](getting-started.md) tutorial and have:

- .NET 8.0 or later
- `Microsoft.Agents.AI.AGUI` package installed
- `AGUI.Client` package installed (the AG-UI C# SDK client)
- `Microsoft.Agents.AI` package installed
- Basic understanding of AG-UI client setup

Expand Down Expand Up @@ -70,61 +70,16 @@ The rest of your client code remains the same as shown in the Getting Started tu
When you register tools with `AsAIAgent()`, the `AGUIChatClient` automatically:

1. Captures the tool definitions (names, descriptions, parameter schemas)
3. Sends the tools with each request to the server agent which maps them to `ChatAgentRunOptions.ChatOptions.Tools`
2. Sends the tools with each request to the server agent, which maps them to `ChatClientAgentRunOptions.ChatOptions.Tools`

The server receives the client tool declarations and the AI model can decide when to call them.

### Inspecting and Modifying Tools with Middleware

You can use agent middleware to inspect or modify the agent run, including accessing the tools:

```csharp
// Create agent with middleware that inspects tools
AIAgent inspectableAgent = baseAgent
.AsBuilder()
.Use(runFunc: null, runStreamingFunc: InspectToolsMiddleware)
.Build();

static async IAsyncEnumerable<AgentResponseUpdate> InspectToolsMiddleware(
IEnumerable<ChatMessage> messages,
AgentSession? session,
AgentRunOptions? options,
AIAgent innerAgent,
CancellationToken cancellationToken)
{
// Access the tools from ChatClientAgentRunOptions
if (options is ChatClientAgentRunOptions chatOptions)
{
IList<AITool>? tools = chatOptions.ChatOptions?.Tools;
if (tools != null)
{
Console.WriteLine($"Tools available for this run: {tools.Count}");
foreach (AITool tool in tools)
{
if (tool is AIFunction function)
{
Console.WriteLine($" - {function.Metadata.Name}: {function.Metadata.Description}");
}
}
}
}

await foreach (AgentResponseUpdate update in innerAgent.RunStreamingAsync(messages, session, options, cancellationToken))
{
yield return update;
}
}
```

This middleware pattern allows you to:
- Validate tool definitions before execution

### Key Concepts

The following are new concepts for frontend tools:

- **Client-side registration**: Tools are registered on the client using `AIFunctionFactory.Create()` and passed to `AsAIAgent()`
- **Automatic capture**: Tools are automatically captured and sent via `ChatAgentRunOptions.ChatOptions.Tools`
- **Automatic capture**: Tools are automatically captured and sent via `ChatClientAgentRunOptions.ChatOptions.Tools`

## How Frontend Tools Work

Expand Down
Loading