From 16072eb8b1d009bc630dc71feb73d467c8ccb8e8 Mon Sep 17 00:00:00 2001 From: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com> Date: Mon, 1 Sep 2025 21:43:35 +0100 Subject: [PATCH 1/6] Add reasoning text content for OpenAI Responses ChatClient Streaming --- .../OpenAIResponsesChatClient.cs | 21 +++ .../OpenAIResponseClientTests.cs | 170 ++++++++++++++++++ 2 files changed, 191 insertions(+) diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs index afb03b518d9..23207b45793 100644 --- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs +++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs @@ -9,6 +9,7 @@ using System.Runtime.CompilerServices; using System.Text; using System.Text.Json; +using System.Text.Json.Serialization.Metadata; using System.Threading; using System.Threading.Tasks; using Microsoft.Shared.Diagnostics; @@ -26,6 +27,9 @@ namespace Microsoft.Extensions.AI; /// Represents an for an . internal sealed class OpenAIResponsesChatClient : IChatClient { + /// Type info for serializing and deserializing arbitrary JSON objects. + private static readonly JsonTypeInfo _jsonTypeInfo = AIJsonUtilities.DefaultOptions.GetTypeInfo(typeof(object)); + /// Metadata about the client. private readonly ChatClientMetadata _metadata; @@ -324,8 +328,25 @@ ChatResponseUpdate CreateUpdate(AIContent? content = null) => break; default: + { + // Breaking-Glass capture of streaming reasoning contents + if (streamingUpdate.GetType().Name == "InternalResponseReasoningSummaryTextDeltaEvent") + { + var responseDeltaElement = JsonSerializer.Deserialize( + JsonSerializer.Serialize(streamingUpdate, _jsonTypeInfo), + OpenAIJsonContext.Default.JsonElement); + + if (responseDeltaElement.TryGetProperty("delta", out var deltaProperty)) + { + yield return CreateUpdate(new TextReasoningContent(deltaProperty.GetString())); + break; + } + } + yield return CreateUpdate(); break; + } + } } } diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs index 72df6002ca2..c405c3fa809 100644 --- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs @@ -168,6 +168,176 @@ public async Task BasicRequestResponse_NonStreaming() Assert.Equal(36, response.Usage.TotalTokenCount); } + [Fact] + public async Task BasicReasoningResponse_Streaming() + { + const string Input = """ + { + "input":[{ + "type":"message", + "role":"user", + "content":[{ + "type":"input_text", + "text":"Calculate the sum of the first 5 positive integers." + }] + }], + "reasoning": { + "summary": "detailed", + "effort": "low" + }, + "model": "o4-mini", + "stream": true + } + """; + + // Compressed down for testing purposes; real-world output would be larger. + const string Output = """ + event: response.created + data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_68b5ebab461881969ed94149372c2a530698ecbf1b9f2704","object":"response","created_at":1756752811,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"o4-mini-2025-04-16","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"low","summary":"detailed"},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} + + event: response.in_progress + data: {"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_68b5ebab461881969ed94149372c2a530698ecbf1b9f2704","object":"response","created_at":1756752811,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"o4-mini-2025-04-16","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"low","summary":"detailed"},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} + + event: response.output_item.added + data: {"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"rs_68b5ebabc0088196afb9fa86b487732d0698ecbf1b9f2704","type":"reasoning","summary":[]}} + + event: response.reasoning_summary_part.added + data: {"type":"response.reasoning_summary_part.added","sequence_number":3,"item_id":"rs_68b5ebabc0088196afb9fa86b487732d0698ecbf1b9f2704","output_index":0,"summary_index":0,"part":{"type":"summary_text","text":""}} + + event: response.reasoning_summary_text.delta + data: {"type":"response.reasoning_summary_text.delta","sequence_number":4,"item_id":"rs_68b5ebabc0088196afb9fa86b487732d0698ecbf1b9f2704","output_index":0,"summary_index":0,"delta":"**Calcul","obfuscation":"sLkbFySM"} + + event: response.reasoning_summary_text.delta + data: {"type":"response.reasoning_summary_text.delta","sequence_number":5,"item_id":"rs_68b5ebabc0088196afb9fa86b487732d0698ecbf1b9f2704","output_index":0,"summary_index":0,"delta":"ating","obfuscation":"dkm1f6DKqUj"} + + event: response.reasoning_summary_text.delta + data: {"type":"response.reasoning_summary_text.delta","sequence_number":6,"item_id":"rs_68b5ebabc0088196afb9fa86b487732d0698ecbf1b9f2704","output_index":0,"summary_index":0,"delta":" a","obfuscation":"X8ahc2lfCf9eA1"} + + event: response.reasoning_summary_text.delta + data: {"type":"response.reasoning_summary_text.delta","sequence_number":7,"item_id":"rs_68b5ebabc0088196afb9fa86b487732d0698ecbf1b9f2704","output_index":0,"summary_index":0,"delta":" simple","obfuscation":"1rLVyIaNl"} + + event: response.reasoning_summary_text.delta + data: {"type":"response.reasoning_summary_text.delta","sequence_number":8,"item_id":"rs_68b5ebabc0088196afb9fa86b487732d0698ecbf1b9f2704","output_index":0,"summary_index":0,"delta":" sum","obfuscation":"jCK7mgNR80Re"} + + event: response.reasoning_summary_text.done + data: {"type":"response.reasoning_summary_text.done","sequence_number":9,"item_id":"rs_68b5ebabc0088196afb9fa86b487732d0698ecbf1b9f2704","output_index":0,"summary_index":0,"text":"**Calculating a simple sum**"} + + event: response.reasoning_summary_part.done + data: {"type":"response.reasoning_summary_part.done","sequence_number":10,"item_id":"rs_68b5ebabc0088196afb9fa86b487732d0698ecbf1b9f2704","output_index":0,"summary_index":0,"part":{"type":"summary_text","text":"**Calculating a simple sum**"}} + + event: response.output_item.done + data: {"type":"response.output_item.done","sequence_number":11,"output_index":0,"item":{"id":"rs_68b5ebabc0088196afb9fa86b487732d0698ecbf1b9f2704","type":"reasoning","summary":[{"type":"summary_text","text":"**Calculating a simple sum**"}]}} + + event: response.output_item.added + data: {"type":"response.output_item.added","sequence_number":12,"output_index":1,"item":{"id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","type":"message","status":"in_progress","content":[],"role":"assistant"}} + + event: response.content_part.added + data: {"type":"response.content_part.added","sequence_number":13,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}} + + event: response.output_text.delta + data: {"type":"response.output_text.delta","sequence_number":14,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"delta":"The","logprobs":[],"obfuscation":"japg2KaCkjNsp"} + + event: response.output_text.delta + data: {"type":"response.output_text.delta","sequence_number":15,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"delta":" sum","logprobs":[],"obfuscation":"1BEqjKQ0KU41"} + + event: response.output_text.delta + data: {"type":"response.output_text.delta","sequence_number":16,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"GUqom1rsdZsnT"} + + event: response.output_text.delta + data: {"type":"response.output_text.delta","sequence_number":17,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"UmCms91yrTlg"} + + event: response.output_text.delta + data: {"type":"response.output_text.delta","sequence_number":18,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"delta":" first","logprobs":[],"obfuscation":"AyNbZpfTXo"} + + event: response.output_text.delta + data: {"type":"response.output_text.delta","sequence_number":19,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"tuyz4HkKODFQRtk"} + + event: response.output_text.delta + data: {"type":"response.output_text.delta","sequence_number":20,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"delta":"5","logprobs":[],"obfuscation":"QAwyISolmjXfTlc"} + + event: response.output_text.delta + data: {"type":"response.output_text.delta","sequence_number":21,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"delta":" positive","logprobs":[],"obfuscation":"2Euge1H"} + + event: response.output_text.delta + data: {"type":"response.output_text.delta","sequence_number":22,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"delta":" integers","logprobs":[],"obfuscation":"ih0Znt8"} + + event: response.output_text.delta + data: {"type":"response.output_text.delta","sequence_number":23,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"delta":" is","logprobs":[],"obfuscation":"oQihR5Pw8jRz5"} + + event: response.output_text.delta + data: {"type":"response.output_text.delta","sequence_number":24,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"delta":" 15","logprobs":[],"obfuscation":"7TdJ1FWlZF8lTd"} + + event: response.output_text.delta + data: {"type":"response.output_text.delta","sequence_number":25,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"delta":".","logprobs":[],"obfuscation":"x2VAJKlWI8qjgYq"} + + event: response.output_text.done + data: {"type":"response.output_text.done","sequence_number":26,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"text":"The sum of the first 5 positive integers is 15.","logprobs":[]} + + event: response.content_part.done + data: {"type":"response.content_part.done","sequence_number":27,"item_id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","output_index":1,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"The sum of the first 5 positive integers is 15."}} + + event: response.output_item.done + data: {"type":"response.output_item.done","sequence_number":28,"output_index":1,"item":{"id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The sum of the first 5 positive integers is 15."}],"role":"assistant"}} + + event: response.completed + data: {"type":"response.completed","sequence_number":29,"response":{"id":"resp_68b5ebab461881969ed94149372c2a530698ecbf1b9f2704","object":"response","created_at":1756752811,"status":"completed","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"o4-mini-2025-04-16","output":[{"id":"rs_68b5ebabc0088196afb9fa86b487732d0698ecbf1b9f2704","type":"reasoning","summary":[{"type":"summary_text","text":"**Calculating a simple sum**"}]},{"id":"msg_68b5ebae5a708196b74b94f22ca8995e0698ecbf1b9f2704","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The sum of the first 5 positive integers is 15."}],"role":"assistant"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"low","summary":"detailed"},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":17,"input_tokens_details":{"cached_tokens":0},"output_tokens":122,"output_tokens_details":{"reasoning_tokens":64},"total_tokens":139},"user":null,"metadata":{}}} + + + """; + + using VerbatimHttpHandler handler = new(Input, Output); + using HttpClient httpClient = new(handler); + using IChatClient client = CreateResponseClient(httpClient, "o4-mini"); + + List updates = []; + await foreach (var update in client.GetStreamingResponseAsync("Calculate the sum of the first 5 positive integers.", new() + { + RawRepresentationFactory = options => new ResponseCreationOptions + { + ReasoningOptions = new() + { + ReasoningEffortLevel = ResponseReasoningEffortLevel.Low, + ReasoningSummaryVerbosity = ResponseReasoningSummaryVerbosity.Detailed + } + } + })) + { + updates.Add(update); + } + + Assert.Equal("The sum of the first 5 positive integers is 15.", string.Concat(updates.Select(u => u.Text))); + + var createdAt = DateTimeOffset.FromUnixTimeSeconds(1_756_752_811); + Assert.Equal(30, updates.Count); + + for (int i = 0; i < updates.Count; i++) + { + Assert.Equal("resp_68b5ebab461881969ed94149372c2a530698ecbf1b9f2704", updates[i].ResponseId); + Assert.Equal("resp_68b5ebab461881969ed94149372c2a530698ecbf1b9f2704", updates[i].ConversationId); + Assert.Equal(createdAt, updates[i].CreatedAt); + Assert.Equal("o4-mini-2025-04-16", updates[i].ModelId); + Assert.Null(updates[i].AdditionalProperties); +#pragma warning disable S1067 // Expressions should not be too complex + Assert.Equal((i >= 4 && i <= 8) || (i >= 14 && i <= 25) || i == 29 ? 1 : 0, updates[i].Contents.Count); +#pragma warning restore S1067 // Expressions should not be too complex + Assert.Equal(i < updates.Count - 1 ? null : ChatFinishReason.Stop, updates[i].FinishReason); + } + + // Reasoning Content Check + for (int i = 4; i <= 8; i++) + { + Assert.Null(updates[i].Role); + var reasoning = Assert.IsType(updates[i].Contents.Single()); + Assert.NotNull(reasoning); + Assert.NotNull(reasoning.Text); + } + + UsageContent usage = updates.SelectMany(u => u.Contents).OfType().Single(); + Assert.Equal(17, usage.Details.InputTokenCount); + Assert.Equal(122, usage.Details.OutputTokenCount); + Assert.Equal(139, usage.Details.TotalTokenCount); + } + [Fact] public async Task BasicRequestResponse_Streaming() { From a6ee61c44571df3b9ef242c3aef4ec3041537c4e Mon Sep 17 00:00:00 2001 From: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com> Date: Mon, 1 Sep 2025 22:03:20 +0100 Subject: [PATCH 2/6] Changed tests for more legible check --- .../OpenAIResponseClientTests.cs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs index c405c3fa809..85cfaa3ed77 100644 --- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs @@ -317,9 +317,23 @@ public async Task BasicReasoningResponse_Streaming() Assert.Equal(createdAt, updates[i].CreatedAt); Assert.Equal("o4-mini-2025-04-16", updates[i].ModelId); Assert.Null(updates[i].AdditionalProperties); -#pragma warning disable S1067 // Expressions should not be too complex - Assert.Equal((i >= 4 && i <= 8) || (i >= 14 && i <= 25) || i == 29 ? 1 : 0, updates[i].Contents.Count); -#pragma warning restore S1067 // Expressions should not be too complex + + if (i is (>= 4 and <= 8)) + { + // Reasoning updates + Assert.Single(updates[i].Contents); + } + else if (i is (>= 14 and <= 25) or 29) + { + // Response Complete and Assistant message updates + Assert.Single(updates[i].Contents); + } + else + { + // Other updates + Assert.Empty(updates[i].Contents); + } + Assert.Equal(i < updates.Count - 1 ? null : ChatFinishReason.Stop, updates[i].FinishReason); } From 37c3b083791959be5d8f2dbc076ae5e90910ff51 Mon Sep 17 00:00:00 2001 From: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com> Date: Tue, 2 Sep 2025 10:42:44 +0100 Subject: [PATCH 3/6] Triggering a new build + small refactor --- .../OpenAIResponseClientTests.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs index 85cfaa3ed77..ca71aee550f 100644 --- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs @@ -322,6 +322,11 @@ public async Task BasicReasoningResponse_Streaming() { // Reasoning updates Assert.Single(updates[i].Contents); + Assert.Null(updates[i].Role); + + var reasoning = Assert.IsType(updates[i].Contents.Single()); + Assert.NotNull(reasoning); + Assert.NotNull(reasoning.Text); } else if (i is (>= 14 and <= 25) or 29) { @@ -337,15 +342,6 @@ public async Task BasicReasoningResponse_Streaming() Assert.Equal(i < updates.Count - 1 ? null : ChatFinishReason.Stop, updates[i].FinishReason); } - // Reasoning Content Check - for (int i = 4; i <= 8; i++) - { - Assert.Null(updates[i].Role); - var reasoning = Assert.IsType(updates[i].Contents.Single()); - Assert.NotNull(reasoning); - Assert.NotNull(reasoning.Text); - } - UsageContent usage = updates.SelectMany(u => u.Contents).OfType().Single(); Assert.Equal(17, usage.Details.InputTokenCount); Assert.Equal(122, usage.Details.OutputTokenCount); From 0742708988fe18ddbe689340269264ea4a697ecf Mon Sep 17 00:00:00 2001 From: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:24:22 +0100 Subject: [PATCH 4/6] Address suggestion --- .../OpenAIResponsesChatClient.cs | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs index 23207b45793..d4601f1af95 100644 --- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs +++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs @@ -4,12 +4,12 @@ using System; using System.ClientModel.Primitives; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using System.Text.Json; -using System.Text.Json.Serialization.Metadata; using System.Threading; using System.Threading.Tasks; using Microsoft.Shared.Diagnostics; @@ -27,8 +27,10 @@ namespace Microsoft.Extensions.AI; /// Represents an for an . internal sealed class OpenAIResponsesChatClient : IChatClient { - /// Type info for serializing and deserializing arbitrary JSON objects. - private static readonly JsonTypeInfo _jsonTypeInfo = AIJsonUtilities.DefaultOptions.GetTypeInfo(typeof(object)); + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] + private static readonly Type? _internalResponseReasoningSummaryTextDeltaEventType = Type.GetType("OpenAI.Responses.InternalResponseReasoningSummaryTextDeltaEvent, OpenAI"); + + private static readonly PropertyInfo? _summaryTextDeltaProperty = _internalResponseReasoningSummaryTextDeltaEventType?.GetProperty("Delta"); /// Metadata about the client. private readonly ChatClientMetadata _metadata; @@ -330,23 +332,16 @@ ChatResponseUpdate CreateUpdate(AIContent? content = null) => default: { // Breaking-Glass capture of streaming reasoning contents - if (streamingUpdate.GetType().Name == "InternalResponseReasoningSummaryTextDeltaEvent") + if (streamingUpdate.GetType() == _internalResponseReasoningSummaryTextDeltaEventType && + _summaryTextDeltaProperty?.GetValue(streamingUpdate) is string delta) { - var responseDeltaElement = JsonSerializer.Deserialize( - JsonSerializer.Serialize(streamingUpdate, _jsonTypeInfo), - OpenAIJsonContext.Default.JsonElement); - - if (responseDeltaElement.TryGetProperty("delta", out var deltaProperty)) - { - yield return CreateUpdate(new TextReasoningContent(deltaProperty.GetString())); - break; - } + yield return CreateUpdate(new TextReasoningContent(delta)); + break; } yield return CreateUpdate(); break; } - } } } From 07d76de498286a84e244bec351ed6711f206115a Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Thu, 4 Sep 2025 21:49:43 -0400 Subject: [PATCH 5/6] Update src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs --- .../Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs index f7856522dff..9ae048c954b 100644 --- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs +++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs @@ -27,9 +27,9 @@ namespace Microsoft.Extensions.AI; /// Represents an for an . internal sealed class OpenAIResponsesChatClient : IChatClient { + // Fix this to not use reflection once https://github.com/openai/openai-dotnet/issues/643 is addressed. [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] private static readonly Type? _internalResponseReasoningSummaryTextDeltaEventType = Type.GetType("OpenAI.Responses.InternalResponseReasoningSummaryTextDeltaEvent, OpenAI"); - private static readonly PropertyInfo? _summaryTextDeltaProperty = _internalResponseReasoningSummaryTextDeltaEventType?.GetProperty("Delta"); /// Metadata about the client. From e5785760d2ea7920bc7e30c6f8f02b32e0edc730 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Thu, 4 Sep 2025 21:50:17 -0400 Subject: [PATCH 6/6] Update src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs --- .../Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs index 9ae048c954b..b5d3c09de32 100644 --- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs +++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs @@ -331,7 +331,6 @@ ChatResponseUpdate CreateUpdate(AIContent? content = null) => default: { - // Breaking-Glass capture of streaming reasoning contents if (streamingUpdate.GetType() == _internalResponseReasoningSummaryTextDeltaEventType && _summaryTextDeltaProperty?.GetValue(streamingUpdate) is string delta) {