Skip to content

Fix/content block code execution result#166

Merged
tghamm merged 3 commits into
tghamm:mainfrom
eduardostefani:fix/content-block-code-execution-result
Oct 24, 2025
Merged

Fix/content block code execution result#166
tghamm merged 3 commits into
tghamm:mainfrom
eduardostefani:fix/content-block-code-execution-result

Conversation

@eduardostefani
Copy link
Copy Markdown
Contributor

When using the code_execution tool with streaming, the chunk with bash_code_execution_tool_result content block has its content as an object instead of a list of content, which is currently mapped in the default ContentBlock.

In this PR I'm overriding it for the bash_code_execution_tool_result and adding a converter to make sure the response is deserialized to the correct type.

I'm also adding the ExpiresAt to the container response.

@tghamm tghamm requested a review from Copilot October 24, 2025 04:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes a deserialization issue where the bash_code_execution_tool_result content block was incorrectly mapped as a list when it should be a single object. The fix introduces a specialized content block class with a custom converter to handle this case correctly during streaming operations. Additionally, the PR adds an ExpiresAt field to the container response.

Key Changes

  • Created BashCodeExecutionToolResultContentBlock to override the Content property type from list to single object
  • Implemented ContentBlockConverter to deserialize content blocks based on their type
  • Added ExpiresAt property to ContainerResponse for tracking container expiration

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
Anthropic.SDK/Messaging/MessageResponse.cs Added new BashCodeExecutionToolResultContentBlock class with overridden Content property
Anthropic.SDK/Messaging/Container.cs Added ExpiresAt property to track container expiration dates
Anthropic.SDK/Extensions/ContentBlockConverter.cs Implemented custom JSON converter for polymorphic ContentBlock deserialization
Anthropic.SDK/EndpointBase.cs Registered ContentBlockConverter in streaming JSON serialization options

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +21 to +37
using (var jsonDoc = JsonDocument.ParseValue(ref reader))
{
var root = jsonDoc.RootElement;
var type = root.GetProperty("type").GetString();

var optionsCopy = GetJsonOptionsCopy(options);

return type switch
{
"bash_code_execution_tool_result" =>
JsonSerializer.Deserialize<BashCodeExecutionToolResultContentBlock>(
root.GetRawText(),
optionsCopy
),
_ => JsonSerializer.Deserialize<ContentBlock>(root.GetRawText(), optionsCopy),
};
}
Copy link

Copilot AI Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using statement with parentheses is an older C# syntax. Consider using the more modern 'using var' declaration pattern which automatically disposes at the end of the enclosing scope, improving code readability.

Suggested change
using (var jsonDoc = JsonDocument.ParseValue(ref reader))
{
var root = jsonDoc.RootElement;
var type = root.GetProperty("type").GetString();
var optionsCopy = GetJsonOptionsCopy(options);
return type switch
{
"bash_code_execution_tool_result" =>
JsonSerializer.Deserialize<BashCodeExecutionToolResultContentBlock>(
root.GetRawText(),
optionsCopy
),
_ => JsonSerializer.Deserialize<ContentBlock>(root.GetRawText(), optionsCopy),
};
}
using var jsonDoc = JsonDocument.ParseValue(ref reader);
var root = jsonDoc.RootElement;
var type = root.GetProperty("type").GetString();
var optionsCopy = GetJsonOptionsCopy(options);
return type switch
{
"bash_code_execution_tool_result" =>
JsonSerializer.Deserialize<BashCodeExecutionToolResultContentBlock>(
root.GetRawText(),
optionsCopy
),
_ => JsonSerializer.Deserialize<ContentBlock>(root.GetRawText(), optionsCopy),
};

Copilot uses AI. Check for mistakes.
using (var jsonDoc = JsonDocument.ParseValue(ref reader))
{
var root = jsonDoc.RootElement;
var type = root.GetProperty("type").GetString();
Copy link

Copilot AI Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing null check after GetProperty. If the 'type' property is missing from the JSON, this will throw a KeyNotFoundException. Consider using TryGetProperty to handle missing properties gracefully.

Suggested change
var type = root.GetProperty("type").GetString();
string type = null;
if (root.TryGetProperty("type", out var typeProperty))
{
type = typeProperty.GetString();
}

Copilot uses AI. Check for mistakes.
@tghamm
Copy link
Copy Markdown
Owner

tghamm commented Oct 24, 2025

Thanks for the PR! I kind of went down a rabbit hole on this one and ended up taking a different approach. After adding an integration test, I was hitting a deserialization exception with the approach you took, not on the bash results, but rather on the text editor code results. I also saw an opportunity to knock out two birds with one stone, as I believe my approach will resolve a lingering issue that's been open for a while as well as satisfying your issue: #121

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WebSearchToolResultContent.Content deserialization issue

3 participants