diff --git a/eng/packages/General.props b/eng/packages/General.props
index a8de843a353..7565d36bac0 100644
--- a/eng/packages/General.props
+++ b/eng/packages/General.props
@@ -20,7 +20,7 @@
-
+
diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/CHANGELOG.md b/src/Libraries/Microsoft.Extensions.AI.OpenAI/CHANGELOG.md
index 6e087263cca..43238de166c 100644
--- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/CHANGELOG.md
+++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/CHANGELOG.md
@@ -2,6 +2,8 @@
## 10.1.1-preview.1.? (NOT YET RELEASED)
+- Updated to depend on OpenAI 2.8.0.
+- Updated public API signatures in `OpenAIClientExtensions` and `MicrosoftExtensionsAIResponsesExtensions` to match the corresponding breaking changes in OpenAI's Responses APIs.
- Updated to accommodate the additions in `Microsoft.Extensions.AI.Abstractions`.
- Updated the OpenAI Responses and Chat Completion `IChatClient`s to populate `UsageDetails`'s `InputCachedTokenCount` and `ReasoningTokenCount`.
- Updated handling of `HostedWebSearchTool`, `HostedFileSearchTool`, and `HostedImageGenerationTool` to pull OpenAI-specific
diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/MicrosoftExtensionsAIResponsesExtensions.cs b/src/Libraries/Microsoft.Extensions.AI.OpenAI/MicrosoftExtensionsAIResponsesExtensions.cs
index 6d989c0b56d..9c2ed0348fb 100644
--- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/MicrosoftExtensionsAIResponsesExtensions.cs
+++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/MicrosoftExtensionsAIResponsesExtensions.cs
@@ -56,12 +56,12 @@ public static IEnumerable AsOpenAIResponseItems(this IEnumerable AsChatMessages(this IEnumerable items) =>
OpenAIResponsesChatClient.ToChatMessages(Throw.IfNull(items));
- /// Creates a Microsoft.Extensions.AI from an .
- /// The to convert to a .
+ /// Creates a Microsoft.Extensions.AI from an .
+ /// The to convert to a .
/// The options employed in the creation of the response.
/// A converted .
/// is .
- public static ChatResponse AsChatResponse(this OpenAIResponse response, ResponseCreationOptions? options = null) =>
+ public static ChatResponse AsChatResponse(this ResponseResult response, CreateResponseOptions? options = null) =>
OpenAIResponsesChatClient.FromOpenAIResponse(Throw.IfNull(response), options, conversationId: null);
///
@@ -74,35 +74,43 @@ public static ChatResponse AsChatResponse(this OpenAIResponse response, Response
/// A sequence of converted instances.
/// is .
public static IAsyncEnumerable AsChatResponseUpdatesAsync(
- this IAsyncEnumerable responseUpdates, ResponseCreationOptions? options = null, CancellationToken cancellationToken = default) =>
+ this IAsyncEnumerable responseUpdates, CreateResponseOptions? options = null, CancellationToken cancellationToken = default) =>
OpenAIResponsesChatClient.FromOpenAIStreamingResponseUpdatesAsync(Throw.IfNull(responseUpdates), options, conversationId: null, cancellationToken: cancellationToken);
- /// Creates an OpenAI from a .
+ /// Creates an OpenAI from a .
/// The response to convert.
/// The options employed in the creation of the response.
- /// The created .
- public static OpenAIResponse AsOpenAIResponse(this ChatResponse response, ChatOptions? options = null)
+ /// The created .
+ public static ResponseResult AsOpenAIResponseResult(this ChatResponse response, ChatOptions? options = null)
{
_ = Throw.IfNull(response);
- if (response.RawRepresentation is OpenAIResponse openAIResponse)
+ if (response.RawRepresentation is ResponseResult openAIResponse)
{
return openAIResponse;
}
- return OpenAIResponsesModelFactory.OpenAIResponse(
- response.ResponseId,
- response.CreatedAt ?? default,
- ResponseStatus.Completed,
- usage: null, // No way to construct a ResponseTokenUsage right now from external to the OpenAI library
- maxOutputTokenCount: options?.MaxOutputTokens,
- outputItems: OpenAIResponsesChatClient.ToOpenAIResponseItems(response.Messages, options),
- parallelToolCallsEnabled: options?.AllowMultipleToolCalls ?? false,
- model: response.ModelId ?? options?.ModelId,
- temperature: options?.Temperature,
- topP: options?.TopP,
- previousResponseId: options?.ConversationId,
- instructions: options?.Instructions);
+ ResponseResult result = new()
+ {
+ ConversationOptions = OpenAIClientExtensions.IsConversationId(response.ConversationId) ? new(response.ConversationId) : null,
+ CreatedAt = response.CreatedAt ?? default,
+ Id = response.ResponseId,
+ Instructions = options?.Instructions,
+ MaxOutputTokenCount = options?.MaxOutputTokens,
+ Model = response.ModelId ?? options?.ModelId,
+ ParallelToolCallsEnabled = options?.AllowMultipleToolCalls ?? true,
+ Status = ResponseStatus.Completed,
+ Temperature = options?.Temperature,
+ TopP = options?.TopP,
+ Usage = OpenAIResponsesChatClient.ToResponseTokenUsage(response.Usage),
+ };
+
+ foreach (var responseItem in OpenAIResponsesChatClient.ToOpenAIResponseItems(response.Messages, options))
+ {
+ result.OutputItems.Add(responseItem);
+ }
+
+ return result;
}
/// Adds the to the list of s.
@@ -111,7 +119,7 @@ public static OpenAIResponse AsOpenAIResponse(this ChatResponse response, ChatOp
///
/// does not derive from , so it cannot be added directly to a list of s.
/// Instead, this method wraps the provided in an and adds that to the list.
- /// The returned by will
+ /// The returned by will
/// be able to unwrap the when it processes the list of tools and use the provided as-is.
///
public static void Add(this IList tools, ResponseTool tool)
@@ -127,7 +135,7 @@ public static void Add(this IList tools, ResponseTool tool)
///
///
/// The returned tool is only suitable for use with the returned by
- /// (or s that delegate
+ /// (or s that delegate
/// to such an instance). It is likely to be ignored by any other implementation.
///
///
@@ -136,7 +144,7 @@ public static void Add(this IList tools, ResponseTool tool)
/// , those types should be preferred instead of this method, as they are more portable,
/// capable of being respected by any implementation. This method does not attempt to
/// map the supplied to any of those types, it simply wraps it as-is:
- /// the returned by will
+ /// the returned by will
/// be able to unwrap the when it processes the list of tools.
///
///
diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIClientExtensions.cs b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIClientExtensions.cs
index f696e394b44..36d8677e70a 100644
--- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIClientExtensions.cs
+++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIClientExtensions.cs
@@ -25,7 +25,7 @@ namespace Microsoft.Extensions.AI;
public static class OpenAIClientExtensions
{
/// Key into AdditionalProperties used to store a strict option.
- private const string StrictKey = "strictJsonSchema";
+ private const string StrictKey = "strict";
/// Gets the default OpenAI endpoint.
internal static Uri DefaultOpenAIEndpoint { get; } = new("https://api.openai.com/v1");
@@ -111,11 +111,11 @@ static void AppendLine(ref StringBuilder? sb, string propName, JsonNode propNode
public static IChatClient AsIChatClient(this ChatClient chatClient) =>
new OpenAIChatClient(chatClient);
- /// Gets an for use with this .
+ /// Gets an for use with this .
/// The client.
- /// An that can be used to converse via the .
+ /// An that can be used to converse via the .
/// is .
- public static IChatClient AsIChatClient(this OpenAIResponseClient responseClient) =>
+ public static IChatClient AsIChatClient(this ResponsesClient responseClient) =>
new OpenAIResponsesChatClient(responseClient);
/// Gets an for use with this .
@@ -246,6 +246,14 @@ internal static void PatchModelIfNotSet(ref JsonPatch patch, string? modelId)
internal static T? GetProperty(this AITool tool, string name) =>
tool.AdditionalProperties?.TryGetValue(name, out object? value) is true && value is T tValue ? tValue : default;
+ /// Gets whether an ID is an OpenAI conversation ID.
+ ///
+ /// Technically, OpenAI's IDs are opaque. However, by convention conversation IDs start with "conv_" and
+ /// we can use that to disambiguate whether we're looking at a conversation ID or something else, like a response ID.
+ ///
+ internal static bool IsConversationId(string? id) =>
+ id?.StartsWith("conv_", StringComparison.OrdinalIgnoreCase) is true;
+
/// Used to create the JSON payload for an OpenAI tool description.
internal sealed class ToolJson
{
diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs
index 98c30b73526..e6359cbdd7a 100644
--- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs
+++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs
@@ -5,6 +5,7 @@
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
@@ -23,53 +24,38 @@
namespace Microsoft.Extensions.AI;
-/// Represents an for an .
+/// Represents an for an .
internal sealed class OpenAIResponsesChatClient : IChatClient
{
// These delegate instances are used to call the internal overloads of CreateResponseAsync and CreateResponseStreamingAsync that accept
// a RequestOptions. These should be replaced once a better way to pass RequestOptions is available.
- private static readonly Func, ResponseCreationOptions, RequestOptions, Task>>?
- _createResponseAsync =
- (Func, ResponseCreationOptions, RequestOptions, Task>>?)
- typeof(OpenAIResponseClient).GetMethod(
- nameof(OpenAIResponseClient.CreateResponseAsync), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
- null, [typeof(IEnumerable), typeof(ResponseCreationOptions), typeof(RequestOptions)], null)
- ?.CreateDelegate(typeof(Func, ResponseCreationOptions, RequestOptions, Task>>));
-
- private static readonly Func, ResponseCreationOptions, RequestOptions, AsyncCollectionResult>?
+
+ private static readonly Func>?
_createResponseStreamingAsync =
- (Func, ResponseCreationOptions, RequestOptions, AsyncCollectionResult>?)
- typeof(OpenAIResponseClient).GetMethod(
- nameof(OpenAIResponseClient.CreateResponseStreamingAsync), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
- null, [typeof(IEnumerable), typeof(ResponseCreationOptions), typeof(RequestOptions)], null)
- ?.CreateDelegate(typeof(Func, ResponseCreationOptions, RequestOptions, AsyncCollectionResult>));
-
- private static readonly Func>>?
- _getResponseAsync =
- (Func>>?)
- typeof(OpenAIResponseClient).GetMethod(
- nameof(OpenAIResponseClient.GetResponseAsync), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
- null, [typeof(string), typeof(RequestOptions)], null)
- ?.CreateDelegate(typeof(Func>>));
-
- private static readonly Func>?
+ (Func>?)
+ typeof(ResponsesClient).GetMethod(
+ nameof(ResponsesClient.CreateResponseStreamingAsync), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
+ null, [typeof(CreateResponseOptions), typeof(RequestOptions)], null)
+ ?.CreateDelegate(typeof(Func>));
+
+ private static readonly Func>?
_getResponseStreamingAsync =
- (Func>?)
- typeof(OpenAIResponseClient).GetMethod(
- nameof(OpenAIResponseClient.GetResponseStreamingAsync), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
- null, [typeof(string), typeof(RequestOptions), typeof(int?)], null)
- ?.CreateDelegate(typeof(Func>));
+ (Func>?)
+ typeof(ResponsesClient).GetMethod(
+ nameof(ResponsesClient.GetResponseStreamingAsync), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
+ null, [typeof(GetResponseOptions), typeof(RequestOptions)], null)
+ ?.CreateDelegate(typeof(Func>));
/// Metadata about the client.
private readonly ChatClientMetadata _metadata;
- /// The underlying .
- private readonly OpenAIResponseClient _responseClient;
+ /// The underlying .
+ private readonly ResponsesClient _responseClient;
- /// Initializes a new instance of the class for the specified .
+ /// Initializes a new instance of the class for the specified .
/// The underlying client.
/// is .
- public OpenAIResponsesChatClient(OpenAIResponseClient responseClient)
+ public OpenAIResponsesChatClient(ResponsesClient responseClient)
{
_ = Throw.IfNull(responseClient);
@@ -86,7 +72,7 @@ public OpenAIResponsesChatClient(OpenAIResponseClient responseClient)
return
serviceKey is not null ? null :
serviceType == typeof(ChatClientMetadata) ? _metadata :
- serviceType == typeof(OpenAIResponseClient) ? _responseClient :
+ serviceType == typeof(ResponsesClient) ? _responseClient :
serviceType.IsInstanceOfType(this) ? this :
null;
}
@@ -97,76 +83,79 @@ public async Task GetResponseAsync(
{
_ = Throw.IfNull(messages);
- // Convert the inputs into what OpenAIResponseClient expects.
- var openAIOptions = ToOpenAIResponseCreationOptions(options, out string? openAIConversationId);
+ // Convert the inputs into what ResponsesClient expects.
+ var openAIOptions = AsCreateResponseOptions(options, out string? openAIConversationId);
// Provided continuation token signals that an existing background response should be fetched.
if (GetContinuationToken(messages, options) is { } token)
{
- var getTask = _getResponseAsync is not null ?
- _getResponseAsync(_responseClient, token.ResponseId, cancellationToken.ToRequestOptions(streaming: false)) :
- _responseClient.GetResponseAsync(token.ResponseId, cancellationToken);
- var response = (await getTask.ConfigureAwait(false)).Value;
-
+ var getTask = _responseClient.GetResponseAsync(token.ResponseId, include: null, stream: null, startingAfter: null, includeObfuscation: null, cancellationToken.ToRequestOptions(streaming: false));
+ var response = (ResponseResult)await getTask.ConfigureAwait(false);
return FromOpenAIResponse(response, openAIOptions, openAIConversationId);
}
- var openAIResponseItems = ToOpenAIResponseItems(messages, options);
+ foreach (var responseItem in ToOpenAIResponseItems(messages, options))
+ {
+ openAIOptions.InputItems.Add(responseItem);
+ }
- // Make the call to the OpenAIResponseClient.
- var createTask = _createResponseAsync is not null ?
- _createResponseAsync(_responseClient, openAIResponseItems, openAIOptions, cancellationToken.ToRequestOptions(streaming: false)) :
- _responseClient.CreateResponseAsync(openAIResponseItems, openAIOptions, cancellationToken);
- var openAIResponse = (await createTask.ConfigureAwait(false)).Value;
+ // Make the call to the ResponsesClient.
+ var createTask = _responseClient.CreateResponseAsync((BinaryContent)openAIOptions, cancellationToken.ToRequestOptions(streaming: false));
+ var openAIResponsesResult = (ResponseResult)await createTask.ConfigureAwait(false);
// Convert the response to a ChatResponse.
- return FromOpenAIResponse(openAIResponse, openAIOptions, openAIConversationId);
+ return FromOpenAIResponse(openAIResponsesResult, openAIOptions, openAIConversationId);
}
- internal static ChatResponse FromOpenAIResponse(OpenAIResponse openAIResponse, ResponseCreationOptions? openAIOptions, string? conversationId)
+ internal static ChatResponse FromOpenAIResponse(ResponseResult responseResult, CreateResponseOptions? openAIOptions, string? conversationId)
{
// Convert and return the results.
ChatResponse response = new()
{
- ConversationId = openAIOptions?.StoredOutputEnabled is false ? null : (conversationId ?? openAIResponse.Id),
- CreatedAt = openAIResponse.CreatedAt,
- ContinuationToken = CreateContinuationToken(openAIResponse),
- FinishReason = ToFinishReason(openAIResponse.IncompleteStatusDetails?.Reason),
- ModelId = openAIResponse.Model,
- RawRepresentation = openAIResponse,
- ResponseId = openAIResponse.Id,
- Usage = ToUsageDetails(openAIResponse),
+ ConversationId = openAIOptions?.StoredOutputEnabled is false ? null : (conversationId ?? responseResult.Id),
+ CreatedAt = responseResult.CreatedAt,
+ ContinuationToken = CreateContinuationToken(responseResult),
+ FinishReason = AsFinishReason(responseResult.IncompleteStatusDetails?.Reason),
+ ModelId = responseResult.Model,
+ RawRepresentation = responseResult,
+ ResponseId = responseResult.Id,
+ Usage = ToUsageDetails(responseResult),
};
- if (!string.IsNullOrEmpty(openAIResponse.EndUserId))
+ if (!string.IsNullOrEmpty(responseResult.EndUserId))
{
- (response.AdditionalProperties ??= [])[nameof(openAIResponse.EndUserId)] = openAIResponse.EndUserId;
+ (response.AdditionalProperties ??= [])[nameof(responseResult.EndUserId)] = responseResult.EndUserId;
}
- if (openAIResponse.Error is not null)
+ if (responseResult.Error is not null)
{
- (response.AdditionalProperties ??= [])[nameof(openAIResponse.Error)] = openAIResponse.Error;
+ (response.AdditionalProperties ??= [])[nameof(responseResult.Error)] = responseResult.Error;
}
- if (openAIResponse.OutputItems is not null)
+ if (responseResult.OutputItems is not null)
{
- response.Messages = [.. ToChatMessages(openAIResponse.OutputItems, openAIOptions)];
+ response.Messages = [.. ToChatMessages(responseResult.OutputItems, openAIOptions)];
- if (response.Messages.LastOrDefault() is { } lastMessage && openAIResponse.Error is { } error)
+ if (response.Messages.LastOrDefault() is { } lastMessage && responseResult.Error is { } error)
{
lastMessage.Contents.Add(new ErrorContent(error.Message) { ErrorCode = error.Code.ToString() });
}
foreach (var message in response.Messages)
{
- message.CreatedAt ??= openAIResponse.CreatedAt;
+ message.CreatedAt ??= responseResult.CreatedAt;
}
}
+ if (responseResult.SafetyIdentifier is not null)
+ {
+ (response.AdditionalProperties ??= [])[nameof(responseResult.SafetyIdentifier)] = responseResult.SafetyIdentifier;
+ }
+
return response;
}
- internal static IEnumerable ToChatMessages(IEnumerable items, ResponseCreationOptions? options = null)
+ internal static IEnumerable ToChatMessages(IEnumerable items, CreateResponseOptions? options = null)
{
ChatMessage? message = null;
@@ -185,7 +174,7 @@ internal static IEnumerable ToChatMessages(IEnumerable)message.Contents).AddRange(ToAIContents(messageItem.Content));
break;
@@ -252,30 +241,38 @@ public IAsyncEnumerable GetStreamingResponseAsync(
{
_ = Throw.IfNull(messages);
- var openAIOptions = ToOpenAIResponseCreationOptions(options, out string? openAIConversationId);
+ var openAIOptions = AsCreateResponseOptions(options, out string? openAIConversationId);
+ openAIOptions.StreamingEnabled = true;
// Provided continuation token signals that an existing background response should be fetched.
if (GetContinuationToken(messages, options) is { } token)
{
+ GetResponseOptions getOptions = new(token.ResponseId) { StartingAfter = token.SequenceNumber, StreamingEnabled = true };
+
+ Debug.Assert(_getResponseStreamingAsync is not null, $"Unable to find {nameof(_getResponseStreamingAsync)} method");
IAsyncEnumerable getUpdates = _getResponseStreamingAsync is not null ?
- _getResponseStreamingAsync(_responseClient, token.ResponseId, cancellationToken.ToRequestOptions(streaming: true), token.SequenceNumber) :
- _responseClient.GetResponseStreamingAsync(token.ResponseId, token.SequenceNumber, cancellationToken);
+ _getResponseStreamingAsync(_responseClient, getOptions, cancellationToken.ToRequestOptions(streaming: true)) :
+ _responseClient.GetResponseStreamingAsync(getOptions, cancellationToken);
return FromOpenAIStreamingResponseUpdatesAsync(getUpdates, openAIOptions, openAIConversationId, token.ResponseId, cancellationToken);
}
- var openAIResponseItems = ToOpenAIResponseItems(messages, options);
+ foreach (var responseItem in ToOpenAIResponseItems(messages, options))
+ {
+ openAIOptions.InputItems.Add(responseItem);
+ }
- var createUpdates = _createResponseStreamingAsync is not null ?
- _createResponseStreamingAsync(_responseClient, openAIResponseItems, openAIOptions, cancellationToken.ToRequestOptions(streaming: true)) :
- _responseClient.CreateResponseStreamingAsync(openAIResponseItems, openAIOptions, cancellationToken);
+ Debug.Assert(_createResponseStreamingAsync is not null, $"Unable to find {nameof(_createResponseStreamingAsync)} method");
+ AsyncCollectionResult createUpdates = _createResponseStreamingAsync is not null ?
+ _createResponseStreamingAsync(_responseClient, openAIOptions, cancellationToken.ToRequestOptions(streaming: true)) :
+ _responseClient.CreateResponseStreamingAsync(openAIOptions, cancellationToken);
return FromOpenAIStreamingResponseUpdatesAsync(createUpdates, openAIOptions, openAIConversationId, cancellationToken: cancellationToken);
}
internal static async IAsyncEnumerable FromOpenAIStreamingResponseUpdatesAsync(
IAsyncEnumerable streamingResponseUpdates,
- ResponseCreationOptions? options,
+ CreateResponseOptions? options,
string? conversationId,
string? resumeResponseId = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
@@ -360,7 +357,7 @@ ChatResponseUpdate CreateUpdate(AIContent? content = null) =>
latestResponseStatus = completedUpdate.Response?.Status;
var update = CreateUpdate(ToUsageDetails(completedUpdate.Response) is { } usage ? new UsageContent(usage) : null);
update.FinishReason =
- ToFinishReason(completedUpdate.Response?.IncompleteStatusDetails?.Reason) ??
+ AsFinishReason(completedUpdate.Response?.IncompleteStatusDetails?.Reason) ??
(anyFunctions ? ChatFinishReason.ToolCalls :
ChatFinishReason.Stop);
yield return update;
@@ -372,7 +369,7 @@ ChatResponseUpdate CreateUpdate(AIContent? content = null) =>
{
case MessageResponseItem mri:
lastMessageId = outputItemAddedUpdate.Item.Id;
- lastRole = ToChatRole(mri.Role);
+ lastRole = AsChatRole(mri.Role);
break;
case FunctionCallResponseItem fcri:
@@ -530,7 +527,7 @@ void UpdateConversationId(string? id)
///
void IDisposable.Dispose()
{
- // Nothing to dispose. Implementation required for the IChatClient interface.
+ // Nothing to dispose.
}
internal static ResponseTool? ToResponseTool(AITool tool, ChatOptions? options = null)
@@ -544,39 +541,60 @@ void IDisposable.Dispose()
return ToResponseTool(aiFunction, options);
case HostedWebSearchTool webSearchTool:
- return ResponseTool.CreateWebSearchTool(
- webSearchTool.GetProperty(nameof(WebSearchTool.UserLocation)),
- webSearchTool.GetProperty(nameof(WebSearchTool.SearchContextSize)),
- webSearchTool.GetProperty(nameof(WebSearchTool.Filters)));
+ return new WebSearchTool
+ {
+ Filters = webSearchTool.GetProperty(nameof(WebSearchTool.Filters)),
+ SearchContextSize = webSearchTool.GetProperty(nameof(WebSearchTool.SearchContextSize)),
+ UserLocation = webSearchTool.GetProperty(nameof(WebSearchTool.UserLocation)),
+ };
case HostedFileSearchTool fileSearchTool:
- return ResponseTool.CreateFileSearchTool(
- fileSearchTool.Inputs?.OfType().Select(c => c.VectorStoreId) ?? [],
- fileSearchTool.MaximumResultCount,
- fileSearchTool.GetProperty(nameof(FileSearchTool.RankingOptions)),
- fileSearchTool.GetProperty(nameof(FileSearchTool.Filters)));
-
- case HostedImageGenerationTool imageGenerationTool:
- return ToImageResponseTool(imageGenerationTool);
+ return new FileSearchTool(fileSearchTool.Inputs?.OfType().Select(c => c.VectorStoreId) ?? [])
+ {
+ Filters = fileSearchTool.GetProperty(nameof(FileSearchTool.Filters)),
+ MaxResultCount = fileSearchTool.MaximumResultCount,
+ RankingOptions = fileSearchTool.GetProperty(nameof(FileSearchTool.RankingOptions)),
+ };
case HostedCodeInterpreterTool codeTool:
- return ResponseTool.CreateCodeInterpreterTool(
- new CodeInterpreterToolContainer(codeTool.Inputs?.OfType().Select(f => f.FileId).ToList() is { Count: > 0 } ids ?
+ return new CodeInterpreterTool(
+ new(codeTool.Inputs?.OfType().Select(f => f.FileId).ToList() is { Count: > 0 } ids ?
CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration(ids) :
new()));
+ case HostedImageGenerationTool imageGenerationTool:
+ ImageGenerationOptions? igo = imageGenerationTool.Options;
+ return new ImageGenerationTool
+ {
+ Background = imageGenerationTool.GetProperty(nameof(ImageGenerationTool.Background)),
+ InputFidelity = imageGenerationTool.GetProperty(nameof(ImageGenerationTool.InputFidelity)),
+ InputImageMask = imageGenerationTool.GetProperty(nameof(ImageGenerationTool.InputImageMask)),
+ Model = igo?.ModelId,
+ ModerationLevel = imageGenerationTool.GetProperty(nameof(ImageGenerationTool.ModerationLevel)),
+ OutputCompressionFactor = imageGenerationTool.GetProperty(nameof(ImageGenerationTool.OutputCompressionFactor)),
+ OutputFileFormat = igo?.MediaType is { } mediaType ?
+ mediaType switch
+ {
+ "image/png" => ImageGenerationToolOutputFileFormat.Png,
+ "image/jpeg" => ImageGenerationToolOutputFileFormat.Jpeg,
+ "image/webp" => ImageGenerationToolOutputFileFormat.Webp,
+ _ => null,
+ } :
+ null,
+ PartialImageCount = igo?.StreamingCount,
+ Quality = imageGenerationTool.GetProperty(nameof(ImageGenerationTool.Quality)),
+ Size = igo?.ImageSize is { } size ?
+ new ImageGenerationToolSize(size.Width, size.Height) :
+ null,
+ };
+
case HostedMcpServerTool mcpTool:
- McpTool responsesMcpTool = Uri.TryCreate(mcpTool.ServerAddress, UriKind.Absolute, out Uri? url) ?
- ResponseTool.CreateMcpTool(
- mcpTool.ServerName,
- url,
- mcpTool.AuthorizationToken,
- mcpTool.ServerDescription) :
- ResponseTool.CreateMcpTool(
- mcpTool.ServerName,
- new McpToolConnectorId(mcpTool.ServerAddress),
- mcpTool.AuthorizationToken,
- mcpTool.ServerDescription);
+ McpTool responsesMcpTool = Uri.TryCreate(mcpTool.ServerAddress, UriKind.Absolute, out Uri? serverAddressUrl) ?
+ new McpTool(mcpTool.ServerName, serverAddressUrl) :
+ new McpTool(mcpTool.ServerName, new McpToolConnectorId(mcpTool.ServerAddress));
+
+ responsesMcpTool.ServerDescription = mcpTool.ServerDescription;
+ responsesMcpTool.AuthorizationToken = mcpTool.AuthorizationToken;
if (mcpTool.AllowedTools is not null)
{
@@ -621,48 +639,21 @@ void IDisposable.Dispose()
internal static FunctionTool ToResponseTool(AIFunctionDeclaration aiFunction, ChatOptions? options = null)
{
- bool? strict =
+ bool? strictModeEnabled =
OpenAIClientExtensions.HasStrict(aiFunction.AdditionalProperties) ??
OpenAIClientExtensions.HasStrict(options?.AdditionalProperties);
- return ResponseTool.CreateFunctionTool(
+ return new FunctionTool(
aiFunction.Name,
- OpenAIClientExtensions.ToOpenAIFunctionParameters(aiFunction, strict),
- strict,
- aiFunction.Description);
- }
-
- internal static ImageGenerationTool ToImageResponseTool(HostedImageGenerationTool imageGenerationTool)
- {
- ImageGenerationOptions? options = imageGenerationTool.Options;
-
- return new()
+ OpenAIClientExtensions.ToOpenAIFunctionParameters(aiFunction, strictModeEnabled),
+ strictModeEnabled)
{
- Background = imageGenerationTool.GetProperty(nameof(ImageGenerationTool.Background)),
- InputFidelity = imageGenerationTool.GetProperty(nameof(ImageGenerationTool.InputFidelity)),
- InputImageMask = imageGenerationTool.GetProperty(nameof(ImageGenerationTool.InputImageMask)),
- Model = options?.ModelId,
- ModerationLevel = imageGenerationTool.GetProperty(nameof(ImageGenerationTool.ModerationLevel)),
- OutputCompressionFactor = imageGenerationTool.GetProperty(nameof(ImageGenerationTool.OutputCompressionFactor)),
- OutputFileFormat = options?.MediaType is not null ?
- options.MediaType switch
- {
- "image/png" => ImageGenerationToolOutputFileFormat.Png,
- "image/jpeg" => ImageGenerationToolOutputFileFormat.Jpeg,
- "image/webp" => ImageGenerationToolOutputFileFormat.Webp,
- _ => null,
- } :
- null,
- PartialImageCount = options?.StreamingCount,
- Quality = imageGenerationTool.GetProperty(nameof(ImageGenerationTool.Quality)),
- Size = options?.ImageSize is not null ?
- new ImageGenerationToolSize(options.ImageSize.Value.Width, options.ImageSize.Value.Height) :
- null
+ FunctionDescription = aiFunction.Description,
};
}
/// Creates a from a .
- private static ChatRole ToChatRole(MessageRole? role) =>
+ private static ChatRole AsChatRole(MessageRole? role) =>
role switch
{
MessageRole.System => ChatRole.System,
@@ -672,23 +663,26 @@ private static ChatRole ToChatRole(MessageRole? role) =>
};
/// Creates a from a .
- private static ChatFinishReason? ToFinishReason(ResponseIncompleteStatusReason? statusReason) =>
+ private static ChatFinishReason? AsFinishReason(ResponseIncompleteStatusReason? statusReason) =>
statusReason == ResponseIncompleteStatusReason.ContentFilter ? ChatFinishReason.ContentFilter :
statusReason == ResponseIncompleteStatusReason.MaxOutputTokens ? ChatFinishReason.Length :
null;
- /// Converts a to a .
- private ResponseCreationOptions ToOpenAIResponseCreationOptions(ChatOptions? options, out string? openAIConversationId)
+ /// Converts a to a .
+ private CreateResponseOptions AsCreateResponseOptions(ChatOptions? options, out string? openAIConversationId)
{
openAIConversationId = null;
if (options is null)
{
- return new();
+ return new()
+ {
+ Model = _responseClient.Model,
+ };
}
bool hasRawRco = false;
- if (options.RawRepresentationFactory?.Invoke(this) is ResponseCreationOptions result)
+ if (options.RawRepresentationFactory?.Invoke(this) is CreateResponseOptions result)
{
hasRawRco = true;
}
@@ -697,32 +691,29 @@ private ResponseCreationOptions ToOpenAIResponseCreationOptions(ChatOptions? opt
result = new();
}
+ result.BackgroundModeEnabled ??= options.AllowBackgroundResponses;
result.MaxOutputTokenCount ??= options.MaxOutputTokens;
+ result.Model ??= options.ModelId ?? _responseClient.Model;
result.Temperature ??= options.Temperature;
result.TopP ??= options.TopP;
- result.BackgroundModeEnabled ??= options.AllowBackgroundResponses;
- OpenAIClientExtensions.PatchModelIfNotSet(ref result.Patch, options.ModelId);
- // If the ResponseCreationOptions.PreviousResponseId is already set (likely rare), then we don't need to do
+ // If the CreateResponseOptions.PreviousResponseId is already set (likely rare), then we don't need to do
// anything with regards to Conversation, because they're mutually exclusive and we would want to ignore
- // ChatOptions.ConversationId regardless of its value. If it's null, we want to examine the ResponseCreationOptions
+ // ChatOptions.ConversationId regardless of its value. If it's null, we want to examine the CreateResponseOptions
// instance to see if a conversation ID has already been set on it and use that conversation ID subsequently if
// it has. If one hasn't been set, but ChatOptions.ConversationId has been set, we'll either set
- // ResponseCreationOptions.Conversation if the string represents a conversation ID or else PreviousResponseId.
+ // CreateResponseOptions.Conversation if the string represents a conversation ID or else PreviousResponseId.
if (result.PreviousResponseId is null)
{
- // Technically, OpenAI's IDs are opaque. However, by convention conversation IDs start with "conv_" and
- // we can use that to disambiguate whether we're looking at a conversation ID or a response ID.
- string? chatOptionsConversationId = options.ConversationId;
- bool chatOptionsHasOpenAIConversationId = chatOptionsConversationId?.StartsWith("conv_", StringComparison.OrdinalIgnoreCase) is true;
+ bool chatOptionsHasOpenAIConversationId = OpenAIClientExtensions.IsConversationId(options.ConversationId);
if (hasRawRco || chatOptionsHasOpenAIConversationId)
{
- _ = result.Patch.TryGetValue("$.conversation"u8, out openAIConversationId);
+ openAIConversationId = result.ConversationOptions?.ConversationId;
if (openAIConversationId is null && chatOptionsHasOpenAIConversationId)
{
- result.Patch.Set("$.conversation"u8, chatOptionsConversationId!);
- openAIConversationId = chatOptionsConversationId;
+ result.ConversationOptions = new(options.ConversationId);
+ openAIConversationId = options.ConversationId;
}
}
@@ -765,7 +756,6 @@ private ResponseCreationOptions ToOpenAIResponseCreationOptions(ChatOptions? opt
break;
case AutoChatToolMode:
- case null:
result.ToolChoice = ResponseToolChoice.CreateAutoChoice();
break;
@@ -1063,9 +1053,10 @@ static FunctionCallOutputResponseItem SerializeAIContent(string callId, IEnumera
break;
case TextReasoningContent reasoningContent:
- yield return OpenAIResponsesModelFactory.ReasoningResponseItem(
- encryptedContent: reasoningContent.ProtectedData,
- summaryText: reasoningContent.Text);
+ yield return new ReasoningResponseItem(reasoningContent.Text)
+ {
+ EncryptedContent = reasoningContent.ProtectedData,
+ };
break;
case FunctionCallContent callContent:
@@ -1119,11 +1110,11 @@ static FunctionCallOutputResponseItem SerializeAIContent(string callId, IEnumera
}
}
- /// Extract usage details from an .
- private static UsageDetails? ToUsageDetails(OpenAIResponse? openAIResponse)
+ /// Extract usage details from a into a .
+ private static UsageDetails? ToUsageDetails(ResponseResult? responseResult)
{
UsageDetails? ud = null;
- if (openAIResponse?.Usage is { } usage)
+ if (responseResult?.Usage is { } usage)
{
ud = new()
{
@@ -1138,6 +1129,38 @@ static FunctionCallOutputResponseItem SerializeAIContent(string callId, IEnumera
return ud;
}
+ /// Converts a to a .
+ internal static ResponseTokenUsage? ToResponseTokenUsage(UsageDetails? usageDetails)
+ {
+ ResponseTokenUsage? rtu = null;
+ if (usageDetails is not null)
+ {
+ rtu = new()
+ {
+ InputTokenCount = (int?)usageDetails.InputTokenCount ?? 0,
+ OutputTokenCount = (int?)usageDetails.OutputTokenCount ?? 0,
+ TotalTokenCount = (int?)usageDetails.TotalTokenCount ?? 0,
+ InputTokenDetails = new(),
+ OutputTokenDetails = new(),
+ };
+
+ if (usageDetails.AdditionalCounts is { } additionalCounts)
+ {
+ if (additionalCounts.TryGetValue($"{nameof(ResponseTokenUsage.InputTokenDetails)}.{nameof(ResponseInputTokenUsageDetails.CachedTokenCount)}", out int? cachedTokenCount))
+ {
+ rtu.InputTokenDetails.CachedTokenCount = cachedTokenCount.GetValueOrDefault();
+ }
+
+ if (additionalCounts.TryGetValue($"{nameof(ResponseTokenUsage.OutputTokenDetails)}.{nameof(ResponseOutputTokenUsageDetails.ReasoningTokenCount)}", out int? reasoningTokenCount))
+ {
+ rtu.OutputTokenDetails.ReasoningTokenCount = reasoningTokenCount.GetValueOrDefault();
+ }
+ }
+ }
+
+ return rtu;
+ }
+
/// Convert a sequence of s to a list of .
private static List ToAIContents(IEnumerable contents)
{
@@ -1145,46 +1168,40 @@ private static List ToAIContents(IEnumerable con
foreach (ResponseContentPart part in contents)
{
+ AIContent? content;
switch (part.Kind)
{
case ResponseContentPartKind.InputText or ResponseContentPartKind.OutputText:
- TextContent text = new(part.Text) { RawRepresentation = part };
+ TextContent text = new(part.Text);
PopulateAnnotations(part, text);
- results.Add(text);
+ content = text;
break;
- case ResponseContentPartKind.InputFile:
- if (!string.IsNullOrWhiteSpace(part.InputImageFileId))
- {
- results.Add(new HostedFileContent(part.InputImageFileId) { MediaType = "image/*", RawRepresentation = part });
- }
- else if (!string.IsNullOrWhiteSpace(part.InputFileId))
- {
- results.Add(new HostedFileContent(part.InputFileId) { Name = part.InputFilename, RawRepresentation = part });
- }
- else if (part.InputFileBytes is not null)
- {
- results.Add(new DataContent(part.InputFileBytes, part.InputFileBytesMediaType ?? "application/octet-stream")
- {
- Name = part.InputFilename,
- RawRepresentation = part,
- });
- }
-
+ case ResponseContentPartKind.InputFile or ResponseContentPartKind.InputImage:
+ content =
+ !string.IsNullOrWhiteSpace(part.InputImageFileId) ? new HostedFileContent(part.InputImageFileId) { MediaType = "image/*" } :
+ !string.IsNullOrWhiteSpace(part.InputFileId) ? new HostedFileContent(part.InputFileId) { Name = part.InputFilename } :
+ part.InputFileBytes is not null ? new DataContent(part.InputFileBytes, part.InputFileBytesMediaType ?? "application/octet-stream") { Name = part.InputFilename } :
+ null;
break;
case ResponseContentPartKind.Refusal:
- results.Add(new ErrorContent(part.Refusal)
+ content = new ErrorContent(part.Refusal)
{
ErrorCode = nameof(ResponseContentPartKind.Refusal),
- RawRepresentation = part,
- });
+ };
break;
default:
- results.Add(new() { RawRepresentation = part });
+ content = new();
break;
}
+
+ if (content is not null)
+ {
+ content.RawRepresentation = part;
+ results.Add(content);
+ }
}
return results;
@@ -1288,7 +1305,7 @@ private static void AddCodeInterpreterContents(CodeInterpreterCallResponseItem c
});
}
- private static void AddImageGenerationContents(ImageGenerationCallResponseItem outputItem, ResponseCreationOptions? options, IList contents)
+ private static void AddImageGenerationContents(ImageGenerationCallResponseItem outputItem, CreateResponseOptions? options, IList contents)
{
var imageGenTool = options?.Tools.OfType().FirstOrDefault();
string outputFormat = imageGenTool?.OutputFileFormat?.ToString() ?? "png";
@@ -1302,14 +1319,11 @@ private static void AddImageGenerationContents(ImageGenerationCallResponseItem o
{
ImageId = outputItem.Id,
RawRepresentation = outputItem,
- Outputs = new List
- {
- new DataContent(outputItem.ImageResultBytes, $"image/{outputFormat}")
- }
+ Outputs = [new DataContent(outputItem.ImageResultBytes, $"image/{outputFormat}")]
});
}
- private static ImageGenerationToolResultContent GetImageGenerationResult(StreamingResponseImageGenerationCallPartialImageUpdate update, ResponseCreationOptions? options)
+ private static ImageGenerationToolResultContent GetImageGenerationResult(StreamingResponseImageGenerationCallPartialImageUpdate update, CreateResponseOptions? options)
{
var imageGenTool = options?.Tools.OfType().FirstOrDefault();
var outputType = imageGenTool?.OutputFileFormat?.ToString() ?? "png";
@@ -1333,15 +1347,13 @@ private static ImageGenerationToolResultContent GetImageGenerationResult(Streami
};
}
- private static OpenAIResponsesContinuationToken? CreateContinuationToken(OpenAIResponse openAIResponse)
- {
- return CreateContinuationToken(
- responseId: openAIResponse.Id,
- responseStatus: openAIResponse.Status,
- isBackgroundModeEnabled: openAIResponse.BackgroundModeEnabled);
- }
+ private static ResponsesClientContinuationToken? CreateContinuationToken(ResponseResult responseResult) =>
+ CreateContinuationToken(
+ responseId: responseResult.Id,
+ responseStatus: responseResult.Status,
+ isBackgroundModeEnabled: responseResult.BackgroundModeEnabled);
- private static OpenAIResponsesContinuationToken? CreateContinuationToken(
+ private static ResponsesClientContinuationToken? CreateContinuationToken(
string responseId,
ResponseStatus? responseStatus,
bool? isBackgroundModeEnabled,
@@ -1359,7 +1371,7 @@ private static ImageGenerationToolResultContent GetImageGenerationResult(Streami
if ((responseStatus is ResponseStatus.InProgress or ResponseStatus.Queued) ||
(responseStatus is null && updateSequenceNumber is not null))
{
- return new OpenAIResponsesContinuationToken(responseId)
+ return new ResponsesClientContinuationToken(responseId)
{
SequenceNumber = updateSequenceNumber,
};
@@ -1371,7 +1383,7 @@ private static ImageGenerationToolResultContent GetImageGenerationResult(Streami
return null;
}
- private static OpenAIResponsesContinuationToken? GetContinuationToken(IEnumerable messages, ChatOptions? options = null)
+ private static ResponsesClientContinuationToken? GetContinuationToken(IEnumerable messages, ChatOptions? options = null)
{
if (options?.ContinuationToken is { } token)
{
@@ -1380,7 +1392,7 @@ private static ImageGenerationToolResultContent GetImageGenerationResult(Streami
throw new InvalidOperationException("Messages are not allowed when continuing a background response using a continuation token.");
}
- return OpenAIResponsesContinuationToken.FromToken(token);
+ return ResponsesClientContinuationToken.FromToken(token);
}
return null;
diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesContinuationToken.cs b/src/Libraries/Microsoft.Extensions.AI.OpenAI/ResponsesClientContinuationToken.cs
similarity index 81%
rename from src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesContinuationToken.cs
rename to src/Libraries/Microsoft.Extensions.AI.OpenAI/ResponsesClientContinuationToken.cs
index 8e6f5ffd71c..770f5b10afa 100644
--- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesContinuationToken.cs
+++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/ResponsesClientContinuationToken.cs
@@ -13,10 +13,10 @@ namespace Microsoft.Extensions.AI;
/// The token is used for resuming streamed background responses and continuing
/// non-streamed background responses until completion.
///
-internal sealed class OpenAIResponsesContinuationToken : ResponseContinuationToken
+internal sealed class ResponsesClientContinuationToken : ResponseContinuationToken
{
- /// Initializes a new instance of the class.
- internal OpenAIResponsesContinuationToken(string responseId)
+ /// Initializes a new instance of the class.
+ internal ResponsesClientContinuationToken(string responseId)
{
ResponseId = responseId;
}
@@ -49,13 +49,13 @@ public override ReadOnlyMemory ToBytes()
return stream.ToArray();
}
- /// Create a new instance of from the provided .
+ /// Create a new instance of from the provided .
///
- /// The token to create the from.
- /// A equivalent of the provided .
- internal static OpenAIResponsesContinuationToken FromToken(ResponseContinuationToken token)
+ /// The token to create the from.
+ /// A equivalent of the provided .
+ internal static ResponsesClientContinuationToken FromToken(ResponseContinuationToken token)
{
- if (token is OpenAIResponsesContinuationToken openAIResponsesContinuationToken)
+ if (token is ResponsesClientContinuationToken openAIResponsesContinuationToken)
{
return openAIResponsesContinuationToken;
}
diff --git a/src/ProjectTemplates/Microsoft.Extensions.AI.Templates/src/ChatWithCustomData/ChatWithCustomData-CSharp.Web/Program.cs b/src/ProjectTemplates/Microsoft.Extensions.AI.Templates/src/ChatWithCustomData/ChatWithCustomData-CSharp.Web/Program.cs
index e9984318254..a51a674cf71 100644
--- a/src/ProjectTemplates/Microsoft.Extensions.AI.Templates/src/ChatWithCustomData/ChatWithCustomData-CSharp.Web/Program.cs
+++ b/src/ProjectTemplates/Microsoft.Extensions.AI.Templates/src/ChatWithCustomData/ChatWithCustomData-CSharp.Web/Program.cs
@@ -49,8 +49,8 @@
var openAIClient = new OpenAIClient(
new ApiKeyCredential(builder.Configuration["OpenAI:Key"] ?? throw new InvalidOperationException("Missing configuration: OpenAI:Key. See the README for details.")));
-#pragma warning disable OPENAI001 // GetOpenAIResponseClient(string) is experimental and subject to change or removal in future updates.
-var chatClient = openAIClient.GetOpenAIResponseClient("gpt-4o-mini").AsIChatClient();
+#pragma warning disable OPENAI001 // GetResponsesClient(string) is experimental and subject to change or removal in future updates.
+var chatClient = openAIClient.GetResponsesClient("gpt-4o-mini").AsIChatClient();
#pragma warning restore OPENAI001
var embeddingGenerator = openAIClient.GetEmbeddingClient("text-embedding-3-small").AsIEmbeddingGenerator();
@@ -66,7 +66,7 @@
#endif
var azureOpenAIEndpoint = new Uri(new Uri(builder.Configuration["AzureOpenAI:Endpoint"] ?? throw new InvalidOperationException("Missing configuration: AzureOpenAi:Endpoint. See the README for details.")), "/openai/v1");
#if (IsManagedIdentity)
-#pragma warning disable OPENAI001 // OpenAIClient(AuthenticationPolicy, OpenAIClientOptions) and GetOpenAIResponseClient(string) are experimental and subject to change or removal in future updates.
+#pragma warning disable OPENAI001 // OpenAIClient(AuthenticationPolicy, OpenAIClientOptions) and GetResponsesClient(string) are experimental and subject to change or removal in future updates.
var azureOpenAi = new OpenAIClient(
new BearerTokenPolicy(new DefaultAzureCredential(), "https://ai.azure.com/.default"),
new OpenAIClientOptions { Endpoint = azureOpenAIEndpoint });
@@ -75,9 +75,9 @@
var openAIOptions = new OpenAIClientOptions { Endpoint = azureOpenAIEndpoint };
var azureOpenAi = new OpenAIClient(new ApiKeyCredential(builder.Configuration["AzureOpenAI:Key"] ?? throw new InvalidOperationException("Missing configuration: AzureOpenAi:Key. See the README for details.")), openAIOptions);
-#pragma warning disable OPENAI001 // GetOpenAIResponseClient(string) is experimental and subject to change or removal in future updates.
+#pragma warning disable OPENAI001 // GetResponsesClient(string) is experimental and subject to change or removal in future updates.
#endif
-var chatClient = azureOpenAi.GetOpenAIResponseClient("gpt-4o-mini").AsIChatClient();
+var chatClient = azureOpenAi.GetResponsesClient("gpt-4o-mini").AsIChatClient();
#pragma warning restore OPENAI001
var embeddingGenerator = azureOpenAi.GetEmbeddingClient("text-embedding-3-small").AsIEmbeddingGenerator();
diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ChatClientIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ChatClientIntegrationTests.cs
index 349de2e771a..1293d14aec3 100644
--- a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ChatClientIntegrationTests.cs
+++ b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ChatClientIntegrationTests.cs
@@ -432,7 +432,7 @@ private async Task AvailableTools_SchemasAreAccepted(bool strict)
if (strict)
{
- aiFuncOptions.AdditionalProperties = new Dictionary { ["strictJsonSchema"] = true };
+ aiFuncOptions.AdditionalProperties = new Dictionary { ["strict"] = true };
}
return aiFuncOptions;
@@ -444,7 +444,7 @@ private async Task AvailableTools_SchemasAreAccepted(bool strict)
if (strict)
{
- additionalProperties["strictJsonSchema"] = true;
+ additionalProperties["strict"] = true;
}
return new CustomAIFunction($"CustomMethod{methodCount++}", schema, additionalProperties);
diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIChatClientTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIChatClientTests.cs
index 458256523e4..99aa44cdd0f 100644
--- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIChatClientTests.cs
+++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIChatClientTests.cs
@@ -332,7 +332,7 @@ public async Task ChatOptions_StrictRespected()
Tools = [AIFunctionFactory.Create(() => 42, "GetPersonAge", "Gets the age of the specified person.")],
AdditionalProperties = new()
{
- ["strictJsonSchema"] = true,
+ ["strict"] = true,
},
});
Assert.NotNull(response);
diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIConversionTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIConversionTests.cs
index 0ab4ea2c6b1..1a711b7417c 100644
--- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIConversionTests.cs
+++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIConversionTests.cs
@@ -47,7 +47,7 @@ public void AsOpenAIChatResponseFormat_HandlesVariousFormats()
"""), RemoveWhitespace(((IJsonModel)jsonSchema).Write(ModelReaderWriterOptions.Json).ToString()));
jsonSchema = ChatResponseFormat.ForJsonSchema(typeof(int), schemaName: "my_schema", schemaDescription: "A test schema").AsOpenAIChatResponseFormat(
- new() { AdditionalProperties = new AdditionalPropertiesDictionary { ["strictJsonSchema"] = true } });
+ new() { AdditionalProperties = new AdditionalPropertiesDictionary { ["strict"] = true } });
Assert.NotNull(jsonSchema);
Assert.Equal(RemoveWhitespace("""
{
@@ -82,7 +82,7 @@ public void AsOpenAIResponseTextFormat_HandlesVariousFormats()
"""), RemoveWhitespace(((IJsonModel)jsonSchema).Write(ModelReaderWriterOptions.Json).ToString()));
jsonSchema = ChatResponseFormat.ForJsonSchema(typeof(int), schemaName: "my_schema", schemaDescription: "A test schema").AsOpenAIResponseTextFormat(
- new() { AdditionalProperties = new AdditionalPropertiesDictionary { ["strictJsonSchema"] = true } });
+ new() { AdditionalProperties = new AdditionalPropertiesDictionary { ["strict"] = true } });
Assert.NotNull(jsonSchema);
Assert.Equal(ResponseTextFormatKind.JsonSchema, jsonSchema.Kind);
Assert.Equal(RemoveWhitespace("""
@@ -788,7 +788,7 @@ static async IAsyncEnumerable CreateUpdates()
[Fact]
public void AsChatResponse_ConvertsOpenAIResponse()
{
- Assert.Throws("response", () => ((OpenAIResponse)null!).AsChatResponse());
+ Assert.Throws("response", () => ((ResponseResult)null!).AsChatResponse());
// The OpenAI library currently doesn't provide any way to create an OpenAIResponse instance,
// as all constructors/factory methods currently are internal. Update this test when such functionality is available.
@@ -1355,32 +1355,32 @@ public async Task AsOpenAIStreamingChatCompletionUpdatesAsync_WithMultipleUpdate
[Fact]
public void AsOpenAIResponse_WithNullArgument_ThrowsArgumentNullException()
{
- Assert.Throws("response", () => ((ChatResponse)null!).AsOpenAIResponse());
+ Assert.Throws("response", () => ((ChatResponse)null!).AsOpenAIResponseResult());
}
[Fact]
public void AsOpenAIResponse_WithRawRepresentation_ReturnsOriginal()
{
- var originalOpenAIResponse = OpenAIResponsesModelFactory.OpenAIResponse(
- "original-response-id",
- new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero),
- ResponseStatus.Completed,
- usage: null,
- maxOutputTokenCount: 100,
- outputItems: [],
- parallelToolCallsEnabled: false,
- model: "gpt-4",
- temperature: 0.7f,
- topP: 0.9f,
- previousResponseId: "prev-id",
- instructions: "Test instructions");
+ ResponseResult originalOpenAIResponse = new()
+ {
+ Id = "original-response-id",
+ CreatedAt = new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero),
+ Status = ResponseStatus.Completed,
+ MaxOutputTokenCount = 100,
+ ParallelToolCallsEnabled = false,
+ Model = "gpt-4",
+ Temperature = 0.7f,
+ TopP = 0.9f,
+ PreviousResponseId = "prev-id",
+ Instructions = "Test instructions"
+ };
var chatResponse = new ChatResponse(new ChatMessage(ChatRole.Assistant, "Test"))
{
RawRepresentation = originalOpenAIResponse
};
- var result = chatResponse.AsOpenAIResponse();
+ var result = chatResponse.AsOpenAIResponseResult();
Assert.Same(originalOpenAIResponse, result);
}
@@ -1396,7 +1396,7 @@ public void AsOpenAIResponse_WithBasicChatResponse_CreatesValidOpenAIResponse()
FinishReason = ChatFinishReason.Stop
};
- var openAIResponse = chatResponse.AsOpenAIResponse();
+ var openAIResponse = chatResponse.AsOpenAIResponseResult();
Assert.NotNull(openAIResponse);
Assert.Equal("test-response-id", openAIResponse.Id);
@@ -1415,6 +1415,7 @@ public void AsOpenAIResponse_WithChatOptions_IncludesOptionsInResponse()
{
var chatResponse = new ChatResponse(new ChatMessage(ChatRole.Assistant, "Test message"))
{
+ ConversationId = "conv_123",
ResponseId = "options-test",
ModelId = "gpt-3.5-turbo"
};
@@ -1423,20 +1424,19 @@ public void AsOpenAIResponse_WithChatOptions_IncludesOptionsInResponse()
{
MaxOutputTokens = 500,
AllowMultipleToolCalls = true,
- ConversationId = "conversation-123",
Instructions = "You are a helpful assistant.",
Temperature = 0.8f,
TopP = 0.95f,
ModelId = "override-model"
};
- var openAIResponse = chatResponse.AsOpenAIResponse(options);
+ var openAIResponse = chatResponse.AsOpenAIResponseResult(options);
Assert.Equal("options-test", openAIResponse.Id);
Assert.Equal("gpt-3.5-turbo", openAIResponse.Model);
Assert.Equal(500, openAIResponse.MaxOutputTokenCount);
Assert.True(openAIResponse.ParallelToolCallsEnabled);
- Assert.Equal("conversation-123", openAIResponse.PreviousResponseId);
+ Assert.Equal("conv_123", openAIResponse.ConversationOptions?.ConversationId);
Assert.Equal("You are a helpful assistant.", openAIResponse.Instructions);
Assert.Equal(0.8f, openAIResponse.Temperature);
Assert.Equal(0.95f, openAIResponse.TopP);
@@ -1451,7 +1451,7 @@ public void AsOpenAIResponse_WithEmptyMessages_CreatesResponseWithEmptyOutputIte
ModelId = "gpt-4"
};
- var openAIResponse = chatResponse.AsOpenAIResponse();
+ var openAIResponse = chatResponse.AsOpenAIResponseResult();
Assert.Equal("empty-response", openAIResponse.Id);
Assert.Equal("gpt-4", openAIResponse.Model);
@@ -1477,7 +1477,7 @@ public void AsOpenAIResponse_WithMultipleMessages_ConvertsAllMessages()
ResponseId = "multi-message-response"
};
- var openAIResponse = chatResponse.AsOpenAIResponse();
+ var openAIResponse = chatResponse.AsOpenAIResponseResult();
Assert.Equal(4, openAIResponse.OutputItems.Count);
@@ -1514,7 +1514,7 @@ public void AsOpenAIResponse_WithToolMessages_ConvertsCorrectly()
ResponseId = "tool-message-test"
};
- var openAIResponse = chatResponse.AsOpenAIResponse();
+ var openAIResponse = chatResponse.AsOpenAIResponseResult();
var outputItems = openAIResponse.OutputItems.ToArray();
Assert.Equal(4, outputItems.Length);
@@ -1545,7 +1545,7 @@ public void AsOpenAIResponse_WithSystemAndUserMessages_ConvertsCorrectly()
ResponseId = "system-user-test"
};
- var openAIResponse = chatResponse.AsOpenAIResponse();
+ var openAIResponse = chatResponse.AsOpenAIResponseResult();
var outputItems = openAIResponse.OutputItems.ToArray();
Assert.Equal(3, outputItems.Length);
@@ -1564,15 +1564,15 @@ public void AsOpenAIResponse_WithDefaultValues_UsesExpectedDefaults()
{
var chatResponse = new ChatResponse(new ChatMessage(ChatRole.Assistant, "Default test"));
- var openAIResponse = chatResponse.AsOpenAIResponse();
+ var openAIResponse = chatResponse.AsOpenAIResponseResult();
Assert.NotNull(openAIResponse);
Assert.Equal(ResponseStatus.Completed, openAIResponse.Status);
- Assert.False(openAIResponse.ParallelToolCallsEnabled);
+ Assert.True(openAIResponse.ParallelToolCallsEnabled);
Assert.Null(openAIResponse.MaxOutputTokenCount);
Assert.Null(openAIResponse.Temperature);
Assert.Null(openAIResponse.TopP);
- Assert.Null(openAIResponse.PreviousResponseId);
+ Assert.Null(openAIResponse.ConversationOptions);
Assert.Null(openAIResponse.Instructions);
Assert.NotNull(openAIResponse.OutputItems);
}
@@ -1587,7 +1587,7 @@ public void AsOpenAIResponse_WithOptionsButNoModelId_UsesOptionsModelId()
ModelId = "options-model-id"
};
- var openAIResponse = chatResponse.AsOpenAIResponse(options);
+ var openAIResponse = chatResponse.AsOpenAIResponseResult(options);
Assert.Equal("options-model-id", openAIResponse.Model);
}
@@ -1605,7 +1605,7 @@ public void AsOpenAIResponse_WithBothModelIds_PrefersChatResponseModelId()
ModelId = "options-model-id"
};
- var openAIResponse = chatResponse.AsOpenAIResponse(options);
+ var openAIResponse = chatResponse.AsOpenAIResponseResult(options);
Assert.Equal("response-model-id", openAIResponse.Model);
}
diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientIntegrationTests.cs
index 830563a60e1..1421e780dca 100644
--- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientIntegrationTests.cs
+++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientIntegrationTests.cs
@@ -14,7 +14,7 @@ public class OpenAIResponseClientIntegrationTests : ChatClientIntegrationTests
{
protected override IChatClient? CreateChatClient() =>
IntegrationTestHelpers.GetOpenAIClient()
- ?.GetOpenAIResponseClient(TestRunnerConfiguration.Instance["OpenAI:ChatModel"] ?? "gpt-4o-mini")
+ ?.GetResponsesClient(TestRunnerConfiguration.Instance["OpenAI:ChatModel"] ?? "gpt-4o-mini")
.AsIChatClient();
public override bool FunctionInvokingChatClientSetsConversationId => true;
diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs
index 34526b683bd..1e19466ee7f 100644
--- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs
+++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs
@@ -11,7 +11,6 @@
using System.Net.Http;
using System.Text;
using System.Text.Json;
-using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
@@ -28,7 +27,7 @@ public class OpenAIResponseClientTests
[Fact]
public void AsIChatClient_InvalidArgs_Throws()
{
- Assert.Throws("responseClient", () => ((OpenAIResponseClient)null!).AsIChatClient());
+ Assert.Throws("responseClient", () => ((ResponsesClient)null!).AsIChatClient());
}
[Fact]
@@ -39,7 +38,7 @@ public void AsIChatClient_ProducesExpectedMetadata()
var client = new OpenAIClient(new ApiKeyCredential("key"), new OpenAIClientOptions { Endpoint = endpoint });
- IChatClient chatClient = client.GetOpenAIResponseClient(model).AsIChatClient();
+ IChatClient chatClient = client.GetResponsesClient(model).AsIChatClient();
var metadata = chatClient.GetService();
Assert.Equal("openai", metadata?.ProviderName);
Assert.Equal(endpoint, metadata?.ProviderUri);
@@ -49,11 +48,11 @@ public void AsIChatClient_ProducesExpectedMetadata()
[Fact]
public void GetService_SuccessfullyReturnsUnderlyingClient()
{
- OpenAIResponseClient openAIClient = new OpenAIClient(new ApiKeyCredential("key")).GetOpenAIResponseClient("model");
+ ResponsesClient openAIClient = new OpenAIClient(new ApiKeyCredential("key")).GetResponsesClient("model");
IChatClient chatClient = openAIClient.AsIChatClient();
Assert.Same(chatClient, chatClient.GetService());
- Assert.Same(openAIClient, chatClient.GetService());
+ Assert.Same(openAIClient, chatClient.GetService());
using IChatClient pipeline = chatClient
.AsBuilder()
@@ -67,7 +66,7 @@ public void GetService_SuccessfullyReturnsUnderlyingClient()
Assert.NotNull(pipeline.GetService());
Assert.NotNull(pipeline.GetService());
- Assert.Same(openAIClient, pipeline.GetService());
+ Assert.Same(openAIClient, pipeline.GetService());
Assert.IsType(pipeline.GetService());
}
@@ -295,7 +294,7 @@ public async Task BasicReasoningResponse_Streaming()
List updates = [];
await foreach (var update in client.GetStreamingResponseAsync("Calculate the sum of the first 5 positive integers.", new()
{
- RawRepresentationFactory = options => new ResponseCreationOptions
+ RawRepresentationFactory = options => new CreateResponseOptions
{
ReasoningOptions = new()
{
@@ -428,7 +427,7 @@ public async Task ReasoningTextDelta_Streaming()
List updates = [];
await foreach (var update in client.GetStreamingResponseAsync("Solve this problem step by step.", new()
{
- RawRepresentationFactory = options => new ResponseCreationOptions
+ RawRepresentationFactory = options => new CreateResponseOptions
{
ReasoningOptions = new()
{
@@ -609,7 +608,6 @@ public async Task MissingAbstractionResponse_NonStreaming()
"display_height": 768
}
],
- "tool_choice": "auto",
"input": [
{
"type": "message",
@@ -700,7 +698,7 @@ public async Task MissingAbstractionResponse_NonStreaming()
ChatOptions chatOptions = new()
{
Tools = [ResponseTool.CreateComputerTool(ComputerToolEnvironment.Browser, 1024, 768).AsAITool()],
- RawRepresentationFactory = options => new ResponseCreationOptions
+ RawRepresentationFactory = options => new CreateResponseOptions
{
ReasoningOptions = new() { ReasoningSummaryVerbosity = ResponseReasoningSummaryVerbosity.Concise },
}
@@ -745,7 +743,6 @@ public async Task MissingAbstractionResponse_Streaming()
"display_height": 768
}
],
- "tool_choice": "auto",
"input": [
{
"type": "message",
@@ -789,7 +786,7 @@ public async Task MissingAbstractionResponse_Streaming()
ChatOptions chatOptions = new()
{
Tools = [ResponseTool.CreateComputerTool(ComputerToolEnvironment.Browser, 1024, 768).AsAITool()],
- RawRepresentationFactory = options => new ResponseCreationOptions
+ RawRepresentationFactory = options => new CreateResponseOptions
{
ReasoningOptions = new() { ReasoningSummaryVerbosity = ResponseReasoningSummaryVerbosity.Concise },
}
@@ -843,7 +840,6 @@ public async Task ChatOptions_StrictRespected()
]
}
],
- "tool_choice": "auto",
"tools": [
{
"type": "function",
@@ -894,7 +890,7 @@ public async Task ChatOptions_StrictRespected()
Tools = [AIFunctionFactory.Create(() => 42, "GetPersonAge", "Gets the age of the specified person.")],
AdditionalProperties = new()
{
- ["strictJsonSchema"] = true,
+ ["strict"] = true,
},
});
Assert.NotNull(response);
@@ -1039,7 +1035,7 @@ public async Task ChatOptions_DoNotOverwrite_NotNullPropertiesInRawRepresentatio
{
RawRepresentationFactory = (c) =>
{
- ResponseCreationOptions openAIOptions = new()
+ CreateResponseOptions openAIOptions = new()
{
MaxOutputTokenCount = 10,
PreviousResponseId = "resp_42",
@@ -1202,7 +1198,6 @@ public async Task McpToolCall_ApprovalRequired_NonStreaming(string role)
"server_url": "https://mcp.deepwiki.com/mcp"
}
],
- "tool_choice": "auto",
"input": [
{
"type": "message",
@@ -1257,7 +1252,6 @@ public async Task McpToolCall_ApprovalRequired_NonStreaming(string role)
},
"verbosity": "medium"
},
- "tool_choice": "auto",
"tools": [
{
"type": "mcp",
@@ -1317,7 +1311,6 @@ public async Task McpToolCall_ApprovalRequired_NonStreaming(string role)
"server_url": "https://mcp.deepwiki.com/mcp"
}
],
- "tool_choice": "auto",
"input": [
{
"type": "mcp_approval_response",
@@ -1474,7 +1467,6 @@ public async Task McpToolCall_ApprovalNotRequired_NonStreaming(bool rawTool)
"require_approval": "never"
}
],
- "tool_choice": "auto",
"input": [
{
"type": "message",
@@ -1739,7 +1731,6 @@ public async Task McpToolCall_ApprovalNotRequired_Streaming()
"require_approval": "never"
}
],
- "tool_choice": "auto",
"input": [
{
"type": "message",
@@ -2610,7 +2601,6 @@ public async Task CodeInterpreterTool_NonStreaming()
"role":"user",
"content":[{"type":"input_text","text":"Calculate the sum of numbers from 1 to 5"}]
}],
- "tool_choice":"auto",
"tools":[{
"type":"code_interpreter",
"container":{"type":"auto"}
@@ -2739,7 +2729,6 @@ public async Task CodeInterpreterTool_Streaming()
"role":"user",
"content":[{"type":"input_text","text":"Calculate the sum of numbers from 1 to 10 using Python"}]
}],
- "tool_choice":"auto",
"tools":[{
"type":"code_interpreter",
"container":{"type":"auto"}
@@ -3032,7 +3021,7 @@ public async Task ConversationId_AsConversationId_NonStreaming()
{
"temperature":0.5,
"model":"gpt-4o-mini",
- "conversation":"conv_12345",
+ "conversation":{"id":"conv_12345"},
"input": [{
"type":"message",
"role":"user",
@@ -3134,7 +3123,7 @@ public async Task ConversationId_WhenStoreDisabled_ReturnsNull_NonStreaming()
{
MaxOutputTokens = 20,
Temperature = 0.5f,
- RawRepresentationFactory = (c) => new ResponseCreationOptions
+ RawRepresentationFactory = (c) => new CreateResponseOptions
{
StoredOutputEnabled = false
}
@@ -3196,7 +3185,7 @@ public async Task ConversationId_ChatOptionsOverridesRawRepresentationResponseId
MaxOutputTokens = 20,
Temperature = 0.5f,
ConversationId = "resp_override",
- RawRepresentationFactory = (c) => new ResponseCreationOptions
+ RawRepresentationFactory = (c) => new CreateResponseOptions
{
PreviousResponseId = null
}
@@ -3258,7 +3247,7 @@ public async Task ConversationId_RawRepresentationPreviousResponseIdTakesPrecede
MaxOutputTokens = 20,
Temperature = 0.5f,
ConversationId = "conv_ignored",
- RawRepresentationFactory = (c) => new ResponseCreationOptions
+ RawRepresentationFactory = (c) => new CreateResponseOptions
{
PreviousResponseId = "resp_fromraw"
}
@@ -3320,7 +3309,7 @@ public async Task ConversationId_WhenStoreExplicitlyTrue_UsesResponseId_NonStrea
{
MaxOutputTokens = 20,
Temperature = 0.5f,
- RawRepresentationFactory = (c) => new ResponseCreationOptions
+ RawRepresentationFactory = (c) => new CreateResponseOptions
{
StoredOutputEnabled = true
}
@@ -3394,7 +3383,7 @@ public async Task ConversationId_WhenStoreExplicitlyTrue_UsesResponseId_Streamin
{
MaxOutputTokens = 20,
Temperature = 0.5f,
- RawRepresentationFactory = (c) => new ResponseCreationOptions
+ RawRepresentationFactory = (c) => new CreateResponseOptions
{
StoredOutputEnabled = true
}
@@ -3475,7 +3464,7 @@ public async Task ConversationId_WhenStoreDisabled_ReturnsNull_Streaming()
{
MaxOutputTokens = 20,
Temperature = 0.5f,
- RawRepresentationFactory = (c) => new ResponseCreationOptions
+ RawRepresentationFactory = (c) => new CreateResponseOptions
{
StoredOutputEnabled = false
}
@@ -3500,7 +3489,7 @@ public async Task ConversationId_AsConversationId_Streaming()
{
"temperature":0.5,
"model":"gpt-4o-mini",
- "conversation":"conv_12345",
+ "conversation":{"id":"conv_12345"},
"input":[
{
"type":"message",
@@ -3656,7 +3645,7 @@ public async Task ConversationId_RawRepresentationConversationIdTakesPrecedence_
{
"temperature":0.5,
"model":"gpt-4o-mini",
- "conversation":"conv_12345",
+ "conversation":{"id":"conv_12345"},
"input": [{
"type":"message",
"role":"user",
@@ -3695,20 +3684,15 @@ public async Task ConversationId_RawRepresentationConversationIdTakesPrecedence_
using HttpClient httpClient = new(handler);
using IChatClient client = CreateResponseClient(httpClient, "gpt-4o-mini");
- var rcoJsonModel = (IJsonModel)new ResponseCreationOptions();
- BinaryData rcoJsonBinaryData = rcoJsonModel.Write(ModelReaderWriterOptions.Json);
- JsonObject rcoJsonObject = Assert.IsType(JsonNode.Parse(rcoJsonBinaryData.ToMemory().Span));
- Assert.Null(rcoJsonObject["conversation"]);
- rcoJsonObject["conversation"] = "conv_12345";
-
var response = await client.GetResponseAsync("hello", new()
{
MaxOutputTokens = 20,
Temperature = 0.5f,
ConversationId = "conv_ignored",
- RawRepresentationFactory = (c) => rcoJsonModel.Create(
- new BinaryData(JsonSerializer.SerializeToUtf8Bytes(rcoJsonObject)),
- ModelReaderWriterOptions.Json)
+ RawRepresentationFactory = _ => new CreateResponseOptions
+ {
+ ConversationOptions = new("conv_12345"),
+ }
});
Assert.NotNull(response);
@@ -5146,7 +5130,6 @@ public async Task HostedImageGenerationTool_NonStreaming()
"output_format": "png"
}
],
- "tool_choice": "auto",
"input": [
{
"type": "message",
@@ -5240,7 +5223,6 @@ public async Task HostedImageGenerationTool_Streaming()
"output_format": "png"
}
],
- "tool_choice": "auto",
"stream": true,
"input": [
{
@@ -5352,7 +5334,6 @@ public async Task HostedImageGenerationTool_StreamingMultipleImages()
"partial_images": 3
}
],
- "tool_choice": "auto",
"stream": true,
"input": [
{
@@ -5486,7 +5467,7 @@ private static IChatClient CreateResponseClient(HttpClient httpClient, string mo
new OpenAIClient(
new ApiKeyCredential("apikey"),
new OpenAIClientOptions { Transport = new HttpClientPipelineTransport(httpClient) })
- .GetOpenAIResponseClient(modelId)
+ .GetResponsesClient(modelId)
.AsIChatClient();
private static string ResponseStatusToRequestValue(ResponseStatus status)
diff --git a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb.OpenAI_AzureAISearch.verified/aichatweb/Program.cs b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb.OpenAI_AzureAISearch.verified/aichatweb/Program.cs
index d7e25135462..4bfb1ca7796 100644
--- a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb.OpenAI_AzureAISearch.verified/aichatweb/Program.cs
+++ b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb.OpenAI_AzureAISearch.verified/aichatweb/Program.cs
@@ -17,8 +17,8 @@
var openAIClient = new OpenAIClient(
new ApiKeyCredential(builder.Configuration["OpenAI:Key"] ?? throw new InvalidOperationException("Missing configuration: OpenAI:Key. See the README for details.")));
-#pragma warning disable OPENAI001 // GetOpenAIResponseClient(string) is experimental and subject to change or removal in future updates.
-var chatClient = openAIClient.GetOpenAIResponseClient("gpt-4o-mini").AsIChatClient();
+#pragma warning disable OPENAI001 // GetResponsesClient(string) is experimental and subject to change or removal in future updates.
+var chatClient = openAIClient.GetResponsesClient("gpt-4o-mini").AsIChatClient();
#pragma warning restore OPENAI001
var embeddingGenerator = openAIClient.GetEmbeddingClient("text-embedding-3-small").AsIEmbeddingGenerator();