From e44196c1b437a16a36a0883683d98502e0b70a18 Mon Sep 17 00:00:00 2001 From: Joseph Daigle Date: Wed, 22 Oct 2025 23:30:01 -0400 Subject: [PATCH] Implementing various fixes: 1. The `RedactedContent` property of `TextReasoningContent` is optional and not required for Claude 4 models. Don't throw new it's not found in `AdditionalProperties`. 2. Use `ProtectedData` for the "Signature" of the reasoning content so that it round trips. See: https://github.com/dotnet/extensions/pull/6784 3. In `GetStreamingResponseAsync`, the final `ReasoningContentBlockDelta` may not have text, but it will have `Signature` and possibly `RedactedContent` These fix a scenario where thinking + tool use fails because the reasoning content sent back with the tool response is invalid. --- ...WSSDK.Extensions.Bedrock.MEAI.NetFramework.csproj | 2 +- ...AWSSDK.Extensions.Bedrock.MEAI.NetStandard.csproj | 2 +- .../AWSSDK.Extensions.Bedrock.MEAI.nuspec | 6 +++--- .../BedrockChatClient.cs | 12 +++++++----- .../BedrockMEAITests.NetFramework.csproj | 2 +- .../6c035145-4fe4-42cd-9339-4f10256de2e7.json | 11 +++++++++++ 6 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 generator/.DevConfigs/6c035145-4fe4-42cd-9339-4f10256de2e7.json diff --git a/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/AWSSDK.Extensions.Bedrock.MEAI.NetFramework.csproj b/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/AWSSDK.Extensions.Bedrock.MEAI.NetFramework.csproj index df6d55e9e4e6..446626bb8afa 100644 --- a/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/AWSSDK.Extensions.Bedrock.MEAI.NetFramework.csproj +++ b/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/AWSSDK.Extensions.Bedrock.MEAI.NetFramework.csproj @@ -37,7 +37,7 @@ - + diff --git a/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/AWSSDK.Extensions.Bedrock.MEAI.NetStandard.csproj b/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/AWSSDK.Extensions.Bedrock.MEAI.NetStandard.csproj index dde3ae6c2422..97b1a20a55e0 100644 --- a/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/AWSSDK.Extensions.Bedrock.MEAI.NetStandard.csproj +++ b/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/AWSSDK.Extensions.Bedrock.MEAI.NetStandard.csproj @@ -41,7 +41,7 @@ - + diff --git a/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/AWSSDK.Extensions.Bedrock.MEAI.nuspec b/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/AWSSDK.Extensions.Bedrock.MEAI.nuspec index 95d38b348b15..5f54078ce358 100644 --- a/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/AWSSDK.Extensions.Bedrock.MEAI.nuspec +++ b/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/AWSSDK.Extensions.Bedrock.MEAI.nuspec @@ -15,17 +15,17 @@ - + - + - + diff --git a/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/BedrockChatClient.cs b/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/BedrockChatClient.cs index 0479bc878232..bfe33dbda368 100644 --- a/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/BedrockChatClient.cs +++ b/extensions/src/AWSSDK.Extensions.Bedrock.MEAI/BedrockChatClient.cs @@ -121,7 +121,7 @@ public async Task GetResponseAsync( if (reasoningContent.ReasoningText.Signature is string signature) { - (trc.AdditionalProperties ??= [])[nameof(reasoningContent.ReasoningText.Signature)] = signature; + trc.ProtectedData = signature; } if (reasoningContent.RedactedContent is { } redactedContent) @@ -249,13 +249,13 @@ public async IAsyncEnumerable GetStreamingResponseAsync( yield return textUpdate; } - if (contentBlockDelta.Delta.ReasoningContent is { Text: not null } reasoningContent) + if (contentBlockDelta.Delta.ReasoningContent is { } reasoningContent) { TextReasoningContent trc = new(reasoningContent.Text); if (reasoningContent.Signature is not null) { - (trc.AdditionalProperties ??= [])[nameof(reasoningContent.Signature)] = reasoningContent.Signature; + trc.ProtectedData = reasoningContent.Signature; } if (reasoningContent.RedactedContent is { } redactedContent) @@ -516,6 +516,8 @@ private static List CreateContents(ChatMessage message) break; case TextReasoningContent trc: + object? redactedContent = null; + trc.AdditionalProperties?.TryGetValue(nameof(ReasoningContentBlock.RedactedContent), out redactedContent); contents.Add(new() { ReasoningContent = new() @@ -523,9 +525,9 @@ private static List CreateContents(ChatMessage message) ReasoningText = new() { Text = trc.Text, - Signature = trc.AdditionalProperties?[nameof(ReasoningContentBlock.ReasoningText.Signature)] as string, + Signature = trc.ProtectedData, }, - RedactedContent = trc.AdditionalProperties?[nameof(ReasoningContentBlock.RedactedContent)] is byte[] array ? new(array) : null, + RedactedContent = redactedContent is byte[] array ? new(array) : null, } }); break; diff --git a/extensions/test/BedrockMEAITests/BedrockMEAITests.NetFramework.csproj b/extensions/test/BedrockMEAITests/BedrockMEAITests.NetFramework.csproj index 42c9d80ffa65..dd9de35ce4a5 100644 --- a/extensions/test/BedrockMEAITests/BedrockMEAITests.NetFramework.csproj +++ b/extensions/test/BedrockMEAITests/BedrockMEAITests.NetFramework.csproj @@ -18,7 +18,7 @@ - + diff --git a/generator/.DevConfigs/6c035145-4fe4-42cd-9339-4f10256de2e7.json b/generator/.DevConfigs/6c035145-4fe4-42cd-9339-4f10256de2e7.json new file mode 100644 index 000000000000..25da818f4561 --- /dev/null +++ b/generator/.DevConfigs/6c035145-4fe4-42cd-9339-4f10256de2e7.json @@ -0,0 +1,11 @@ +{ + "extensions": [ + { + "extensionName": "Extensions.Bedrock.MEAI", + "type": "patch", + "changeLogMessages": [ + "Fix reading/writing ReasoningContent for tool use." + ] + } + ] +} \ No newline at end of file