diff --git a/docs/FAQS.md b/docs/FAQS.md
index 8363fd40d1..3ecd5514cc 100644
--- a/docs/FAQS.md
+++ b/docs/FAQS.md
@@ -23,23 +23,23 @@ To download nightly builds follow the following steps:
-
+
-
+
-
-
-
-
+
+
+
+
```
diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props
index 7fb6459906..d110ec4426 100644
--- a/dotnet/Directory.Packages.props
+++ b/dotnet/Directory.Packages.props
@@ -15,7 +15,7 @@
-
+
@@ -68,13 +68,15 @@
-
+
-
-
+
+
+
+
@@ -84,7 +86,7 @@
-
+
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 7cbe76b6fc..3e845c75d9 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -47,7 +47,8 @@
-
+
+
@@ -65,6 +66,7 @@
+
@@ -154,8 +156,8 @@
-
+
@@ -309,10 +311,10 @@
-
+
-
+
diff --git a/dotnet/nuget/nuget-package.props b/dotnet/nuget/nuget-package.props
index 69476cc713..0e92f8ef06 100644
--- a/dotnet/nuget/nuget-package.props
+++ b/dotnet/nuget/nuget-package.props
@@ -2,9 +2,9 @@
1.0.0
- $(VersionPrefix)-$(VersionSuffix).251105.1
- $(VersionPrefix)-preview.251105.1
- 1.0.0-preview.251105.1
+ $(VersionPrefix)-$(VersionSuffix).251107.1
+ $(VersionPrefix)-preview.251107.1
+ 1.0.0-preview.251107.1
Debug;Release;Publish
true
diff --git a/dotnet/samples/AGUIClientServer/AGUIClient/AGUIClient.csproj b/dotnet/samples/AGUIClientServer/AGUIClient/AGUIClient.csproj
index db07df5504..01ce32a62a 100644
--- a/dotnet/samples/AGUIClientServer/AGUIClient/AGUIClient.csproj
+++ b/dotnet/samples/AGUIClientServer/AGUIClient/AGUIClient.csproj
@@ -16,6 +16,7 @@
+
diff --git a/dotnet/samples/AGUIClientServer/AGUIClient/AGUIClientSerializerContext.cs b/dotnet/samples/AGUIClientServer/AGUIClient/AGUIClientSerializerContext.cs
new file mode 100644
index 0000000000..1cc4fb8f53
--- /dev/null
+++ b/dotnet/samples/AGUIClientServer/AGUIClient/AGUIClientSerializerContext.cs
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample demonstrates how to use the AG-UI client to connect to a remote AG-UI server
+// and display streaming updates including conversation/response metadata, text content, and errors.
+
+using System.Text.Json.Serialization;
+
+namespace AGUIClient;
+
+[JsonSerializable(typeof(SensorRequest))]
+[JsonSerializable(typeof(SensorResponse))]
+internal sealed partial class AGUIClientSerializerContext : JsonSerializerContext;
diff --git a/dotnet/samples/AGUIClientServer/AGUIClient/Program.cs b/dotnet/samples/AGUIClientServer/AGUIClient/Program.cs
index 0c6a6539a8..0cbf15d6e4 100644
--- a/dotnet/samples/AGUIClientServer/AGUIClient/Program.cs
+++ b/dotnet/samples/AGUIClientServer/AGUIClient/Program.cs
@@ -4,7 +4,9 @@
// and display streaming updates including conversation/response metadata, text content, and errors.
using System.CommandLine;
+using System.ComponentModel;
using System.Reflection;
+using System.Text;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AGUI;
using Microsoft.Extensions.AI;
@@ -51,11 +53,40 @@ public static class Program
Timeout = TimeSpan.FromSeconds(60)
};
- AGUIAgent agent = new(
- id: "agui-client",
+ var changeBackground = AIFunctionFactory.Create(
+ () =>
+ {
+ Console.ForegroundColor = ConsoleColor.DarkBlue;
+ Console.WriteLine("Changing color to blue");
+ },
+ name: "change_background_color",
+ description: "Change the console background color to dark blue."
+ );
+
+ var readClientClimateSensors = AIFunctionFactory.Create(
+ ([Description("The sensors measurements to include in the response")] SensorRequest request) =>
+ {
+ return new SensorResponse()
+ {
+ Temperature = 22.5,
+ Humidity = 45.0,
+ AirQualityIndex = 75
+ };
+ },
+ name: "read_client_climate_sensors",
+ description: "Reads the climate sensor data from the client device.",
+ serializerOptions: AGUIClientSerializerContext.Default.Options
+ );
+
+ var chatClient = new AGUIChatClient(
+ httpClient,
+ serverUrl,
+ jsonSerializerOptions: AGUIClientSerializerContext.Default.Options);
+
+ AIAgent agent = chatClient.CreateAIAgent(
+ name: "agui-client",
description: "AG-UI Client Agent",
- httpClient: httpClient,
- endpoint: serverUrl);
+ tools: [changeBackground, readClientClimateSensors]);
AgentThread thread = agent.GetNewThread();
List messages = [new(ChatRole.System, "You are a helpful assistant.")];
@@ -82,10 +113,12 @@ public static class Program
// Call RunStreamingAsync to get streaming updates
bool isFirstUpdate = true;
string? threadId = null;
+ var updates = new List();
await foreach (AgentRunResponseUpdate update in agent.RunStreamingAsync(messages, thread, cancellationToken: cancellationToken))
{
// Use AsChatResponseUpdate to access ChatResponseUpdate properties
ChatResponseUpdate chatUpdate = update.AsChatResponseUpdate();
+ updates.Add(chatUpdate);
if (chatUpdate.ConversationId != null)
{
threadId = chatUpdate.ConversationId;
@@ -111,6 +144,25 @@ public static class Program
Console.ResetColor();
break;
+ case FunctionCallContent functionCallContent:
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine($"\n[Function Call - Name: {functionCallContent.Name}, Arguments: {PrintArguments(functionCallContent.Arguments)}]");
+ Console.ResetColor();
+ break;
+
+ case FunctionResultContent functionResultContent:
+ Console.ForegroundColor = ConsoleColor.Magenta;
+ if (functionResultContent.Exception != null)
+ {
+ Console.WriteLine($"\n[Function Result - Exception: {functionResultContent.Exception}]");
+ }
+ else
+ {
+ Console.WriteLine($"\n[Function Result - Result: {functionResultContent.Result}]");
+ }
+ Console.ResetColor();
+ break;
+
case ErrorContent errorContent:
Console.ForegroundColor = ConsoleColor.Red;
string code = errorContent.AdditionalProperties?["Code"] as string ?? "Unknown";
@@ -120,6 +172,14 @@ public static class Program
}
}
}
+ if (updates.Count > 0 && !updates[^1].Contents.Any(c => c is TextContent))
+ {
+ var lastUpdate = updates[^1];
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine();
+ Console.WriteLine($"[Run Ended - Thread: {threadId}, Run: {lastUpdate.ResponseId}]");
+ Console.ResetColor();
+ }
messages.Clear();
Console.WriteLine();
}
@@ -134,4 +194,20 @@ public static class Program
return;
}
}
+
+ private static string PrintArguments(IDictionary? arguments)
+ {
+ if (arguments == null)
+ {
+ return "";
+ }
+ var builder = new StringBuilder();
+ builder.AppendLine();
+ foreach (var kvp in arguments)
+ {
+ builder.AppendLine($" Name: {kvp.Key}");
+ builder.AppendLine($" Value: {kvp.Value}");
+ }
+ return builder.ToString();
+ }
}
diff --git a/dotnet/samples/AGUIClientServer/AGUIClient/SensorRequest.cs b/dotnet/samples/AGUIClientServer/AGUIClient/SensorRequest.cs
new file mode 100644
index 0000000000..76e6efa8de
--- /dev/null
+++ b/dotnet/samples/AGUIClientServer/AGUIClient/SensorRequest.cs
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample demonstrates how to use the AG-UI client to connect to a remote AG-UI server
+// and display streaming updates including conversation/response metadata, text content, and errors.
+
+namespace AGUIClient;
+
+internal sealed class SensorRequest
+{
+ public bool IncludeTemperature { get; set; } = true;
+ public bool IncludeHumidity { get; set; } = true;
+ public bool IncludeAirQualityIndex { get; set; } = true;
+}
diff --git a/dotnet/samples/AGUIClientServer/AGUIClient/SensorResponse.cs b/dotnet/samples/AGUIClientServer/AGUIClient/SensorResponse.cs
new file mode 100644
index 0000000000..09ade6a0c7
--- /dev/null
+++ b/dotnet/samples/AGUIClientServer/AGUIClient/SensorResponse.cs
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample demonstrates how to use the AG-UI client to connect to a remote AG-UI server
+// and display streaming updates including conversation/response metadata, text content, and errors.
+
+namespace AGUIClient;
+
+internal sealed class SensorResponse
+{
+ public double Temperature { get; set; }
+ public double Humidity { get; set; }
+ public int AirQualityIndex { get; set; }
+}
diff --git a/dotnet/samples/AGUIClientServer/AGUIServer/AGUIServerSerializerContext.cs b/dotnet/samples/AGUIClientServer/AGUIServer/AGUIServerSerializerContext.cs
new file mode 100644
index 0000000000..1ca6ad7bdc
--- /dev/null
+++ b/dotnet/samples/AGUIClientServer/AGUIServer/AGUIServerSerializerContext.cs
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Text.Json.Serialization;
+
+namespace AGUIServer;
+
+[JsonSerializable(typeof(ServerWeatherForecastRequest))]
+[JsonSerializable(typeof(ServerWeatherForecastResponse))]
+internal sealed partial class AGUIServerSerializerContext : JsonSerializerContext;
diff --git a/dotnet/samples/AGUIClientServer/AGUIServer/Program.cs b/dotnet/samples/AGUIClientServer/AGUIServer/Program.cs
index f26ace30a1..4ecf9a8429 100644
--- a/dotnet/samples/AGUIClientServer/AGUIServer/Program.cs
+++ b/dotnet/samples/AGUIClientServer/AGUIServer/Program.cs
@@ -1,5 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
+using System.ComponentModel;
+using AGUIServer;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore;
@@ -8,17 +10,40 @@ using OpenAI;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient().AddLogging();
+builder.Services.ConfigureHttpJsonOptions(options => options.SerializerOptions.TypeInfoResolverChain.Add(AGUIServerSerializerContext.Default));
+builder.Services.AddAGUI();
+
WebApplication app = builder.Build();
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.");
-// Create the AI agent
+// Create the AI agent with tools
var agent = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetChatClient(deploymentName)
- .CreateAIAgent(name: "AGUIAssistant");
+ .CreateAIAgent(
+ name: "AGUIAssistant",
+ tools: [
+ AIFunctionFactory.Create(
+ () => DateTimeOffset.UtcNow,
+ name: "get_current_time",
+ description: "Get the current UTC time."
+ ),
+ AIFunctionFactory.Create(
+ ([Description("The weather forecast request")]ServerWeatherForecastRequest request) => {
+ return new ServerWeatherForecastResponse()
+ {
+ Summary = "Sunny",
+ TemperatureC = 25,
+ Date = request.Date
+ };
+ },
+ name: "get_server_weather_forecast",
+ description: "Gets the forecast for a specific location and date",
+ AGUIServerSerializerContext.Default.Options)
+ ]);
// Map the AG-UI agent endpoint
app.MapAGUI("/", agent);
diff --git a/dotnet/samples/AGUIClientServer/AGUIServer/ServerWeatherForecastRequest.cs b/dotnet/samples/AGUIClientServer/AGUIServer/ServerWeatherForecastRequest.cs
new file mode 100644
index 0000000000..a4e3d983ca
--- /dev/null
+++ b/dotnet/samples/AGUIClientServer/AGUIServer/ServerWeatherForecastRequest.cs
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+namespace AGUIServer;
+
+internal sealed class ServerWeatherForecastRequest
+{
+ public DateTime Date { get; set; }
+ public string Location { get; set; } = "Seattle";
+}
diff --git a/dotnet/samples/AGUIClientServer/AGUIServer/ServerWeatherForecastResponse.cs b/dotnet/samples/AGUIClientServer/AGUIServer/ServerWeatherForecastResponse.cs
new file mode 100644
index 0000000000..2bc5d8fbb9
--- /dev/null
+++ b/dotnet/samples/AGUIClientServer/AGUIServer/ServerWeatherForecastResponse.cs
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+namespace AGUIServer;
+
+internal sealed class ServerWeatherForecastResponse
+{
+ public string Summary { get; set; } = "";
+
+ public int TemperatureC { get; set; }
+
+ public DateTime Date { get; set; }
+}
diff --git a/dotnet/samples/AGUIClientServer/README.md b/dotnet/samples/AGUIClientServer/README.md
index dabc841542..b0ad2265d0 100644
--- a/dotnet/samples/AGUIClientServer/README.md
+++ b/dotnet/samples/AGUIClientServer/README.md
@@ -134,15 +134,21 @@ This automatically handles:
### Client Side
-The `AGUIClient` uses the `AGUIAgent` class to connect to the remote server:
+The `AGUIClient` uses the `AGUIChatClient` to connect to the remote server:
```csharp
-AGUIAgent agent = new(
- id: "agui-client",
+using HttpClient httpClient = new();
+var chatClient = new AGUIChatClient(
+ httpClient,
+ endpoint: serverUrl,
+ modelId: "agui-client",
+ jsonSerializerOptions: null);
+
+AIAgent agent = chatClient.CreateAIAgent(
+ instructions: null,
+ name: "agui-client",
description: "AG-UI Client Agent",
- messages: [],
- httpClient: httpClient,
- endpoint: serverUrl);
+ tools: []);
bool isFirstUpdate = true;
AgentRunResponseUpdate? currentUpdate = null;
diff --git a/dotnet/samples/AgentWebChat/AgentWebChat.AgentHost/AgentWebChat.AgentHost.csproj b/dotnet/samples/AgentWebChat/AgentWebChat.AgentHost/AgentWebChat.AgentHost.csproj
index 802c864c1f..53fd4757ee 100644
--- a/dotnet/samples/AgentWebChat/AgentWebChat.AgentHost/AgentWebChat.AgentHost.csproj
+++ b/dotnet/samples/AgentWebChat/AgentWebChat.AgentHost/AgentWebChat.AgentHost.csproj
@@ -1,4 +1,4 @@
-
+
net9.0
@@ -13,7 +13,7 @@
-
+
@@ -37,4 +37,4 @@
-
+
\ No newline at end of file
diff --git a/dotnet/samples/AgentWebChat/AgentWebChat.AgentHost/Custom/CustomAITools.cs b/dotnet/samples/AgentWebChat/AgentWebChat.AgentHost/Custom/CustomAITools.cs
new file mode 100644
index 0000000000..d3deb9162c
--- /dev/null
+++ b/dotnet/samples/AgentWebChat/AgentWebChat.AgentHost/Custom/CustomAITools.cs
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Microsoft.Extensions.AI;
+
+namespace AgentWebChat.AgentHost.Custom;
+
+public class CustomAITool : AITool
+{
+}
+
+public class CustomFunctionTool : AIFunction
+{
+ protected override ValueTask