diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props index b870cf92b8dc..8a586cdc2b2b 100644 --- a/dotnet/Directory.Packages.props +++ b/dotnet/Directory.Packages.props @@ -22,9 +22,9 @@ - - - + + + @@ -92,7 +92,7 @@ - + @@ -109,8 +109,8 @@ - - + + @@ -119,10 +119,10 @@ - - + + - + @@ -131,14 +131,14 @@ - + - + @@ -151,7 +151,7 @@ - + diff --git a/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step01_Basics/Program.cs b/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step01_Basics/Program.cs index 7302ce5dae09..5f3552b2beab 100644 --- a/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step01_Basics/Program.cs +++ b/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step01_Basics/Program.cs @@ -3,6 +3,7 @@ using Azure.AI.OpenAI; using Azure.Identity; using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; using Microsoft.SemanticKernel.Agents.OpenAI; using OpenAI; @@ -24,8 +25,8 @@ async Task SKAgentAsync() Console.WriteLine("\n=== SK Agent ===\n"); var responseClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) - .GetResponsesClient(deploymentName); - OpenAIResponseAgent agent = new(responseClient) + .GetResponsesClient(); + OpenAIResponseAgent agent = new(responseClient, deploymentName) { Name = "Joker", Instructions = "You are good at telling jokes.", @@ -54,9 +55,9 @@ async Task SKAgent_As_AFAgentAsync() Console.WriteLine("\n=== SK Agent Converted as an AF Agent ===\n"); var responseClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) - .GetResponsesClient(deploymentName); + .GetResponsesClient(); - OpenAIResponseAgent skAgent = new(responseClient) + OpenAIResponseAgent skAgent = new(responseClient, deploymentName) { Name = "Joker", Instructions = "You are good at telling jokes.", @@ -83,7 +84,7 @@ async Task AFAgentAsync() Console.WriteLine("\n=== AF Agent ===\n"); var agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) - .GetResponsesClient(deploymentName) + .GetResponsesClient().AsIChatClient(deploymentName) .CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes."); var thread = agent.GetNewThread(); diff --git a/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step02_ReasoningModel/Program.cs b/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step02_ReasoningModel/Program.cs index 480d5fed12ff..dc864675fbf9 100644 --- a/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step02_ReasoningModel/Program.cs +++ b/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step02_ReasoningModel/Program.cs @@ -51,8 +51,8 @@ async Task SKAgentAsync() Console.WriteLine("\n=== SK Agent ===\n"); var responseClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) - .GetResponsesClient(deploymentName); - OpenAIResponseAgent agent = new(responseClient) + .GetResponsesClient(); + OpenAIResponseAgent agent = new(responseClient, deploymentName) { Name = "Thinker", Instructions = "You are good at thinking hard before answering.", @@ -119,11 +119,11 @@ async Task SKAgent_As_AFAgentAsync() Console.WriteLine("\n=== SK Agent Converted as an AF Agent ===\n"); var responseClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) - .GetResponsesClient(deploymentName); + .GetResponsesClient(); #pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - OpenAIResponseAgent skAgent = new(responseClient) + OpenAIResponseAgent skAgent = new(responseClient, deploymentName) { Name = "Thinker", Instructions = "You are good at thinking hard before answering.", @@ -180,7 +180,7 @@ async Task AFAgentAsync() Console.WriteLine("\n=== AF Agent ===\n"); var agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) - .GetResponsesClient(deploymentName) + .GetResponsesClient().AsIChatClient(deploymentName) .CreateAIAgent(name: "Thinker", instructions: "You are good at thinking hard before answering."); var thread = agent.GetNewThread(); diff --git a/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step03_ToolCall/Program.cs b/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step03_ToolCall/Program.cs index 1155a02a339a..04b25861c54d 100644 --- a/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step03_ToolCall/Program.cs +++ b/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step03_ToolCall/Program.cs @@ -29,7 +29,7 @@ static string GetWeather([Description("The location to get the weather for.")] s async Task SKAgentAsync() { OpenAIResponseAgent agent = new(new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) - .GetResponsesClient(deploymentName)) + .GetResponsesClient(), deploymentName) { StoreEnabled = true }; // Initialize plugin and add to the agent's Kernel (same as direct Kernel usage). @@ -49,7 +49,7 @@ async Task SKAgentAsync() async Task SKAgent_As_AFAgentAsync() { OpenAIResponseAgent skAgent = new(new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) - .GetResponsesClient(deploymentName)) + .GetResponsesClient(), deploymentName) { StoreEnabled = true }; // Initialize plugin and add to the agent's Kernel (same as direct Kernel usage). @@ -66,7 +66,7 @@ async Task SKAgent_As_AFAgentAsync() async Task AFAgentAsync() { var agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) - .GetResponsesClient(deploymentName) + .GetResponsesClient().AsIChatClient(deploymentName) .CreateAIAgent(instructions: "You are a helpful assistant", tools: [AIFunctionFactory.Create(GetWeather)]); Console.WriteLine("\n=== AF Agent Response ===\n"); diff --git a/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step04_DependencyInjection/Program.cs b/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step04_DependencyInjection/Program.cs index 098dc5eacff1..a7b612c0a277 100644 --- a/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step04_DependencyInjection/Program.cs +++ b/dotnet/samples/AgentFrameworkMigration/AzureOpenAIResponses/Step04_DependencyInjection/Program.cs @@ -28,7 +28,7 @@ async Task SKAgentAsync() var serviceCollection = new ServiceCollection(); serviceCollection.AddTransient((sp) => new OpenAIResponseAgent(new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) - .GetResponsesClient(deploymentName)) + .GetResponsesClient(), deploymentName) { Name = "Joker", Instructions = "You are good at telling jokes.", @@ -49,7 +49,7 @@ async Task SKAgent_As_AFAgentAsync() var serviceCollection = new ServiceCollection(); serviceCollection.AddTransient((sp) => new OpenAIResponseAgent(new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) - .GetResponsesClient(deploymentName)) + .GetResponsesClient(), deploymentName) { Name = "Joker", Instructions = "You are good at telling jokes.", @@ -71,7 +71,7 @@ async Task AFAgentAsync() var serviceCollection = new ServiceCollection(); serviceCollection.AddTransient((sp) => new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()) - .GetResponsesClient(deploymentName) + .GetResponsesClient().AsIChatClient(deploymentName) .CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes.")); await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider(); diff --git a/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step01_Basics/Program.cs b/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step01_Basics/Program.cs index 4d3b6e34e286..b130a3e2a0cc 100644 --- a/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step01_Basics/Program.cs +++ b/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step01_Basics/Program.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using Microsoft.Agents.AI; +using Microsoft.Extensions.AI; using Microsoft.SemanticKernel.Agents.OpenAI; using OpenAI; @@ -21,7 +22,7 @@ async Task SKAgentAsync() { Console.WriteLine("\n=== SK Agent ===\n"); - var responseClient = new OpenAIClient(apiKey).GetResponsesClient(model); + var responseClient = new OpenAIClient(apiKey).GetResponsesClient(); OpenAIResponseAgent agent = new(responseClient) { Name = "Joker", @@ -51,7 +52,7 @@ async Task SKAgent_As_AFAgentAsync() { Console.WriteLine("\n=== SK Agent Converted as an AF Agent ===\n"); - var responseClient = new OpenAIClient(apiKey).GetResponsesClient(model); + var responseClient = new OpenAIClient(apiKey).GetResponsesClient(); OpenAIResponseAgent skAgent = new(responseClient) { @@ -79,7 +80,7 @@ async Task AFAgentAsync() { Console.WriteLine("\n=== AF Agent ===\n"); - var agent = new OpenAIClient(apiKey).GetResponsesClient(model) + var agent = new OpenAIClient(apiKey).GetResponsesClient().AsIChatClient(model) .CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes."); var thread = agent.GetNewThread(); diff --git a/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step02_ReasoningModel/Program.cs b/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step02_ReasoningModel/Program.cs index 9079dd73748b..d7519abd347d 100644 --- a/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step02_ReasoningModel/Program.cs +++ b/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step02_ReasoningModel/Program.cs @@ -48,7 +48,7 @@ async Task SKAgentAsync() { Console.WriteLine("\n=== SK Agent ===\n"); - var responseClient = new OpenAIClient(apiKey).GetResponsesClient(model); + var responseClient = new OpenAIClient(apiKey).GetResponsesClient(); OpenAIResponseAgent agent = new(responseClient) { Name = "Thinker", @@ -116,7 +116,7 @@ async Task SKAgent_As_AFAgentAsync() { Console.WriteLine("\n=== SK Agent Converted as an AF Agent ===\n"); - var responseClient = new OpenAIClient(apiKey).GetResponsesClient(model); + var responseClient = new OpenAIClient(apiKey).GetResponsesClient(); #pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -176,7 +176,7 @@ async Task AFAgentAsync() { Console.WriteLine("\n=== AF Agent ===\n"); - var agent = new OpenAIClient(apiKey).GetResponsesClient(model) + var agent = new OpenAIClient(apiKey).GetResponsesClient().AsIChatClient(model) .CreateAIAgent(name: "Thinker", instructions: "You are at thinking hard before answering."); var thread = agent.GetNewThread(); diff --git a/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step03_ToolCall/Program.cs b/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step03_ToolCall/Program.cs index eacc92a2d26c..ff9fdae2d4d6 100644 --- a/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step03_ToolCall/Program.cs +++ b/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step03_ToolCall/Program.cs @@ -28,7 +28,7 @@ async Task SKAgentAsync() { var builder = Kernel.CreateBuilder().AddOpenAIChatClient(model, apiKey); - OpenAIResponseAgent agent = new(new OpenAIClient(apiKey).GetResponsesClient(model)) { StoreEnabled = true }; + OpenAIResponseAgent agent = new(new OpenAIClient(apiKey).GetResponsesClient(), model) { StoreEnabled = true }; // Initialize plugin and add to the agent's Kernel (same as direct Kernel usage). agent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("KernelPluginName", [KernelFunctionFactory.CreateFromMethod(GetWeather)])); @@ -48,7 +48,7 @@ async Task SKAgent_As_AFAgentAsync() { var builder = Kernel.CreateBuilder().AddOpenAIChatClient(model, apiKey); - OpenAIResponseAgent skAgent = new(new OpenAIClient(apiKey).GetResponsesClient(model)) { StoreEnabled = true }; + OpenAIResponseAgent skAgent = new(new OpenAIClient(apiKey).GetResponsesClient(), model) { StoreEnabled = true }; // Initialize plugin and add to the agent's Kernel (same as direct Kernel usage). skAgent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("KernelPluginName", [KernelFunctionFactory.CreateFromMethod(GetWeather)])); @@ -63,7 +63,7 @@ async Task SKAgent_As_AFAgentAsync() async Task AFAgentAsync() { - var agent = new OpenAIClient(apiKey).GetResponsesClient(model).CreateAIAgent( + var agent = new OpenAIClient(apiKey).GetResponsesClient().AsIChatClient(model).CreateAIAgent( instructions: "You are a helpful assistant", tools: [AIFunctionFactory.Create(GetWeather)]); diff --git a/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step04_DependencyInjection/Program.cs b/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step04_DependencyInjection/Program.cs index bc746d77a895..403ec70e6575 100644 --- a/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step04_DependencyInjection/Program.cs +++ b/dotnet/samples/AgentFrameworkMigration/OpenAIResponses/Step04_DependencyInjection/Program.cs @@ -25,7 +25,7 @@ async Task SKAgentAsync() var serviceCollection = new ServiceCollection(); serviceCollection.AddTransient((sp) - => new OpenAIResponseAgent(new OpenAIClient(apiKey).GetResponsesClient(model)) + => new OpenAIResponseAgent(new OpenAIClient(apiKey).GetResponsesClient(), model) { Name = "Joker", Instructions = "You are good at telling jokes." @@ -44,7 +44,7 @@ async Task SKAgent_As_AFAgentAsync() var serviceCollection = new ServiceCollection(); serviceCollection.AddTransient((sp) - => new OpenAIResponseAgent(new OpenAIClient(apiKey).GetResponsesClient(model)) + => new OpenAIResponseAgent(new OpenAIClient(apiKey).GetResponsesClient(), model) { Name = "Joker", Instructions = "You are good at telling jokes." @@ -65,7 +65,7 @@ async Task AFAgentAsync() var serviceCollection = new ServiceCollection(); serviceCollection.AddTransient((sp) => new OpenAIClient(apiKey) - .GetResponsesClient(model) + .GetResponsesClient().AsIChatClient(model) .CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes.")); await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider(); diff --git a/dotnet/samples/Demos/OpenAIRealtime/Program.cs b/dotnet/samples/Demos/OpenAIRealtime/Program.cs index 2de269dd1609..ce971fc32064 100644 --- a/dotnet/samples/Demos/OpenAIRealtime/Program.cs +++ b/dotnet/samples/Demos/OpenAIRealtime/Program.cs @@ -33,19 +33,22 @@ public static async Task Main(string[] args) kernel.ImportPluginFromType(); // Start a new conversation session. - using RealtimeSession session = await realtimeConversationClient.StartConversationSessionAsync("gpt-4o-realtime-preview"); + using RealtimeSessionClient session = await realtimeConversationClient.StartConversationSessionAsync("gpt-4o-realtime-preview"); // Initialize session options. // Session options control connection-wide behavior shared across all conversations, // including audio input format and voice activity detection settings. - ConversationSessionOptions sessionOptions = new() + RealtimeConversationSessionOptions sessionOptions = new() { - Voice = ConversationVoice.Alloy, - InputAudioFormat = RealtimeAudioFormat.Pcm16, - OutputAudioFormat = RealtimeAudioFormat.Pcm16, - InputTranscriptionOptions = new() + AudioOptions = new() { - Model = "whisper-1", + InputAudioOptions = new() + { + AudioTranscriptionOptions = new() + { + Model = "whisper-1", + }, + }, }, }; @@ -58,7 +61,7 @@ public static async Task Main(string[] args) // If any tools are available, set tool choice to "auto". if (sessionOptions.Tools.Count > 0) { - sessionOptions.ToolChoice = ConversationToolChoice.CreateAutoToolChoice(); + sessionOptions.ToolChoice = RealtimeDefaultToolChoice.Auto; } // Configure session with defined options. @@ -66,8 +69,8 @@ public static async Task Main(string[] args) // Items such as user, assistant, or system messages, as well as input audio, can be sent to the session. // An example of sending user message to the session. - // ConversationItem can be constructed from Microsoft.SemanticKernel.ChatMessageContent if needed by mapping the relevant fields. - await session.AddItemAsync(RealtimeItem.CreateUserMessage(["I'm trying to decide what to wear on my trip."])); + // RealtimeItem can be constructed from Microsoft.SemanticKernel.ChatMessageContent if needed by mapping the relevant fields. + await session.AddItemAsync(RealtimeItem.CreateUserMessageItem("I'm trying to decide what to wear on my trip.")); // Use audio file that contains a recorded question: "What's the weather like in San Francisco, California?" string inputAudioPath = FindFile("Assets\\realtime_whats_the_weather_pcm16_24khz_mono.wav"); @@ -81,115 +84,132 @@ public static async Task Main(string[] args) Dictionary functionArgumentBuildersById = []; // Define a loop to receive conversation updates in the session. - await foreach (RealtimeUpdate update in session.ReceiveUpdatesAsync()) + await foreach (RealtimeServerUpdate update in session.ReceiveUpdatesAsync()) { // Notification indicating the start of the conversation session. - if (update is ConversationSessionStartedUpdate sessionStartedUpdate) + if (update is RealtimeServerUpdateSessionCreated sessionStartedUpdate) { - Console.WriteLine($"<<< Session started. ID: {sessionStartedUpdate.SessionId}"); + Console.WriteLine($"<<< Session started. ID: {sessionStartedUpdate.EventId}"); Console.WriteLine(); } // Notification indicating the start of detected voice activity. - if (update is InputAudioSpeechStartedUpdate speechStartedUpdate) + if (update is RealtimeServerUpdateInputAudioBufferSpeechStarted speechStartedUpdate) { Console.WriteLine( $" -- Voice activity detection started at {speechStartedUpdate.AudioStartTime}"); } // Notification indicating the end of detected voice activity. - if (update is InputAudioSpeechFinishedUpdate speechFinishedUpdate) + if (update is RealtimeServerUpdateInputAudioBufferSpeechStopped speechFinishedUpdate) { Console.WriteLine( $" -- Voice activity detection ended at {speechFinishedUpdate.AudioEndTime}"); } // Notification indicating the start of item streaming, such as a function call or response message. - if (update is OutputStreamingStartedUpdate itemStreamingStartedUpdate) + if (update is RealtimeServerUpdateResponseOutputItemAdded itemStreamingStartedUpdate) { Console.WriteLine(" -- Begin streaming of new item"); - if (!string.IsNullOrEmpty(itemStreamingStartedUpdate.FunctionName)) + if (itemStreamingStartedUpdate.Item is RealtimeFunctionCallItem funcItem) { - Console.Write($" {itemStreamingStartedUpdate.FunctionName}: "); + Console.Write($" {funcItem.FunctionName}: "); } } - // Notification about item streaming delta, which may include audio transcript, audio bytes, or function arguments. - if (update is OutputDeltaUpdate deltaUpdate) + // Notification about audio transcript delta. + if (update is RealtimeServerUpdateResponseOutputAudioTranscriptDelta audioTranscriptDelta) { - Console.Write(deltaUpdate.AudioTranscript); - Console.Write(deltaUpdate.Text); - Console.Write(deltaUpdate.FunctionArguments); + Console.Write(audioTranscriptDelta.Delta); + } - // Handle audio bytes. - if (deltaUpdate.AudioBytes is not null) + // Notification about text delta. + if (update is RealtimeServerUpdateResponseOutputTextDelta textDelta) + { + Console.Write(textDelta.Delta); + } + + // Notification about audio bytes delta. + if (update is RealtimeServerUpdateResponseOutputAudioDelta audioDelta) + { + if (audioDelta.Delta is not null) { - if (!outputAudioStreamsById.TryGetValue(deltaUpdate.ItemId, out MemoryStream? value)) + if (!outputAudioStreamsById.TryGetValue(audioDelta.ItemId, out MemoryStream? value)) { value = new MemoryStream(); - outputAudioStreamsById[deltaUpdate.ItemId] = value; + outputAudioStreamsById[audioDelta.ItemId] = value; } - value.Write(deltaUpdate.AudioBytes); + value.Write(audioDelta.Delta.ToArray()); } + } - // Handle function arguments. - if (!functionArgumentBuildersById.TryGetValue(deltaUpdate.ItemId, out StringBuilder? arguments)) + // Notification about function call arguments delta. + if (update is RealtimeServerUpdateResponseFunctionCallArgumentsDelta funcArgsDelta) + { + if (!functionArgumentBuildersById.TryGetValue(funcArgsDelta.ItemId, out StringBuilder? arguments)) { - functionArgumentBuildersById[deltaUpdate.ItemId] = arguments = new(); + functionArgumentBuildersById[funcArgsDelta.ItemId] = arguments = new(); } - if (!string.IsNullOrWhiteSpace(deltaUpdate.FunctionArguments)) + if (funcArgsDelta.Delta is not null) { - arguments.Append(deltaUpdate.FunctionArguments); + arguments.Append(funcArgsDelta.Delta.ToString()); } } // Notification indicating the end of item streaming, such as a function call or response message. // At this point, audio transcript can be displayed on console, or a function can be called with aggregated arguments. - if (update is OutputStreamingFinishedUpdate itemStreamingFinishedUpdate) + if (update is RealtimeServerUpdateResponseOutputItemDone itemStreamingFinishedUpdate) { Console.WriteLine(); - Console.WriteLine($" -- Item streaming finished, item_id={itemStreamingFinishedUpdate.ItemId}"); + Console.WriteLine($" -- Item streaming finished, response_id={itemStreamingFinishedUpdate.ResponseId}"); // If an item is a function call, invoke a function with provided arguments. - if (itemStreamingFinishedUpdate.FunctionCallId is not null) + if (itemStreamingFinishedUpdate.Item is RealtimeFunctionCallItem functionCallItem) { - Console.WriteLine($" + Responding to tool invoked by item: {itemStreamingFinishedUpdate.FunctionName}"); + Console.WriteLine($" + Responding to tool invoked by item: {functionCallItem.FunctionName}"); // Parse function name. - var (functionName, pluginName) = ParseFunctionName(itemStreamingFinishedUpdate.FunctionName); + var (functionName, pluginName) = ParseFunctionName(functionCallItem.FunctionName); // Deserialize arguments. - var argumentsString = functionArgumentBuildersById[itemStreamingFinishedUpdate.ItemId].ToString(); + var argumentsString = functionArgumentBuildersById.TryGetValue(functionCallItem.Id, out var sb) ? sb.ToString() : "{}"; var arguments = DeserializeArguments(argumentsString); // Create a function call content based on received data. var functionCallContent = new FunctionCallContent( functionName: functionName, pluginName: pluginName, - id: itemStreamingFinishedUpdate.FunctionCallId, + id: functionCallItem.CallId, arguments: arguments); // Invoke a function. var resultContent = await functionCallContent.InvokeAsync(kernel); // Create a function call output conversation item with function call result. - RealtimeItem functionOutputItem = RealtimeItem.CreateFunctionCallOutput( - callId: itemStreamingFinishedUpdate.FunctionCallId, - output: ProcessFunctionResult(resultContent.Result)); + RealtimeItem functionOutputItem = RealtimeItem.CreateFunctionCallOutputItem( + callId: functionCallItem.CallId, + functionOutput: ProcessFunctionResult(resultContent.Result)); // Send function call output conversation item to the session, so the model can use it for further processing. await session.AddItemAsync(functionOutputItem); } // If an item is a response message, output it to the console. - else if (itemStreamingFinishedUpdate.MessageContentParts?.Count > 0) + else if (itemStreamingFinishedUpdate.Item is RealtimeMessageItem messageItem && messageItem.Content?.Count > 0) { - Console.Write($" + [{itemStreamingFinishedUpdate.MessageRole}]: "); + Console.Write($" + [{messageItem.Role}]: "); - foreach (ConversationContentPart contentPart in itemStreamingFinishedUpdate.MessageContentParts) + foreach (RealtimeMessageContentPart contentPart in messageItem.Content) { - Console.Write(contentPart.AudioTranscript); + if (contentPart is RealtimeOutputAudioMessageContentPart audioContentPart) + { + Console.Write(audioContentPart.Transcript); + } + else if (contentPart is RealtimeOutputTextMessageContentPart textContentPart) + { + Console.Write(textContentPart.Text); + } } Console.WriteLine(); @@ -197,7 +217,7 @@ public static async Task Main(string[] args) } // Notification indicating the completion of transcription from input audio. - if (update is InputAudioTranscriptionFinishedUpdate transcriptionCompletedUpdate) + if (update is RealtimeServerUpdateConversationItemInputAudioTranscriptionCompleted transcriptionCompletedUpdate) { Console.WriteLine(); Console.WriteLine($" -- User audio transcript: {transcriptionCompletedUpdate.Transcript}"); @@ -205,13 +225,13 @@ public static async Task Main(string[] args) } // Notification about completed model response turn. - if (update is ResponseFinishedUpdate turnFinishedUpdate) + if (update is RealtimeServerUpdateResponseDone turnFinishedUpdate) { - Console.WriteLine($" -- Model turn generation finished. Status: {turnFinishedUpdate.Status}"); + Console.WriteLine($" -- Model turn generation finished. Status: {turnFinishedUpdate.Response?.Status}"); - // If the created session items contain a function name, it indicates a function call result has been provided, + // If the output items contain a function call, it indicates a function call result has been provided, // and response updates can begin. - if (turnFinishedUpdate.CreatedItems.Any(item => item.FunctionName?.Length > 0)) + if (turnFinishedUpdate.Response?.OutputItems?.Any(item => item is RealtimeFunctionCallItem) == true) { Console.WriteLine(" -- Ending client turn for pending tool responses"); @@ -225,10 +245,10 @@ public static async Task Main(string[] args) } // Notification about error in conversation session. - if (update is RealtimeErrorUpdate errorUpdate) + if (update is RealtimeServerUpdateError errorUpdate) { Console.WriteLine(); - Console.WriteLine($"ERROR: {errorUpdate.Message}"); + Console.WriteLine($"ERROR: {errorUpdate.Error?.Message}"); break; } } @@ -337,7 +357,7 @@ private static (string FunctionName, string? PluginName) ParseFunctionName(strin } /// Helper method to convert Kernel plugins/function to realtime session conversation tools. - private static IEnumerable ConvertFunctions(Kernel kernel) + private static IEnumerable ConvertFunctions(Kernel kernel) { foreach (var plugin in kernel.Plugins) { @@ -347,10 +367,10 @@ private static IEnumerable ConvertFunctions(Kernel kernel) { var toolDefinition = metadata.ToOpenAIFunction().ToFunctionDefinition(false); - yield return new ConversationFunctionTool(name: toolDefinition.FunctionName) + yield return new RealtimeFunctionTool(functionName: toolDefinition.FunctionName) { - Description = toolDefinition.FunctionDescription, - Parameters = toolDefinition.FunctionParameters + FunctionDescription = toolDefinition.FunctionDescription, + FunctionParameters = toolDefinition.FunctionParameters }; } } diff --git a/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step01_OpenAIResponseAgent.cs b/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step01_OpenAIResponseAgent.cs index dd2c52ef3c97..87f661e3d2f1 100644 --- a/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step01_OpenAIResponseAgent.cs +++ b/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step01_OpenAIResponseAgent.cs @@ -15,7 +15,7 @@ public class Step01_OpenAIResponseAgent(ITestOutputHelper output) : BaseResponse public async Task UseOpenAIResponseAgentAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { Name = "ResponseAgent", Instructions = "Answer all queries in English and French.", @@ -33,7 +33,7 @@ public async Task UseOpenAIResponseAgentAsync() public async Task UseOpenAIResponseAgentStreamingAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { Name = "ResponseAgent", Instructions = "Answer all queries in English and French.", @@ -48,7 +48,7 @@ public async Task UseOpenAIResponseAgentStreamingAsync() public async Task UseOpenAIResponseAgentWithThreadedConversationAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { Name = "ResponseAgent", Instructions = "Answer all queries in the users preferred language.", @@ -84,7 +84,7 @@ public async Task UseOpenAIResponseAgentWithThreadedConversationAsync() public async Task UseOpenAIResponseAgentWithThreadedConversationStreamingAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { Name = "ResponseAgent", Instructions = "Answer all queries in the users preferred language.", @@ -116,7 +116,7 @@ public async Task UseOpenAIResponseAgentWithThreadedConversationStreamingAsync() public async Task UseOpenAIResponseAgentWithImageContentAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { Name = "ResponseAgent", Instructions = "Provide a detailed description including the weather conditions.", diff --git a/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step02_OpenAIResponseAgent_ConversationState.cs b/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step02_OpenAIResponseAgent_ConversationState.cs index 3f5c9a31d7a1..c14c0faa0353 100644 --- a/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step02_OpenAIResponseAgent_ConversationState.cs +++ b/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step02_OpenAIResponseAgent_ConversationState.cs @@ -18,7 +18,7 @@ public class Step02_OpenAIResponseAgent_ConversationState(ITestOutputHelper outp public async Task ManuallyConstructPastConversationAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { StoreEnabled = false, }; @@ -46,7 +46,7 @@ public async Task ManuallyConstructPastConversationAsync() public async Task ManuallyConstructPastConversationStreamingAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { StoreEnabled = false, }; @@ -75,7 +75,7 @@ public async Task ManuallyConstructPastConversationStreamingAsync() public async Task ManageConversationStateWithResponseIdAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { StoreEnabled = false, }; @@ -106,7 +106,7 @@ public async Task ManageConversationStateWithResponseIdAsync() public async Task ManageConversationStateWithResponseIdStreamingAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { StoreEnabled = false, }; @@ -138,7 +138,7 @@ public async Task ManageConversationStateWithResponseIdStreamingAsync() public async Task StoreConversationStateAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { StoreEnabled = true, }; @@ -186,7 +186,7 @@ public async Task StoreConversationStateAsync() public async Task StoreConversationStateWithStreamingAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { StoreEnabled = true, }; diff --git a/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step03_OpenAIResponseAgent_ReasoningModel.cs b/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step03_OpenAIResponseAgent_ReasoningModel.cs index 7db3ecc847bf..59c2171a3826 100644 --- a/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step03_OpenAIResponseAgent_ReasoningModel.cs +++ b/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step03_OpenAIResponseAgent_ReasoningModel.cs @@ -15,7 +15,7 @@ public class Step03_OpenAIResponseAgent_ReasoningModel(ITestOutputHelper output) public async Task UseOpenAIResponseAgentWithAReasoningModelAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { Name = "ResponseAgent", Instructions = "Answer all queries with a detailed response.", @@ -33,7 +33,7 @@ public async Task UseOpenAIResponseAgentWithAReasoningModelAsync() public async Task UseOpenAIResponseAgentWithAReasoningModelAndSummariesAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client); + OpenAIResponseAgent agent = new(this.Client, this.ModelId); // ResponseCreationOptions allows you to specify tools for the agent. OpenAIResponseAgentInvokeOptions invokeOptions = new() @@ -86,7 +86,7 @@ exceed 80 columns public async Task UseOpenAIResponseAgentWithAReasoningModelAndToolsAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { Name = "ResponseAgent", Instructions = "Answer all queries with a detailed response.", diff --git a/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step04_OpenAIResponseAgent_Tools.cs b/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step04_OpenAIResponseAgent_Tools.cs index d2897430a478..80230c93cdd6 100644 --- a/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step04_OpenAIResponseAgent_Tools.cs +++ b/dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step04_OpenAIResponseAgent_Tools.cs @@ -22,7 +22,7 @@ public class Step04_OpenAIResponseAgent_Tools(ITestOutputHelper output) : BaseRe public async Task InvokeAgentWithFunctionToolsAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { StoreEnabled = false, }; @@ -53,7 +53,7 @@ public async Task InvokeAgentWithFunctionToolsAsync() public async Task InvokeAgentWithWebSearchAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { StoreEnabled = false, }; @@ -89,7 +89,7 @@ public async Task InvokeAgentWithFileSearchAsync() }); // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { StoreEnabled = false, }; @@ -131,7 +131,7 @@ public async Task InvokeAgentWithFileSearchAsync() public async Task InvokeAgentWithMultipleToolsAsync() { // Define the agent - OpenAIResponseAgent agent = new(this.Client) + OpenAIResponseAgent agent = new(this.Client, this.ModelId) { StoreEnabled = false, }; diff --git a/dotnet/src/Agents/OpenAI/Extensions/KernelContentExtensions.cs b/dotnet/src/Agents/OpenAI/Extensions/KernelContentExtensions.cs index 59f11f0f68cd..4be9d36f5031 100644 --- a/dotnet/src/Agents/OpenAI/Extensions/KernelContentExtensions.cs +++ b/dotnet/src/Agents/OpenAI/Extensions/KernelContentExtensions.cs @@ -29,11 +29,18 @@ internal static ResponseContentPart ToResponseContentPart(this TextContent conte internal static ResponseContentPart ToResponseContentPart(this ImageContent content) { - return content.Uri is not null - ? ResponseContentPart.CreateInputImagePart(content.Uri) - : content.Data is not null - ? ResponseContentPart.CreateInputImagePart(new BinaryData(content.Data), content.MimeType) - : throw new NotSupportedException("ImageContent cannot be converted to ResponseContentPart. Only ImageContent with a uri or binary data is supported."); + if (content.Uri is not null) + { + return ResponseContentPart.CreateInputImagePart(content.Uri); + } + + if (content.Data is not null) + { + var dataUri = new Uri($"data:{content.MimeType};base64,{Convert.ToBase64String(content.Data.Value.ToArray())}"); + return ResponseContentPart.CreateInputImagePart(dataUri); + } + + throw new NotSupportedException("ImageContent cannot be converted to ResponseContentPart. Only ImageContent with a uri or binary data is supported."); } internal static ResponseContentPart ToResponseContentPart(this BinaryContent content) diff --git a/dotnet/src/Agents/OpenAI/Internal/ResponseCreationOptionsFactory.cs b/dotnet/src/Agents/OpenAI/Internal/ResponseCreationOptionsFactory.cs index 0a49bb66e172..4a9fd3f7e51a 100644 --- a/dotnet/src/Agents/OpenAI/Internal/ResponseCreationOptionsFactory.cs +++ b/dotnet/src/Agents/OpenAI/Internal/ResponseCreationOptionsFactory.cs @@ -23,6 +23,7 @@ internal static CreateResponseOptions CreateOptions( { creationOptions = new CreateResponseOptions { + Model = responseAgentInvokeOptions.ResponseCreationOptions.Model ?? agent.ModelId, EndUserId = responseAgentInvokeOptions.ResponseCreationOptions.EndUserId ?? agent.GetDisplayName(), Instructions = responseAgentInvokeOptions.ResponseCreationOptions.Instructions ?? instructions, StoredOutputEnabled = responseAgentInvokeOptions.ResponseCreationOptions.StoredOutputEnabled ?? agent.StoreEnabled, @@ -44,6 +45,7 @@ internal static CreateResponseOptions CreateOptions( { creationOptions = new CreateResponseOptions { + Model = agent.ModelId, EndUserId = agent.GetDisplayName(), Instructions = instructions, StoredOutputEnabled = agent.StoreEnabled, diff --git a/dotnet/src/Agents/OpenAI/OpenAIResponseAgent.cs b/dotnet/src/Agents/OpenAI/OpenAIResponseAgent.cs index 02dcd57d85e1..e09b89708375 100644 --- a/dotnet/src/Agents/OpenAI/OpenAIResponseAgent.cs +++ b/dotnet/src/Agents/OpenAI/OpenAIResponseAgent.cs @@ -22,11 +22,13 @@ public sealed class OpenAIResponseAgent : Agent /// Initializes a new instance of the class. /// /// The OpenAI provider for accessing the Responses API service. - public OpenAIResponseAgent(ResponsesClient client) + /// The model to use for generating responses. + public OpenAIResponseAgent(ResponsesClient client, string? modelId = null) { Verify.NotNull(client); this.Client = client; + this.ModelId = modelId; } /// @@ -34,6 +36,11 @@ public OpenAIResponseAgent(ResponsesClient client) /// public ResponsesClient Client { get; } + /// + /// The model to use for generating responses. + /// + public string? ModelId { get; init; } + /// /// Storing of messages is enabled. /// diff --git a/dotnet/src/Agents/UnitTests/OpenAI/BaseOpenAIResponseClientTest.cs b/dotnet/src/Agents/UnitTests/OpenAI/BaseOpenAIResponseClientTest.cs index e4408047a62d..e9c81b1e374e 100644 --- a/dotnet/src/Agents/UnitTests/OpenAI/BaseOpenAIResponseClientTest.cs +++ b/dotnet/src/Agents/UnitTests/OpenAI/BaseOpenAIResponseClientTest.cs @@ -27,7 +27,7 @@ internal BaseOpenAIResponseClientTest() { Transport = new HttpClientPipelineTransport(this.HttpClient) }; - this.Client = new ResponsesClient("model", new ApiKeyCredential("apiKey"), clientOptions); + this.Client = new ResponsesClient(new ApiKeyCredential("apiKey"), clientOptions); } /// diff --git a/dotnet/src/Agents/UnitTests/OpenAI/Extensions/OpenAIResponseExtensionsTests.cs b/dotnet/src/Agents/UnitTests/OpenAI/Extensions/OpenAIResponseExtensionsTests.cs index d8a90a80a2cd..69ec60ab6995 100644 --- a/dotnet/src/Agents/UnitTests/OpenAI/Extensions/OpenAIResponseExtensionsTests.cs +++ b/dotnet/src/Agents/UnitTests/OpenAI/Extensions/OpenAIResponseExtensionsTests.cs @@ -238,14 +238,13 @@ private ResponseResult CreateMockOpenAIResponse(string model, IEnumerable tools, float topP, IDictionary metadata, ResponseIncompleteStatusDetails incompleteStatusDetails, IEnumerable outputItems, bool parallelToolCallsEnabled, ResponseToolChoice toolChoice) + private ResponseResult CreateMockOpenAIResponse(string id, DateTimeOffset createdAt, ResponseError error, string model, string previousResponseId, float temperature, IEnumerable tools, float topP, IDictionary metadata, ResponseIncompleteStatusDetails incompleteStatusDetails, IEnumerable outputItems, bool parallelToolCallsEnabled, ResponseToolChoice toolChoice) { var result = new ResponseResult { Id = id, CreatedAt = createdAt, Error = error, - Instructions = instructions, Model = model, PreviousResponseId = previousResponseId, Temperature = temperature, diff --git a/dotnet/src/Agents/UnitTests/OpenAI/OpenAIResponseAgentExtensionsTests.cs b/dotnet/src/Agents/UnitTests/OpenAI/OpenAIResponseAgentExtensionsTests.cs index f4ea33a3ea9b..8f124b33a49f 100644 --- a/dotnet/src/Agents/UnitTests/OpenAI/OpenAIResponseAgentExtensionsTests.cs +++ b/dotnet/src/Agents/UnitTests/OpenAI/OpenAIResponseAgentExtensionsTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using System; +using System.ClientModel; using System.Text.Json; using Microsoft.SemanticKernel.Agents; using Microsoft.SemanticKernel.Agents.OpenAI; @@ -16,7 +17,7 @@ public sealed class OpenAIResponseAgentExtensionsTests public void AsAIAgent_WithValidOpenAIResponseAgent_ReturnsSemanticKernelAIAgent() { // Arrange - var responseClient = new ResponsesClient("model", "apikey"); + var responseClient = new ResponsesClient(new ApiKeyCredential("apikey")); var responseAgent = new OpenAIResponseAgent(responseClient); // Act @@ -41,7 +42,7 @@ public void AsAIAgent_WithNullOpenAIResponseAgent_ThrowsArgumentNullException() public void AsAIAgent_CreatesWorkingThreadFactoryStoreTrue() { // Arrange - var responseClient = new ResponsesClient("model", "apikey"); + var responseClient = new ResponsesClient(new ApiKeyCredential("apikey")); var responseAgent = new OpenAIResponseAgent(responseClient) { StoreEnabled = true @@ -62,7 +63,7 @@ public void AsAIAgent_CreatesWorkingThreadFactoryStoreTrue() public void AsAIAgent_CreatesWorkingThreadFactoryStoreFalse() { // Arrange - var responseClient = new ResponsesClient("model", "apikey"); + var responseClient = new ResponsesClient(new ApiKeyCredential("apikey")); var responseAgent = new OpenAIResponseAgent(responseClient) { StoreEnabled = false @@ -83,7 +84,7 @@ public void AsAIAgent_CreatesWorkingThreadFactoryStoreFalse() public void AsAIAgent_ThreadDeserializationFactory_WithNullAgentId_CreatesNewThread() { // Arrange - var responseClient = new ResponsesClient("model", "apikey"); + var responseClient = new ResponsesClient(new ApiKeyCredential("apikey")); var responseAgent = new OpenAIResponseAgent(responseClient) { StoreEnabled = true @@ -105,7 +106,7 @@ public void AsAIAgent_ThreadDeserializationFactory_WithNullAgentId_CreatesNewThr public void AsAIAgent_ThreadDeserializationFactory_WithValidAgentId_CreatesThreadWithId() { // Arrange - var responseClient = new ResponsesClient("model", "apikey"); + var responseClient = new ResponsesClient(new ApiKeyCredential("apikey")); var responseAgent = new OpenAIResponseAgent(responseClient) { StoreEnabled = true @@ -129,7 +130,7 @@ public void AsAIAgent_ThreadDeserializationFactory_WithValidAgentId_CreatesThrea public void AsAIAgent_ThreadSerializer_SerializesThreadId() { // Arrange - var responseClient = new ResponsesClient("model", "apikey"); + var responseClient = new ResponsesClient(new ApiKeyCredential("apikey")); var responseAgent = new OpenAIResponseAgent(responseClient) { StoreEnabled = true @@ -152,7 +153,7 @@ public void AsAIAgent_ThreadSerializer_SerializesThreadId() [Fact] public void AsAIAgent_ThreadDeserializationFactory_WithNullJson_CreatesThreadWithEmptyChatHistory() { - var responseClient = new ResponsesClient("model", "apikey"); + var responseClient = new ResponsesClient(new ApiKeyCredential("apikey")); var responseAgent = new OpenAIResponseAgent(responseClient); var jsonElement = JsonSerializer.SerializeToElement((string?)null); @@ -171,7 +172,7 @@ public void AsAIAgent_ThreadDeserializationFactory_WithNullJson_CreatesThreadWit [Fact] public void AsAIAgent_ThreadDeserializationFactory_WithChatHistory_CreatesThreadWithChatHistory() { - var responseClient = new ResponsesClient("model", "apikey"); + var responseClient = new ResponsesClient(new ApiKeyCredential("apikey")); var responseAgent = new OpenAIResponseAgent(responseClient); var expectedChatHistory = new ChatHistory("mock message", AuthorRole.User); var jsonElement = JsonSerializer.SerializeToElement(expectedChatHistory); @@ -195,7 +196,7 @@ public void AsAIAgent_ThreadDeserializationFactory_WithChatHistory_CreatesThread public void AsAIAgent_ThreadSerializer_SerializesChatHistory() { // Arrange - var responseClient = new ResponsesClient("model", "apikey"); + var responseClient = new ResponsesClient(new ApiKeyCredential("apikey")); var responseAgent = new OpenAIResponseAgent(responseClient); var expectedChatHistory = new ChatHistory("mock message", AuthorRole.User); var jsonElement = JsonSerializer.SerializeToElement(expectedChatHistory); diff --git a/dotnet/src/Connectors/Connectors.OpenAI/Core/ClientCore.TextToImage.cs b/dotnet/src/Connectors/Connectors.OpenAI/Core/ClientCore.TextToImage.cs index 33b18f30def2..049f31b8c883 100644 --- a/dotnet/src/Connectors/Connectors.OpenAI/Core/ClientCore.TextToImage.cs +++ b/dotnet/src/Connectors/Connectors.OpenAI/Core/ClientCore.TextToImage.cs @@ -122,8 +122,8 @@ internal async Task> GetImageContentsAsync( { "STANDARD" => GeneratedImageQuality.Standard, "HIGH" or "HD" => GeneratedImageQuality.High, - "MEDIUM" => GeneratedImageQuality.Medium, - "LOW" => GeneratedImageQuality.Low, + "MEDIUM" => GeneratedImageQuality.MediumQuality, + "LOW" => GeneratedImageQuality.LowQuality, "AUTO" => GeneratedImageQuality.Auto, _ => throw new NotSupportedException($"The provided quality '{quality}' is not supported.") }; diff --git a/dotnet/src/IntegrationTests/Agents/CommonInterfaceConformance/OpenAIResponseAgentFixture.cs b/dotnet/src/IntegrationTests/Agents/CommonInterfaceConformance/OpenAIResponseAgentFixture.cs index b0151d639088..1e00fd205342 100644 --- a/dotnet/src/IntegrationTests/Agents/CommonInterfaceConformance/OpenAIResponseAgentFixture.cs +++ b/dotnet/src/IntegrationTests/Agents/CommonInterfaceConformance/OpenAIResponseAgentFixture.cs @@ -95,12 +95,12 @@ public override async Task InitializeAsync() { OpenAIConfiguration configuration = this._configuration.GetSection("OpenAI").Get()!; var options = new OpenAIClientOptions(); - this._responseClient = new(model: configuration.ChatModelId, credential: new ApiKeyCredential(configuration.ApiKey), options: options); + this._responseClient = new(credential: new ApiKeyCredential(configuration.ApiKey), options: options); var kernelBuilder = Kernel.CreateBuilder(); Kernel kernel = kernelBuilder.Build(); - this._agent = new OpenAIResponseAgent(this._responseClient) + this._agent = new OpenAIResponseAgent(this._responseClient, configuration.ChatModelId) { Name = "HelpfulAssistant", Instructions = "You are a helpful assistant.", @@ -109,10 +109,10 @@ public override async Task InitializeAsync() }; this._thread = new OpenAIResponseAgentThread(this._responseClient); - var response = await this._responseClient.CreateResponseAsync([ResponseItem.CreateUserMessageItem("Hello")]); + var response = await this._responseClient.CreateResponseAsync(new CreateResponseOptions(configuration.ChatModelId, [ResponseItem.CreateUserMessageItem("Hello")])); this._createdThread = new OpenAIResponseAgentThread(this._responseClient, response.Value.Id); - var serviceFailingClient = new ResponsesClient(configuration.ModelId, credential: new ApiKeyCredential("FakeApiKey"), options: options); + var serviceFailingClient = new ResponsesClient(credential: new ApiKeyCredential("FakeApiKey"), options: options); this._serviceFailingAgentThread = new OpenAIResponseAgentThread(serviceFailingClient); this._createdServiceFailingAgentThread = new OpenAIResponseAgentThread(this._responseClient, "FakeId"); diff --git a/dotnet/src/IntegrationTests/Agents/OpenAIResponseAgentTests.cs b/dotnet/src/IntegrationTests/Agents/OpenAIResponseAgentTests.cs index 8fab795524d7..a0379a11a248 100644 --- a/dotnet/src/IntegrationTests/Agents/OpenAIResponseAgentTests.cs +++ b/dotnet/src/IntegrationTests/Agents/OpenAIResponseAgentTests.cs @@ -43,10 +43,11 @@ public sealed class OpenAIResponseAgentTests(ITestOutputHelper output) [InlineData("What is the capital of France?", "Paris", false, false)] public async Task OpenAIResponseAgentInvokeAsync(string input, string expectedAnswerContains, bool isOpenAI, bool storeEnabled) { - ResponsesClient client = this.CreateClient(isOpenAI); + var (client, modelId) = this.CreateClient(isOpenAI); await this.ExecuteAgentAsync( client, + modelId, storeEnabled, input, expectedAnswerContains); @@ -63,8 +64,8 @@ await this.ExecuteAgentAsync( public async Task OpenAIResponseAgentInvokeWithThreadAsync(string input, string expectedAnswerContains, bool isOpenAI, bool storeEnabled) { // Arrange - ResponsesClient client = this.CreateClient(isOpenAI); - OpenAIResponseAgent agent = new(client) + var (client, modelId) = this.CreateClient(isOpenAI); + OpenAIResponseAgent agent = new(client, modelId) { StoreEnabled = storeEnabled, Instructions = "Answer all queries in English and French." @@ -112,9 +113,9 @@ public async Task OpenAIResponseAgentInvokeWithThreadAsync(string input, string public async Task OpenAIResponseAgentInvokeWithFunctionCallingAsync(string input, string expectedAnswerContains, bool isOpenAI, bool storeEnabled) { // Arrange - ResponsesClient client = this.CreateClient(isOpenAI); + var (client, modelId) = this.CreateClient(isOpenAI); KernelPlugin plugin = KernelPluginFactory.CreateFromType(); - OpenAIResponseAgent agent = new(client) + OpenAIResponseAgent agent = new(client, modelId) { StoreEnabled = storeEnabled, Instructions = "Answer questions about the menu." @@ -161,10 +162,11 @@ public async Task OpenAIResponseAgentInvokeWithFunctionCallingAsync(string input [InlineData("What is the capital of France?", "Paris", false, false)] public async Task OpenAIResponseAgentInvokeStreamingAsync(string input, string expectedAnswerContains, bool isOpenAI, bool storeEnabled) { - ResponsesClient client = this.CreateClient(isOpenAI); + var (client, modelId) = this.CreateClient(isOpenAI); await this.ExecuteStreamingAgentAsync( client, + modelId, storeEnabled, input, expectedAnswerContains); @@ -181,8 +183,8 @@ await this.ExecuteStreamingAgentAsync( public async Task OpenAIResponseAgentInvokeStreamingWithThreadAsync(bool isOpenAI, bool storeEnabled) { // Arrange - ResponsesClient client = this.CreateClient(isOpenAI); - OpenAIResponseAgent agent = new(client) + var (client, modelId) = this.CreateClient(isOpenAI); + OpenAIResponseAgent agent = new(client, modelId) { StoreEnabled = storeEnabled, Instructions = "Answer all queries in English and French." @@ -229,9 +231,9 @@ public async Task OpenAIResponseAgentInvokeStreamingWithThreadAsync(bool isOpenA public async Task OpenAIResponseAgentInvokeStreamingWithFunctionCallingAsync(string input, string expectedAnswerContains, bool isOpenAI, bool storeEnabled) { // Arrange - ResponsesClient client = this.CreateClient(isOpenAI); + var (client, modelId) = this.CreateClient(isOpenAI); KernelPlugin plugin = KernelPluginFactory.CreateFromType(); - OpenAIResponseAgent agent = new(client) + OpenAIResponseAgent agent = new(client, modelId) { StoreEnabled = storeEnabled, Instructions = "Answer questions about the menu." @@ -274,12 +276,13 @@ public async Task OpenAIResponseAgentInvokeStreamingWithFunctionCallingAsync(str private async Task ExecuteAgentAsync( ResponsesClient client, + string modelId, bool storeEnabled, string input, string expected) { // Arrange - OpenAIResponseAgent agent = new(client) + OpenAIResponseAgent agent = new(client, modelId) { StoreEnabled = storeEnabled, Instructions = "Answer all queries in English and French." @@ -306,12 +309,13 @@ private async Task ExecuteAgentAsync( private async Task ExecuteStreamingAgentAsync( ResponsesClient client, + string modelId, bool storeEnabled, string input, string expected) { // Arrange - OpenAIResponseAgent agent = new(client) + OpenAIResponseAgent agent = new(client, modelId) { StoreEnabled = storeEnabled, Instructions = "Answer all queries in English and French." @@ -355,22 +359,17 @@ private OpenAIConfiguration ReadConfiguration() return configuration; } - private ResponsesClient CreateClient(bool isOpenAI) + private (ResponsesClient Client, string ModelId) CreateClient(bool isOpenAI) { - ResponsesClient client; if (isOpenAI) { - client = this.CreateClient(this._configuration.GetSection("OpenAI").Get()); - } - else - { - client = this.CreateClient(this._configuration.GetSection("AzureOpenAI").Get()); + return this.CreateClient(this._configuration.GetSection("OpenAI").Get()); } - return client; + return this.CreateClient(this._configuration.GetSection("AzureOpenAI").Get()); } - private ResponsesClient CreateClient(OpenAIConfiguration? configuration) + private (ResponsesClient, string) CreateClient(OpenAIConfiguration? configuration) { Assert.NotNull(configuration); @@ -387,10 +386,10 @@ private ResponsesClient CreateClient(OpenAIConfiguration? configuration) }; } - return new ResponsesClient(configuration.ChatModelId, new ApiKeyCredential(configuration.ApiKey), options); + return (new ResponsesClient(new ApiKeyCredential(configuration.ApiKey), options), configuration.ChatModelId!); } - private ResponsesClient CreateClient(AzureOpenAIConfiguration? configuration) + private (ResponsesClient, string) CreateClient(AzureOpenAIConfiguration? configuration) { Assert.NotNull(configuration); @@ -408,7 +407,7 @@ private ResponsesClient CreateClient(AzureOpenAIConfiguration? configuration) } var azureClient = new AzureOpenAIClient(new Uri(configuration.Endpoint), new AzureCliCredential(), options); - return azureClient.GetResponsesClient(configuration.ChatDeploymentName); + return (azureClient.GetResponsesClient(), configuration.ChatDeploymentName!); } public sealed class MenuPlugin diff --git a/dotnet/src/InternalUtilities/samples/AgentUtilities/BaseResponsesAgentTest.cs b/dotnet/src/InternalUtilities/samples/AgentUtilities/BaseResponsesAgentTest.cs index 13a763cac459..db47336631ff 100644 --- a/dotnet/src/InternalUtilities/samples/AgentUtilities/BaseResponsesAgentTest.cs +++ b/dotnet/src/InternalUtilities/samples/AgentUtilities/BaseResponsesAgentTest.cs @@ -27,11 +27,14 @@ protected BaseResponsesAgentTest(ITestOutputHelper output, string? model = null) }); } - this.Client = new(model: model ?? TestConfiguration.OpenAI.ChatModelId, credential: new ApiKeyCredential(TestConfiguration.OpenAI.ApiKey), options: options); + this.ModelId = model ?? TestConfiguration.OpenAI.ChatModelId; + this.Client = new(credential: new ApiKeyCredential(TestConfiguration.OpenAI.ApiKey), options: options); this.FileClient = new OpenAIFileClient(TestConfiguration.OpenAI.ApiKey); this.VectorStoreClient = new VectorStoreClient(TestConfiguration.OpenAI.ApiKey); } + protected string ModelId { get; set; } + protected OpenAIFileClient FileClient { get; set; } protected VectorStoreClient VectorStoreClient { get; set; }