Overhaul orchestration library with new approach (#199)

This commit is contained in:
Stephen Toub
2025-07-23 12:29:37 -04:00
committed by GitHub
Unverified
parent 27f7af2160
commit 5472d6e996
104 changed files with 1212 additions and 5084 deletions
@@ -2,7 +2,6 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
@@ -10,11 +9,6 @@ namespace HelloHttpApi.Web;
public class AgentClient(HttpClient httpClient, ILogger<AgentClient> logger)
{
private static readonly JsonSerializerOptions s_jsonOptions = new(JsonSerializerDefaults.Web)
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
public async IAsyncEnumerable<AgentRunResponseUpdate> SendMessageStreamAsync(
string agentName,
string message,
@@ -27,7 +21,7 @@ public class AgentClient(HttpClient httpClient, ILogger<AgentClient> logger)
Messages = [new ChatMessage(ChatRole.User, message)]
};
var content = JsonContent.Create(request, s_jsonOptions.GetTypeInfo<ChatClientAgentRunRequest>(AgentClientJsonContext.Default));
var content = JsonContent.Create(request, AgentClientJsonContext.Default.ChatClientAgentRunRequest);
var requestUri = new Uri($"/invocations/actor/{agentName}/{sessionId}/{requestId}?stream=true", UriKind.Relative);
@@ -82,7 +76,7 @@ public class AgentClient(HttpClient httpClient, ILogger<AgentClient> logger)
Messages = [new ChatMessage(ChatRole.User, message)]
};
var content = JsonContent.Create(request, s_jsonOptions.GetTypeInfo<ChatClientAgentRunRequest>(AgentClientJsonContext.Default));
var content = JsonContent.Create(request, AgentClientJsonContext.Default.ChatClientAgentRunRequest);
var requestUri = new Uri($"/invocations/actor/{agentName}/{sessionId}/{requestId}?stream=false", UriKind.Relative);
@@ -96,7 +90,7 @@ public class AgentClient(HttpClient httpClient, ILogger<AgentClient> logger)
try
{
var agentResponse = await response.Content.ReadFromJsonAsync(s_jsonOptions.GetTypeInfo<AgentResponse>(AgentClientJsonContext.Default), cancellationToken);
var agentResponse = await response.Content.ReadFromJsonAsync(AgentClientJsonContext.Default.AgentResponse, cancellationToken);
return agentResponse ?? new AgentResponse { Content = "No response received", Status = "error" };
}
catch (JsonException ex)
@@ -113,7 +107,7 @@ public class AgentClient(HttpClient httpClient, ILogger<AgentClient> logger)
try
{
var eventData = JsonSerializer.Deserialize(jsonData, s_jsonOptions.GetTypeInfo<EventData>(AgentClientJsonContext.Default));
var eventData = JsonSerializer.Deserialize(jsonData, AgentClientJsonContext.Default.EventData);
if (eventData?.Event != null)
{
var eventElement = eventData.Event.Value;
@@ -121,7 +115,7 @@ public class AgentClient(HttpClient httpClient, ILogger<AgentClient> logger)
// Try to deserialize as AgentRunResponseUpdate for intermediate updates
try
{
var update = JsonSerializer.Deserialize<AgentRunResponseUpdate>(eventElement.GetRawText(), s_jsonOptions);
var update = JsonSerializer.Deserialize<AgentRunResponseUpdate>(eventElement.GetRawText(), AgentAbstractionsJsonUtilities.DefaultOptions);
if (update != null)
{
responseUpdate = update;
@@ -171,32 +165,6 @@ public class AgentResponse
public string Status { get; set; } = "";
}
/// <summary>
/// Provides extension methods for JSON serialization with source generation support.
/// </summary>
internal static class JsonSerializerExtensions
{
/// <summary>
/// Gets the JsonTypeInfo for a type, preferring the one from options if available,
/// otherwise falling back to the source-generated context.
/// </summary>
/// <typeparam name="T">The type to get JsonTypeInfo for.</typeparam>
/// <param name="options">The JsonSerializerOptions to check first.</param>
/// <param name="fallbackContext">The fallback JsonSerializerContext to use if not found in options.</param>
/// <returns>The JsonTypeInfo for the requested type.</returns>
public static JsonTypeInfo<T> GetTypeInfo<T>(this JsonSerializerOptions options, JsonSerializerContext fallbackContext)
{
// Try to get from the options first (if a context is configured)
if (options.TypeInfoResolver?.GetTypeInfo(typeof(T), options) is JsonTypeInfo<T> typeInfo)
{
return typeInfo;
}
// Fall back to the provided source-generated context
return (JsonTypeInfo<T>)fallbackContext.GetTypeInfo(typeof(T))!;
}
}
/// <summary>
/// Source-generated JSON type information for use by AgentClient.
/// </summary>
@@ -206,10 +174,6 @@ internal static class JsonSerializerExtensions
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = false)]
[JsonSerializable(typeof(ChatClientAgentRunRequest))]
[JsonSerializable(typeof(ChatMessage))]
[JsonSerializable(typeof(List<ChatMessage>))]
[JsonSerializable(typeof(EventData))]
[JsonSerializable(typeof(AgentRunResponseUpdate))]
[JsonSerializable(typeof(AgentResponse))]
[JsonSerializable(typeof(JsonElement))]
internal sealed partial class AgentClientJsonContext : JsonSerializerContext;