-
Notifications
You must be signed in to change notification settings - Fork 1.5k
.NET: Add Code Interpreter container file download samples #5014
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
chetantoshniwal
wants to merge
1
commit into
microsoft:main
Choose a base branch
from
chetantoshniwal:agent/fix-3081-1
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
...Step06_CodeInterpreterFileDownload/Agent_OpenAI_Step06_CodeInterpreterFileDownload.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFrameworks>net10.0</TargetFrameworks> | ||
|
|
||
| <Nullable>enable</Nullable> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.OpenAI\Microsoft.Agents.AI.OpenAI.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
98 changes: 98 additions & 0 deletions
98
...ples/02-agents/AgentWithOpenAI/Agent_OpenAI_Step06_CodeInterpreterFileDownload/Program.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| // Copyright (c) Microsoft. All rights reserved. | ||
|
|
||
| // This sample shows how to download files generated by Code Interpreter using the Containers API. | ||
| // Code Interpreter generates files inside containers (cfile_ / cntr_ IDs) which cannot be | ||
| // downloaded via the standard Files API. Use ContainerClient instead. | ||
|
|
||
| #pragma warning disable OPENAI001 | ||
|
|
||
| using System.ClientModel; | ||
| using Microsoft.Agents.AI; | ||
| using Microsoft.Extensions.AI; | ||
| using OpenAI; | ||
| using OpenAI.Containers; | ||
| using OpenAI.Responses; | ||
|
|
||
| string apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set."); | ||
| string model = Environment.GetEnvironmentVariable("OPENAI_CHAT_MODEL_NAME") ?? "gpt-4o-mini"; | ||
|
|
||
| var openAIClient = new OpenAIClient(new ApiKeyCredential(apiKey)); | ||
|
|
||
| // Create an agent with Code Interpreter tool enabled | ||
| AIAgent agent = openAIClient | ||
| .GetResponsesClient() | ||
| .AsAIAgent( | ||
| model: model, | ||
| instructions: "You are a helpful assistant that can generate files using code.", | ||
| name: "CodeInterpreterAgent", | ||
| tools: [new HostedCodeInterpreterTool()]); | ||
|
|
||
| // Ask the agent to generate a file | ||
| AgentResponse response = await agent.RunAsync( | ||
| "Create a CSV file with the multiplication times tables from 1 to 12. Include headers."); | ||
|
|
||
| // Display the text response | ||
| foreach (ChatMessage message in response.Messages) | ||
| { | ||
| foreach (AIContent content in message.Contents) | ||
| { | ||
| if (content is TextContent textContent) | ||
| { | ||
| Console.WriteLine(textContent.Text); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Extract container file citations from response annotations and download | ||
| ContainerClient containerClient = openAIClient.GetContainerClient(); | ||
|
|
||
| HashSet<string> downloadedFiles = []; | ||
| bool foundContainerFiles = false; | ||
|
|
||
| foreach (ChatMessage message in response.Messages) | ||
| { | ||
| foreach (AIContent content in message.Contents) | ||
| { | ||
| if (content.Annotations is null) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| foreach (AIAnnotation annotation in content.Annotations) | ||
| { | ||
| // Container files from Code Interpreter have ContainerFileCitationMessageAnnotation as raw representation | ||
| if (annotation is CitationAnnotation citation | ||
| && citation.RawRepresentation is ContainerFileCitationMessageAnnotation containerCitation) | ||
| { | ||
| foundContainerFiles = true; | ||
|
|
||
| // Deduplicate by container+file ID in case the same file is cited multiple times | ||
| string key = $"{containerCitation.ContainerId}/{containerCitation.FileId}"; | ||
| if (!downloadedFiles.Add(key)) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| Console.WriteLine($"\nDownloading container file: {containerCitation.Filename}"); | ||
| Console.WriteLine($" Container ID: {containerCitation.ContainerId}"); | ||
| Console.WriteLine($" File ID: {containerCitation.FileId}"); | ||
|
|
||
| BinaryData fileData = await containerClient.DownloadContainerFileAsync( | ||
| containerCitation.ContainerId, | ||
| containerCitation.FileId); | ||
|
|
||
| // Sanitize filename to prevent path traversal | ||
| string safeFilename = Path.GetFileName(containerCitation.Filename); | ||
| string outputPath = Path.Combine(Directory.GetCurrentDirectory(), safeFilename); | ||
| await File.WriteAllBytesAsync(outputPath, fileData.ToArray()); | ||
| Console.WriteLine($" Saved to: {outputPath}"); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (!foundContainerFiles) | ||
| { | ||
| Console.WriteLine("\nNo container file citations found in the response."); | ||
| Console.WriteLine("The model may not have generated a downloadable file for this prompt."); | ||
| } |
51 changes: 51 additions & 0 deletions
51
...gents/AgentWithOpenAI/Agent_OpenAI_Step06_CodeInterpreterFileDownload/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # Code Interpreter File Download (OpenAI) | ||
|
|
||
| This sample demonstrates how to download files generated by Code Interpreter when using the OpenAI Responses API. | ||
|
|
||
| ## What this sample demonstrates | ||
|
|
||
| - Creating an agent with Code Interpreter tool using `ResponsesClient.AsAIAgent()` | ||
| - Generating files through Code Interpreter (e.g., CSV, Excel, images) | ||
| - Extracting container file citations from agent response annotations | ||
| - Downloading container files using the `ContainerClient` API | ||
|
|
||
| ## Container files vs regular files | ||
|
|
||
| When Code Interpreter generates a file, the file is stored inside a **container** with a `cntr_` prefixed ID. The file itself gets a `cfile_` prefixed ID. | ||
|
|
||
| These container files **cannot** be downloaded using the standard Files API (`GetOpenAIFileClient`), which returns 404 for `cfile_` IDs. Instead, you must use the **Containers API** (`GetContainerClient`) to download them: | ||
|
|
||
| ```csharp | ||
| // ❌ This does NOT work for container files | ||
| var filesClient = openAIClient.GetOpenAIFileClient(); | ||
| await filesClient.DownloadFileAsync("cfile_..."); // Returns 404 | ||
|
|
||
| // ✅ Use ContainerClient instead | ||
| var containerClient = openAIClient.GetContainerClient(); | ||
| await containerClient.DownloadContainerFileAsync("cntr_...", "cfile_..."); | ||
| ``` | ||
|
|
||
| The container ID and file ID are available from the `ContainerFileCitationMessageAnnotation` annotation in the response, accessible via `CitationAnnotation.RawRepresentation`. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - .NET 10 SDK or later | ||
| - OpenAI API key with access to a model that supports Code Interpreter | ||
|
|
||
| Set the following environment variables: | ||
|
|
||
| ```powershell | ||
| $env:OPENAI_API_KEY="sk-..." | ||
| $env:OPENAI_CHAT_MODEL_NAME="gpt-4o-mini" # Optional, defaults to gpt-4o-mini | ||
| ``` | ||
|
|
||
| ## Run the sample | ||
|
|
||
| ```powershell | ||
| dotnet run | ||
| ``` | ||
|
|
||
| ## See also | ||
|
|
||
| - [Code Interpreter File Download with Foundry](../../../02-agents/AgentsWithFoundry/Agent_Step24_CodeInterpreterFileDownload/) — same scenario using Microsoft Foundry | ||
| - [Code Interpreter](../../../02-agents/AgentsWithFoundry/Agent_Step14_CodeInterpreter/) — Code Interpreter without file download |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
.../Agent_Step24_CodeInterpreterFileDownload/Agent_Step24_CodeInterpreterFileDownload.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFrameworks>net10.0</TargetFrameworks> | ||
|
|
||
| <Nullable>enable</Nullable> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="Azure.Identity" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.Foundry\Microsoft.Agents.AI.Foundry.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
100 changes: 100 additions & 0 deletions
100
...t/samples/02-agents/AgentsWithFoundry/Agent_Step24_CodeInterpreterFileDownload/Program.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| // Copyright (c) Microsoft. All rights reserved. | ||
|
|
||
| // This sample shows how to download files generated by Code Interpreter using Microsoft Foundry. | ||
| // Code Interpreter generates files inside containers (cfile_ / cntr_ IDs) which cannot be | ||
| // downloaded via the standard Files API. Use ContainerClient from the project's OpenAI client instead. | ||
|
|
||
| #pragma warning disable OPENAI001 | ||
|
|
||
| using Azure.AI.Projects; | ||
| using Azure.Identity; | ||
| using Microsoft.Agents.AI; | ||
| using Microsoft.Extensions.AI; | ||
| using OpenAI.Responses; | ||
|
|
||
| string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); | ||
| string deploymentName = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; | ||
|
|
||
| // WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production. | ||
| // In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid | ||
| // latency issues, unintended credential probing, and potential security risks from fallback mechanisms. | ||
| AIProjectClient aiProjectClient = new(new Uri(endpoint), new DefaultAzureCredential()); | ||
|
|
||
| // Create an agent with Code Interpreter tool enabled | ||
| AIAgent agent = aiProjectClient.AsAIAgent( | ||
| deploymentName, | ||
| instructions: "You are a helpful assistant that can generate files using code.", | ||
| name: "CodeInterpreterAgent", | ||
| tools: [new HostedCodeInterpreterTool()]); | ||
|
|
||
| // Ask the agent to generate a file | ||
| AgentResponse response = await agent.RunAsync( | ||
| "Create a CSV file with the multiplication times tables from 1 to 12. Include headers."); | ||
|
|
||
| // Display the text response | ||
| foreach (ChatMessage message in response.Messages) | ||
| { | ||
| foreach (AIContent content in message.Contents) | ||
| { | ||
| if (content is TextContent textContent) | ||
| { | ||
| Console.WriteLine(textContent.Text); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Extract container file citations from response annotations and download. | ||
| // AIProjectClient.GetProjectOpenAIClient() returns a ProjectOpenAIClient (inherits from OpenAI.OpenAIClient) | ||
| // which supports GetContainerClient(), unlike AzureOpenAIClient which does not. | ||
| var containerClient = aiProjectClient.GetProjectOpenAIClient().GetContainerClient(); | ||
|
|
||
| HashSet<string> downloadedFiles = []; | ||
| bool foundContainerFiles = false; | ||
|
|
||
| foreach (ChatMessage message in response.Messages) | ||
| { | ||
| foreach (AIContent content in message.Contents) | ||
|
Comment on lines
+54
to
+56
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could also be flattened into |
||
| { | ||
| if (content.Annotations is null) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| foreach (AIAnnotation annotation in content.Annotations) | ||
| { | ||
| // Container files from Code Interpreter have ContainerFileCitationMessageAnnotation as raw representation | ||
| if (annotation is CitationAnnotation citation | ||
| && citation.RawRepresentation is ContainerFileCitationMessageAnnotation containerCitation) | ||
| { | ||
| foundContainerFiles = true; | ||
|
|
||
| // Deduplicate by container+file ID in case the same file is cited multiple times | ||
| string key = $"{containerCitation.ContainerId}/{containerCitation.FileId}"; | ||
| if (!downloadedFiles.Add(key)) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| Console.WriteLine($"\nDownloading container file: {containerCitation.Filename}"); | ||
| Console.WriteLine($" Container ID: {containerCitation.ContainerId}"); | ||
| Console.WriteLine($" File ID: {containerCitation.FileId}"); | ||
|
|
||
| BinaryData fileData = await containerClient.DownloadContainerFileAsync( | ||
| containerCitation.ContainerId, | ||
| containerCitation.FileId); | ||
|
|
||
| // Sanitize filename to prevent path traversal | ||
| string safeFilename = Path.GetFileName(containerCitation.Filename); | ||
| string outputPath = Path.Combine(Directory.GetCurrentDirectory(), safeFilename); | ||
| await File.WriteAllBytesAsync(outputPath, fileData.ToArray()); | ||
| Console.WriteLine($" Saved to: {outputPath}"); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (!foundContainerFiles) | ||
| { | ||
| Console.WriteLine("\nNo container file citations found in the response."); | ||
| Console.WriteLine("The model may not have generated a downloadable file for this prompt."); | ||
| } | ||
56 changes: 56 additions & 0 deletions
56
.../02-agents/AgentsWithFoundry/Agent_Step24_CodeInterpreterFileDownload/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # Code Interpreter File Download (Microsoft Foundry) | ||
|
|
||
| This sample demonstrates how to download files generated by Code Interpreter when using Microsoft Foundry. | ||
|
|
||
| ## What this sample demonstrates | ||
|
|
||
| - Creating an agent with Code Interpreter tool using `AIProjectClient.AsAIAgent()` | ||
| - Generating files through Code Interpreter (e.g., CSV, Excel, images) | ||
| - Extracting container file citations from agent response annotations | ||
| - Downloading container files using the `ContainerClient` via `AIProjectClient.GetProjectOpenAIClient()` | ||
|
|
||
| ## Container files vs regular files | ||
|
|
||
| When Code Interpreter generates a file, the file is stored inside a **container** with a `cntr_` prefixed ID. The file itself gets a `cfile_` prefixed ID. | ||
|
|
||
| These container files **cannot** be downloaded using the standard Files API (`GetOpenAIFileClient`), which returns 404 for `cfile_` IDs. Instead, you must use the **Containers API** to download them. | ||
|
|
||
| ### Getting the ContainerClient with Foundry | ||
|
|
||
| `AzureOpenAIClient.GetContainerClient()` is not supported and throws `InvalidOperationException`. Instead, use the project's OpenAI client which inherits directly from `OpenAI.OpenAIClient`: | ||
|
|
||
| ```csharp | ||
| // ❌ AzureOpenAIClient does not support ContainerClient | ||
| var azureClient = new AzureOpenAIClient(endpoint, credential); | ||
| azureClient.GetContainerClient(); // Throws InvalidOperationException | ||
|
|
||
| // ✅ Use AIProjectClient's project OpenAI client | ||
| var containerClient = aiProjectClient.GetProjectOpenAIClient().GetContainerClient(); | ||
| await containerClient.DownloadContainerFileAsync("cntr_...", "cfile_..."); | ||
| ``` | ||
|
|
||
| The container ID and file ID are available from the `ContainerFileCitationMessageAnnotation` annotation in the response, accessible via `CitationAnnotation.RawRepresentation`. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - .NET 10 SDK or later | ||
| - Microsoft Foundry service endpoint and deployment configured | ||
| - Azure CLI installed and authenticated (`az login`) | ||
|
|
||
| Set the following environment variables: | ||
|
|
||
| ```powershell | ||
| $env:AZURE_AI_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project" | ||
| $env:AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-4o-mini" # Optional, defaults to gpt-4o-mini | ||
| ``` | ||
|
|
||
| ## Run the sample | ||
|
|
||
| ```powershell | ||
| dotnet run | ||
| ``` | ||
|
|
||
| ## See also | ||
|
|
||
| - [Code Interpreter File Download with OpenAI](../../../02-agents/AgentWithOpenAI/Agent_OpenAI_Step06_CodeInterpreterFileDownload/) — same scenario using Public OpenAI | ||
| - [Code Interpreter](../Agent_Step14_CodeInterpreter/) — Code Interpreter without file download |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion