Skip to content

.NET: Add Code Interpreter container file download samples#5014

Open
chetantoshniwal wants to merge 1 commit intomicrosoft:mainfrom
chetantoshniwal:agent/fix-3081-1
Open

.NET: Add Code Interpreter container file download samples#5014
chetantoshniwal wants to merge 1 commit intomicrosoft:mainfrom
chetantoshniwal:agent/fix-3081-1

Conversation

@chetantoshniwal
Copy link
Copy Markdown
Contributor

@chetantoshniwal chetantoshniwal commented Mar 31, 2026

Motivation and Context

Azure OpenAI Responses API Code Interpreter generates files with cfile_ IDs that live inside containers (cntr_ IDs). The standard Files API (GetOpenAIFileClient) cannot download these container-scoped files, leaving users unable to retrieve Code Interpreter output.

Fixes #3081

Description

Revised approach: Instead of adding a wrapper extension method (which is not our responsibility — the OpenAI SDK already provides ContainerClient directly), this PR adds two end-to-end samples that demonstrate the correct pattern for downloading Code Interpreter generated files.

What changed

  • Removed OpenAIClientContainerFileExtensions and its unit tests — the OpenAI SDK already provides OpenAIClient.GetContainerClient() and ContainerClient.DownloadContainerFileAsync() natively.
  • Added Agent_OpenAI_Step06_CodeInterpreterFileDownload — Public OpenAI sample using OpenAIClientGetResponsesClient().AsAIAgent() with Code Interpreter → downloads container files via openAIClient.GetContainerClient().
  • Added Agent_Step24_CodeInterpreterFileDownload — Microsoft Foundry sample using AIProjectClient.AsAIAgent() with HostedCodeInterpreterTool → downloads via aiProjectClient.GetProjectOpenAIClient().GetContainerClient().
  • Updated solution file and parent READMEs to include the new samples.

Key finding

AzureOpenAIClient.GetContainerClient() throws InvalidOperationException, but AIProjectClient.GetProjectOpenAIClient() returns a ProjectOpenAIClient which inherits from OpenAI.OpenAIClient (not AzureOpenAIClient), so GetContainerClient() works on it. This is the correct path for Foundry users.

Container files vs regular files

The samples and their READMEs explain the difference:

  • Code Interpreter files have cfile_ IDs and live inside cntr_ containers
  • Standard Files API (GetOpenAIFileClient) returns 404 for these IDs
  • Use ContainerClient (GetContainerClient()) to download them
  • The ContainerId and FileId are available from ContainerFileCitationMessageAnnotation via CitationAnnotation.RawRepresentation

Verified end-to-end

Both samples were tested against real services and successfully downloaded generated CSV files:

  • ✅ Public OpenAI: Downloaded multiplication_times_table.csv (1378 bytes)
  • ✅ Microsoft Foundry: Downloaded multiplication_times_tables_1_to_12.csv (498 bytes)

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass (96/96), and samples verified E2E
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

Copy link
Copy Markdown
Contributor Author

@chetantoshniwal chetantoshniwal left a comment

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 4 | Confidence: 86%

✓ Correctness

The PR adds a thin extension method on OpenAIClient to download container files, plus comprehensive input-validation unit tests. The implementation is clean: argument guards use the shared Throw helper consistently, the CancellationToken is forwarded correctly, the namespace follows existing conventions (OpenAI extensions live in the OpenAI namespace), and the [Experimental] attribute matches other extension classes. The tests correctly expect ArgumentNullException for null inputs and ArgumentException for empty/whitespace, matching the Throw.IfNullOrWhitespace behavior. No correctness issues found.

✓ Security Reliability

This PR adds a clean extension method for downloading OpenAI container files, with proper input validation via the established Throw helpers, correct CancellationToken propagation, and ConfigureAwait(false) for library code. The method follows the same patterns used by other extension methods in the project (e.g., OpenAIResponseClientExtensions). Tests cover all guard-clause branches. No security or reliability concerns were identified — there are no injection risks, resource leaks, secrets, or unhandled failure modes.

✗ Test Coverage

The test file thoroughly covers all input-validation guard clauses (null, empty, and whitespace for both containerId and fileId, plus null client), which is good. However, there is no happy-path test verifying that when valid arguments are supplied, the method actually delegates to client.GetContainerClient().DownloadContainerFileAsync(...) with the correct arguments and propagates the CancellationToken. The tests only exercise the three Throw.* lines (lines 39-41 of the production code) and never reach the actual business logic on lines 43-44. This is a significant gap: without a happy-path test, a regression that breaks the delegation or drops the CancellationToken would go undetected.

✓ Design Approach

The extension follows the established pattern in this codebase (thin validated wrapper over an SDK method, placed in the SDK's namespace) and the implementation itself is sound. The only meaningful gap is the complete absence of a happy-path test: all seven tests exercise pre-condition validation that fires before the method reaches GetContainerClient().DownloadContainerFileAsync(), so the actual delegation logic—the one line of real behaviour—is entirely untested. If the underlying SDK method is mockable or the OpenAIClient subclass approach already used in the test file can be extended to stub the container client, a success-case test should be added.

Flagged Issues

  • No happy-path test: the core behavior of the method — obtaining a ContainerClient and calling DownloadContainerFileAsync with the correct containerId, fileId, and CancellationToken (lines 43-44) — is completely untested. All seven tests only cover argument-validation guard clauses.

Suggestions

  • Add a happy-path test that extends the existing TestOpenAIClient stub (similar to the pattern in OpenAIAssistantClientExtensionsTests) to intercept GetContainerClient().DownloadContainerFileAsync, then verify that the extension correctly delegates with the expected containerId, fileId, and CancellationToken and returns the expected ClientResult.
  • Consider adding a test that verifies CancellationToken propagation — e.g., passing a pre-cancelled token and asserting it is forwarded to the underlying SDK call.

Automated review by chetantoshniwal's agents

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

Adds a .NET extension on OpenAIClient to download Code Interpreter container-scoped files (cfile_ within cntr_) via the Containers API, addressing the inability to download these files through the standard Files API.

Changes:

  • Added OpenAIClientContainerFileExtensions.DownloadContainerFileAsync to route downloads through GetContainerClient().
  • Added unit tests covering null/empty/whitespace argument guards for client, containerId, and fileId.

Reviewed changes

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

File Description
dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIClientContainerFileExtensions.cs New OpenAIClient extension method to download container-scoped cfile_ outputs via Containers API.
dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIClientContainerFileExtensionsTests.cs New unit tests validating argument guard behavior for the new extension method.

@rogerbarreto rogerbarreto changed the title .NET: Add container file download extension for Code Interpreter cfile_ IDs .NET: Add Code Interpreter container file download samples Apr 7, 2026
@moonbox3 moonbox3 added the documentation Improvements or additions to documentation label Apr 7, 2026
@rogerbarreto rogerbarreto self-assigned this Apr 7, 2026
@rogerbarreto rogerbarreto requested a review from a team as a code owner April 7, 2026 15:08
@moonbox3 moonbox3 added python workflows Related to Workflows in agent-framework lab Agent Framework Lab labels Apr 7, 2026
@github-actions github-actions bot changed the title .NET: Add Code Interpreter container file download samples Python: .NET: Add Code Interpreter container file download samples Apr 7, 2026
- Add Agent_OpenAI_Step06_CodeInterpreterFileDownload (Public OpenAI)
- Add Agent_Step24_CodeInterpreterFileDownload (Microsoft Foundry)
- Both samples demonstrate downloading cfile_/cntr_ container files
  via ContainerClient instead of the standard Files API
- Update solution file and parent READMEs
Comment on lines +35 to +44
foreach (ChatMessage message in response.Messages)
{
foreach (AIContent content in message.Contents)
{
if (content is TextContent textContent)
{
Console.WriteLine(textContent.Text);
}
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggestion

Suggested change
foreach (ChatMessage message in response.Messages)
{
foreach (AIContent content in message.Contents)
{
if (content is TextContent textContent)
{
Console.WriteLine(textContent.Text);
}
}
}
foreach (TextContent textContent in response.Messages.SelectMany(x => x.Contents).OfType<TextContent>())
{
Console.WriteLine(textContent.Text);
}

Comment on lines +54 to +56
foreach (ChatMessage message in response.Messages)
{
foreach (AIContent content in message.Contents)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This could also be flattened into foreach (ChatMessage message in response.Messages.SelectMany(x => x.Contents))

@eavanvalkenburg eavanvalkenburg changed the title Python: .NET: Add Code Interpreter container file download samples .NET: Add Code Interpreter container file download samples Apr 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation lab Agent Framework Lab .NET workflows Related to Workflows in agent-framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

.NET: Cannot download Code Interpreter generated files using cfile_ IDs from Azure OpenAI Responses API

7 participants