Files
agent-framework/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Models/ConversationReference.cs
T
3c322c91e7 .NET: Update to latest Azure.AI.*, OpenAI, and M.E.AI* (#2850)
* Update to latest Azure.AI.*, OpenAI, and M.E.AI*

Absorb breaking changes in Responses surface area

* Update dotnet/samples/AgentWebChat/AgentWebChat.AgentHost/Utilities/ChatClientExtensions.cs

* Update dotnet/samples/AgentWebChat/AgentWebChat.AgentHost/Utilities/ChatClientExtensions.cs

* Update dotnet/samples/AgentWebChat/AgentWebChat.AgentHost/Utilities/ChatClientExtensions.cs

* Update dotnet/samples/GettingStarted/AgentWithOpenAI/Agent_OpenAI_Step04_CreateFromOpenAIResponseClient/Program.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Using patch to remove the model is necessary, updated the response client to actually use the the ForAgent

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
2025-12-16 12:41:20 +00:00

102 lines
3.9 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Microsoft.Agents.AI.Hosting.OpenAI.Responses.Models;
/// <summary>
/// Represents a reference to a conversation, which can be either a conversation ID (string) or a conversation object.
/// </summary>
[JsonConverter(typeof(ConversationReferenceJsonConverter))]
internal sealed class ConversationReference
{
/// <summary>
/// The conversation ID.
/// </summary>
[JsonPropertyName("id")]
public string? Id { get; init; }
/// <summary>
/// The conversation metadata (optional, only when passing a conversation object).
/// </summary>
[JsonPropertyName("metadata")]
public Dictionary<string, string>? Metadata { get; init; }
/// <summary>
/// Creates a conversation reference from a conversation ID.
/// </summary>
public static ConversationReference FromId(string id) => new() { Id = id };
/// <summary>
/// Creates a conversation reference from a conversation object.
/// </summary>
public static ConversationReference FromObject(string id, Dictionary<string, string>? metadata = null) =>
new() { Id = id, Metadata = metadata };
}
/// <summary>
/// JSON converter for ConversationReference that handles both string (conversation ID) and object representations.
/// </summary>
internal sealed class ConversationReferenceJsonConverter : JsonConverter<ConversationReference>
{
/// <inheritdoc/>
public override ConversationReference? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
{
// Handle string format: just the conversation ID
var id = reader.GetString();
return id is null ? null : ConversationReference.FromId(id);
}
else if (reader.TokenType == JsonTokenType.StartObject)
{
// Handle object format: { "id": "...", "metadata": {...} }
using var doc = JsonDocument.ParseValue(ref reader);
var root = doc.RootElement;
var id = root.TryGetProperty("id", out var idProp) ? idProp.GetString() : null;
Dictionary<string, string>? metadata = null;
if (root.TryGetProperty("metadata", out var metadataProp) && metadataProp.ValueKind == JsonValueKind.Object)
{
metadata = JsonSerializer.Deserialize(metadataProp.GetRawText(), OpenAIHostingJsonContext.Default.DictionaryStringString);
}
return id is null ? null : ConversationReference.FromObject(id, metadata);
}
else if (reader.TokenType == JsonTokenType.Null)
{
return null;
}
throw new JsonException($"Unexpected token type for ConversationReference: {reader.TokenType}");
}
/// <inheritdoc/>
public override void Write(Utf8JsonWriter writer, ConversationReference value, JsonSerializerOptions options)
{
if (value is null)
{
writer.WriteNullValue();
return;
}
// Ideally if only ID is present and no metadata, we would serialize as a simple string.
// However, while a request's "conversation" property can be either a string or an object
// containing a string, a response's "conversation" property is always an object. Since
// here we don't know which scenario we're in, we always serialize as an object, which works
// in any scenario.
writer.WriteStartObject();
writer.WriteString("id", value.Id);
if (value.Metadata is not null)
{
writer.WritePropertyName("metadata");
JsonSerializer.Serialize(writer, value.Metadata, OpenAIHostingJsonContext.Default.DictionaryStringString);
}
writer.WriteEndObject();
}
}