Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions api/OpenAI.net8.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2449,6 +2449,10 @@ public class ContainerClient {
public virtual ClientResult<DeleteContainerFileResponse> DeleteContainerFile(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual Task<ClientResult> DeleteContainerFileAsync(string containerId, string fileId, RequestOptions options);
public virtual Task<ClientResult<DeleteContainerFileResponse>> DeleteContainerFileAsync(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual ClientResult DownloadContainerFile(string containerId, string fileId, RequestOptions options);
public virtual ClientResult<BinaryData> DownloadContainerFile(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual Task<ClientResult> DownloadContainerFileAsync(string containerId, string fileId, RequestOptions options);
public virtual Task<ClientResult<BinaryData>> DownloadContainerFileAsync(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual ClientResult GetContainer(string containerId, RequestOptions options);
public virtual ClientResult<ContainerResource> GetContainer(string containerId, CancellationToken cancellationToken = default);
public virtual Task<ClientResult> GetContainerAsync(string containerId, RequestOptions options);
Expand All @@ -2457,10 +2461,6 @@ public class ContainerClient {
public virtual ClientResult<ContainerFileResource> GetContainerFile(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual Task<ClientResult> GetContainerFileAsync(string containerId, string fileId, RequestOptions options);
public virtual Task<ClientResult<ContainerFileResource>> GetContainerFileAsync(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual ClientResult GetContainerFileContent(string containerId, string fileId, RequestOptions options);
public virtual ClientResult<BinaryData> GetContainerFileContent(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual Task<ClientResult> GetContainerFileContentAsync(string containerId, string fileId, RequestOptions options);
public virtual Task<ClientResult<BinaryData>> GetContainerFileContentAsync(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual CollectionResult<ContainerFileResource> GetContainerFiles(string containerId, ContainerFileCollectionOptions options = null, CancellationToken cancellationToken = default);
public virtual CollectionResult GetContainerFiles(string containerId, int? limit, string order, string after, RequestOptions options);
public virtual AsyncCollectionResult<ContainerFileResource> GetContainerFilesAsync(string containerId, ContainerFileCollectionOptions options = null, CancellationToken cancellationToken = default);
Expand Down Expand Up @@ -5040,6 +5040,19 @@ public class ComputerTool : ResponseTool, IJsonModel<ComputerTool>, IPersistable
public override readonly string ToString();
}
[Experimental("OPENAI001")]
public class ContainerFileCitationMessageAnnotation : ResponseMessageAnnotation, IJsonModel<ContainerFileCitationMessageAnnotation>, IPersistableModel<ContainerFileCitationMessageAnnotation> {
public ContainerFileCitationMessageAnnotation(string containerId, string fileId, int startIndex, int endIndex, string filename);
public string ContainerId { get; set; }
public int EndIndex { get; set; }
public string FileId { get; set; }
public string Filename { get; set; }
public int StartIndex { get; set; }
protected override ResponseMessageAnnotation JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options);
protected override void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options);
protected override ResponseMessageAnnotation PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options);
protected override BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options);
}
[Experimental("OPENAI001")]
public class CustomMcpToolCallApprovalPolicy : IJsonModel<CustomMcpToolCallApprovalPolicy>, IPersistableModel<CustomMcpToolCallApprovalPolicy> {
[EditorBrowsable(EditorBrowsableState.Never)]
[Experimental("SCME0001")]
Expand Down
20 changes: 16 additions & 4 deletions api/OpenAI.netstandard2.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2096,6 +2096,10 @@ public class ContainerClient {
public virtual ClientResult<DeleteContainerFileResponse> DeleteContainerFile(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual Task<ClientResult> DeleteContainerFileAsync(string containerId, string fileId, RequestOptions options);
public virtual Task<ClientResult<DeleteContainerFileResponse>> DeleteContainerFileAsync(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual ClientResult DownloadContainerFile(string containerId, string fileId, RequestOptions options);
public virtual ClientResult<BinaryData> DownloadContainerFile(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual Task<ClientResult> DownloadContainerFileAsync(string containerId, string fileId, RequestOptions options);
public virtual Task<ClientResult<BinaryData>> DownloadContainerFileAsync(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual ClientResult GetContainer(string containerId, RequestOptions options);
public virtual ClientResult<ContainerResource> GetContainer(string containerId, CancellationToken cancellationToken = default);
public virtual Task<ClientResult> GetContainerAsync(string containerId, RequestOptions options);
Expand All @@ -2104,10 +2108,6 @@ public class ContainerClient {
public virtual ClientResult<ContainerFileResource> GetContainerFile(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual Task<ClientResult> GetContainerFileAsync(string containerId, string fileId, RequestOptions options);
public virtual Task<ClientResult<ContainerFileResource>> GetContainerFileAsync(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual ClientResult GetContainerFileContent(string containerId, string fileId, RequestOptions options);
public virtual ClientResult<BinaryData> GetContainerFileContent(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual Task<ClientResult> GetContainerFileContentAsync(string containerId, string fileId, RequestOptions options);
public virtual Task<ClientResult<BinaryData>> GetContainerFileContentAsync(string containerId, string fileId, CancellationToken cancellationToken = default);
public virtual CollectionResult<ContainerFileResource> GetContainerFiles(string containerId, ContainerFileCollectionOptions options = null, CancellationToken cancellationToken = default);
public virtual CollectionResult GetContainerFiles(string containerId, int? limit, string order, string after, RequestOptions options);
public virtual AsyncCollectionResult<ContainerFileResource> GetContainerFilesAsync(string containerId, ContainerFileCollectionOptions options = null, CancellationToken cancellationToken = default);
Expand Down Expand Up @@ -4403,6 +4403,18 @@ public class ComputerTool : ResponseTool, IJsonModel<ComputerTool>, IPersistable
public static bool operator !=(ComputerToolEnvironment left, ComputerToolEnvironment right);
public override readonly string ToString();
}
public class ContainerFileCitationMessageAnnotation : ResponseMessageAnnotation, IJsonModel<ContainerFileCitationMessageAnnotation>, IPersistableModel<ContainerFileCitationMessageAnnotation> {
public ContainerFileCitationMessageAnnotation(string containerId, string fileId, int startIndex, int endIndex, string filename);
public string ContainerId { get; set; }
public int EndIndex { get; set; }
public string FileId { get; set; }
public string Filename { get; set; }
public int StartIndex { get; set; }
protected override ResponseMessageAnnotation JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options);
protected override void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options);
protected override ResponseMessageAnnotation PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options);
protected override BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options);
}
public class CustomMcpToolCallApprovalPolicy : IJsonModel<CustomMcpToolCallApprovalPolicy>, IPersistableModel<CustomMcpToolCallApprovalPolicy> {
[EditorBrowsable(EditorBrowsableState.Never)]
public ref JsonPatch Patch { get; }
Expand Down
56 changes: 56 additions & 0 deletions examples/Responses/Example10_CodeInterpreter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using NUnit.Framework;
using OpenAI.Containers;
using OpenAI.Responses;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace OpenAI.Examples;

// This example uses experimental APIs which are subject to change. To use experimental APIs,
// please acknowledge their experimental status by suppressing the corresponding warning.
#pragma warning disable OPENAI001

public partial class ResponseExamples
{
[Test]
public void Example10_CodeInterpreter()
{
OpenAIResponseClient client = new(model: "gpt-5", apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY"));

CodeInterpreterToolContainer container = new(CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration());
CodeInterpreterTool codeInterpreterTool = new(container);

ResponseCreationOptions options = new()
{
Tools = { codeInterpreterTool }
};

List<ResponseItem> inputItems =
[
ResponseItem.CreateUserMessageItem("Create a Excel spreadsheet that contains the mathematical times tables from 1-12."),
];

OpenAIResponse response = client.CreateResponse(inputItems, options);

MessageResponseItem message = response.OutputItems
.OfType<MessageResponseItem>()
.FirstOrDefault();

ResponseContentPart contentPart = message.Content
.Where(part => part.Kind == ResponseContentPartKind.OutputText)
.FirstOrDefault();

ContainerFileCitationMessageAnnotation containerFileCitation = contentPart.OutputTextAnnotations
.OfType<ContainerFileCitationMessageAnnotation>()
.FirstOrDefault();

ContainerClient containerClient = new(apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
BinaryData fileBytes = containerClient.DownloadContainerFile(containerFileCitation.ContainerId, containerFileCitation.FileId);
using FileStream stream = File.OpenWrite($"{Guid.NewGuid()}.xlsx");
fileBytes.ToStream().CopyTo(stream);
}
}

#pragma warning restore OPENAI001
57 changes: 57 additions & 0 deletions examples/Responses/Example10_CodeInterpreterAsync.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using NUnit.Framework;
using OpenAI.Containers;
using OpenAI.Responses;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace OpenAI.Examples;

// This example uses experimental APIs which are subject to change. To use experimental APIs,
// please acknowledge their experimental status by suppressing the corresponding warning.
#pragma warning disable OPENAI001

public partial class ResponseExamples
{
[Test]
public async Task Example10_CodeInterpreterAsync()
{
OpenAIResponseClient client = new(model: "gpt-5", apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY"));

CodeInterpreterToolContainer container = new(CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration());
CodeInterpreterTool codeInterpreterTool = new(container);

ResponseCreationOptions options = new()
{
Tools = { codeInterpreterTool }
};

List<ResponseItem> inputItems =
[
ResponseItem.CreateUserMessageItem("Create a Excel spreadsheet that contains the mathematical times tables from 1-12."),
];

OpenAIResponse response = await client.CreateResponseAsync(inputItems, options);

MessageResponseItem message = response.OutputItems
.OfType<MessageResponseItem>()
.FirstOrDefault();

ResponseContentPart contentPart = message.Content
.Where(part => part.Kind == ResponseContentPartKind.OutputText)
.FirstOrDefault();

ContainerFileCitationMessageAnnotation containerFileCitation = contentPart.OutputTextAnnotations
.OfType<ContainerFileCitationMessageAnnotation>()
.FirstOrDefault();

ContainerClient containerClient = new(apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
BinaryData fileBytes = await containerClient.DownloadContainerFileAsync(containerFileCitation.ContainerId, containerFileCitation.FileId);
using FileStream stream = File.OpenWrite($"{Guid.NewGuid()}.xlsx");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does the response provide any information about the expected file extension of the file, or would the caller always need to know this somehow?

Copy link
Collaborator Author

@joseharriaga joseharriaga Oct 30, 2025

Choose a reason for hiding this comment

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

The extension is visible in the Filename of the ContainerFileCitationMessageAnnotation. I have modified the sample to use that instead.

Copy link
Collaborator

Choose a reason for hiding this comment

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

much better!

fileBytes.ToStream().CopyTo(stream);
}
}

#pragma warning restore OPENAI001
7 changes: 5 additions & 2 deletions specification/base/typespec/responses/models.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -1089,11 +1089,11 @@ model AnnotationUrlCitation extends Annotation {
}

/** A citation for a container file used to generate a model response. */
model ContainerFileCitationBody {
model ContainerFileCitationBody extends Annotation {
@doc("""
The type of the container file citation. Always `container_file_citation`.
""")
type: "container_file_citation" = "container_file_citation";
type: AnnotationType.container_file_citation;

/** The ID of the container file. */
container_id: string;
Expand All @@ -1106,6 +1106,9 @@ model ContainerFileCitationBody {

/** The index of the last character of the container file citation in the message. */
end_index: int32;

/** The filename of the container file cited. */
filename: string;
}

// Tool customization (apply_discriminator): Apply discriminated base type, rename for consistency and clarity
Expand Down
2 changes: 1 addition & 1 deletion specification/client/containers.client.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ using Azure.ClientGenerator.Core;

@@clientName(Containers.retrieveContainer, "GetContainer");
@@clientName(Containers.retrieveContainerFile, "GetContainerFile");
@@clientName(Containers.retrieveContainerFileContent, "GetContainerFileContent");
@@clientName(Containers.retrieveContainerFileContent, "DownloadContainerFile");
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace OpenAI.Responses;

// CUSTOM: Renamed.
[CodeGenType("ContainerFileCitationBody")]
public partial class ContainerFileCitationMessageAnnotation
{
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
namespace OpenAI.Responses;

// CUSTOM:
// - Renamed.
// CUSTOM: Renamed.
[CodeGenType("AnnotationFileCitation")]
public partial class FileCitationMessageAnnotation
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
namespace OpenAI.Responses;

// CUSTOM:
// - Renamed.
// CUSTOM: Renamed.
[CodeGenType("AnnotationFilePath")]
public partial class FilePathMessageAnnotation
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ namespace OpenAI.Responses;
[CodeGenType("AnnotationType")]
public enum ResponseMessageAnnotationKind
{
[CodeGenMember("FileCitation")]
FileCitation,

[CodeGenMember("UrlCitation")]
UriCitation,

[CodeGenMember("FilePath")]
FilePath,

[CodeGenMember("ContainerFileCitation")]
ContainerFileCitation
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

namespace OpenAI.Responses;

// CUSTOM:
// - Renamed.
// CUSTOM: Renamed.
[CodeGenType("AnnotationUrlCitation")]
public partial class UriCitationMessageAnnotation
{
// CUSTOM: Renamed.
[CodeGenMember("Url")]
public Uri Uri { get; set; }
}
2 changes: 1 addition & 1 deletion src/Generated/ContainerClient.RestClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ internal virtual PipelineMessage CreateDeleteContainerFileRequest(string contain
return message;
}

internal virtual PipelineMessage CreateGetContainerFileContentRequest(string containerId, string fileId, RequestOptions options)
internal virtual PipelineMessage CreateDownloadContainerFileRequest(string containerId, string fileId, RequestOptions options)
{
ClientUriBuilder uri = new ClientUriBuilder();
uri.Reset(_endpoint);
Expand Down
16 changes: 8 additions & 8 deletions src/Generated/ContainerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,39 +281,39 @@ public virtual async Task<ClientResult<DeleteContainerFileResponse>> DeleteConta
return ClientResult.FromValue((DeleteContainerFileResponse)result, result.GetRawResponse());
}

public virtual ClientResult GetContainerFileContent(string containerId, string fileId, RequestOptions options)
public virtual ClientResult DownloadContainerFile(string containerId, string fileId, RequestOptions options)
{
Argument.AssertNotNullOrEmpty(containerId, nameof(containerId));
Argument.AssertNotNullOrEmpty(fileId, nameof(fileId));

using PipelineMessage message = CreateGetContainerFileContentRequest(containerId, fileId, options);
using PipelineMessage message = CreateDownloadContainerFileRequest(containerId, fileId, options);
return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options));
}

public virtual async Task<ClientResult> GetContainerFileContentAsync(string containerId, string fileId, RequestOptions options)
public virtual async Task<ClientResult> DownloadContainerFileAsync(string containerId, string fileId, RequestOptions options)
{
Argument.AssertNotNullOrEmpty(containerId, nameof(containerId));
Argument.AssertNotNullOrEmpty(fileId, nameof(fileId));

using PipelineMessage message = CreateGetContainerFileContentRequest(containerId, fileId, options);
using PipelineMessage message = CreateDownloadContainerFileRequest(containerId, fileId, options);
return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false));
}

public virtual ClientResult<BinaryData> GetContainerFileContent(string containerId, string fileId, CancellationToken cancellationToken = default)
public virtual ClientResult<BinaryData> DownloadContainerFile(string containerId, string fileId, CancellationToken cancellationToken = default)
{
Argument.AssertNotNullOrEmpty(containerId, nameof(containerId));
Argument.AssertNotNullOrEmpty(fileId, nameof(fileId));

ClientResult result = GetContainerFileContent(containerId, fileId, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null);
ClientResult result = DownloadContainerFile(containerId, fileId, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null);
return ClientResult.FromValue(result.GetRawResponse().Content, result.GetRawResponse());
}

public virtual async Task<ClientResult<BinaryData>> GetContainerFileContentAsync(string containerId, string fileId, CancellationToken cancellationToken = default)
public virtual async Task<ClientResult<BinaryData>> DownloadContainerFileAsync(string containerId, string fileId, CancellationToken cancellationToken = default)
{
Argument.AssertNotNullOrEmpty(containerId, nameof(containerId));
Argument.AssertNotNullOrEmpty(fileId, nameof(fileId));

ClientResult result = await GetContainerFileContentAsync(containerId, fileId, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null).ConfigureAwait(false);
ClientResult result = await DownloadContainerFileAsync(containerId, fileId, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null).ConfigureAwait(false);
return ClientResult.FromValue(result.GetRawResponse().Content, result.GetRawResponse());
}
}
Expand Down
Loading
Loading