From 0e922de9be666e4a02fcdc9c009b5a989be796f3 Mon Sep 17 00:00:00 2001
From: markwallace-microsoft
<127216156+markwallace-microsoft@users.noreply.github.com>
Date: Fri, 9 Jan 2026 11:43:37 +0000
Subject: [PATCH 1/8] Declarative support for AzureAI Persistent agents
---
.../CodeInterpreterToolExtensions.cs | 64 ++++++
.../Extensions/FileSearchToolExtensions.cs | 67 +++++++
.../Extensions/FunctionToolExtensions.cs | 67 +++++++
.../HostedCodeInterpreterToolExtensions.cs | 24 +++
.../HostedFileSearchToolExtensions.cs | 25 +++
.../HostedMcpServerToolExtensions.cs | 28 +++
.../HostedWebSearchToolExtensions.cs | 26 +++
.../Extensions/McpServerToolExtensions.cs | 53 +++++
.../Extensions/PromptAgentExtensions.cs | 142 ++++++++++++++
.../Extensions/RecordDataTypeExtensions.cs | 45 +++++
.../Extensions/RecordDataValueExtensions.cs | 39 ++++
.../Extensions/WebSearchToolExtensions.cs | 38 ++++
.../FoundryAgentFactory.cs | 111 +++++++++++
.../FoundryPersistentAgentFactory.cs | 94 +++++++++
.../JsonSchemaFunctionParameters.cs | 32 +++
...s.AI.Declarative.AzureAI.Persistent.csproj | 52 +++++
.../OpenAIAgentFactory.cs | 183 ++++++++++++++++++
.../OpenAIAssistantAgentFactory.cs | 92 +++++++++
.../OpenAIChatAgentFactory.cs | 85 ++++++++
.../OpenAIResponseAgentFactory.cs | 85 ++++++++
20 files changed, 1352 insertions(+)
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/CodeInterpreterToolExtensions.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FileSearchToolExtensions.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FunctionToolExtensions.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedCodeInterpreterToolExtensions.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedFileSearchToolExtensions.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedMcpServerToolExtensions.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedWebSearchToolExtensions.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/McpServerToolExtensions.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/PromptAgentExtensions.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataTypeExtensions.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataValueExtensions.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/WebSearchToolExtensions.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryAgentFactory.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryPersistentAgentFactory.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/JsonSchemaFunctionParameters.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Microsoft.Agents.AI.Declarative.AzureAI.Persistent.csproj
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAgentFactory.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAssistantAgentFactory.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIChatAgentFactory.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIResponseAgentFactory.cs
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/CodeInterpreterToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/CodeInterpreterToolExtensions.cs
new file mode 100644
index 0000000000..e45fe4c5e5
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/CodeInterpreterToolExtensions.cs
@@ -0,0 +1,64 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Collections.Generic;
+using System.Linq;
+using Azure.AI.Agents.Persistent;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Bot.ObjectModel;
+
+///
+/// Extension methods for .
+///
+internal static class CodeInterpreterToolExtensions
+{
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+ internal static CodeInterpreterToolDefinition CreateCodeInterpreterToolDefinition(this CodeInterpreterTool tool)
+ {
+ Throw.IfNull(tool);
+
+ return new CodeInterpreterToolDefinition();
+ }
+
+ ///
+ /// Converts a to an .
+ ///
+ /// Instance of
+ /// A new instance configured with the container ID from the tool's extension data.
+ internal static OpenAI.Responses.CodeInterpreterTool CreateCodeInterpreterTool(this CodeInterpreterTool tool)
+ {
+ Throw.IfNull(tool);
+
+ var containerId = tool.ExtensionData?.GetPropertyOrNull(InitializablePropertyPath.Create("containerId"))?.Value;
+ Throw.IfNull(containerId, "The 'containerId' property must be specified in the CodeInterpreterTool's extension data to create a code interpreter tool.");
+
+ return new OpenAI.Responses.CodeInterpreterTool(new OpenAI.Responses.CodeInterpreterToolContainer(containerId));
+ }
+
+ ///
+ /// Collects the file IDs from the extension data of a .
+ ///
+ /// Instance of
+ internal static List? GetFileIds(this CodeInterpreterTool tool)
+ {
+ var fileIds = tool.ExtensionData?.GetPropertyOrNull(InitializablePropertyPath.Create("fileIds"));
+ return fileIds is not null
+ ? [.. fileIds.Values.Select(fileId => fileId.GetPropertyOrNull(InitializablePropertyPath.Create("value"))?.Value)]
+ : null;
+ }
+
+ ///
+ /// Collects the data sources from the extension data of a .
+ ///
+ /// Instance of
+ internal static List? GetDataSources(this CodeInterpreterTool tool)
+ {
+ var dataSources = tool.ExtensionData?.GetPropertyOrNull(InitializablePropertyPath.Create("dataSources"));
+ return dataSources is not null
+ ? dataSources.Values.Select(dataSource => dataSource.CreateDataSource()).ToList()
+ : null;
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FileSearchToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FileSearchToolExtensions.cs
new file mode 100644
index 0000000000..e582672f93
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FileSearchToolExtensions.cs
@@ -0,0 +1,67 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Collections.Generic;
+using System.Linq;
+using Azure.AI.Agents.Persistent;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Bot.ObjectModel;
+
+///
+/// Extension methods for .
+///
+internal static class FileSearchToolExtensions
+{
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+ internal static FileSearchToolDefinition CreateFileSearchToolDefinition(this FileSearchTool tool)
+ {
+ Throw.IfNull(tool);
+
+ // TODO: Add support for FileSearchToolDefinitionDetails.
+
+ return new FileSearchToolDefinition();
+ }
+
+ ///
+ /// Creates an from a .
+ ///
+ /// Instance of
+ /// A new instance configured with the vector store IDs.
+ internal static OpenAI.Responses.FileSearchTool CreateFileSearchTool(this FileSearchTool tool)
+ {
+ Throw.IfNull(tool);
+
+ return new OpenAI.Responses.FileSearchTool(tool.GetVectorStoreIds());
+ }
+
+ ///
+ /// Get the vector store IDs for the specified .
+ ///
+ /// Instance of
+ internal static List? GetVectorStoreIds(this FileSearchTool tool)
+ {
+ return tool.VectorStoreIds?.LiteralValue.ToList();
+ }
+
+ internal static IList? GetVectorStoreConfigurations(this FileSearchTool tool)
+ {
+ var dataSources = tool.ExtensionData?.GetPropertyOrNull(InitializablePropertyPath.Create("options.configurations"));
+ return dataSources?.Values.Select(value => value.CreateVectorStoreConfiguration()).ToList();
+ }
+
+ internal static VectorStoreConfigurations CreateVectorStoreConfiguration(this RecordDataValue value)
+ {
+ Throw.IfNull(value);
+
+ var storeName = value.GetPropertyOrNull(InitializablePropertyPath.Create("storeName"))?.Value;
+ Throw.IfNullOrEmpty(storeName);
+
+ var dataSources = value.GetDataSources();
+ Throw.IfNull(dataSources);
+
+ return new VectorStoreConfigurations(storeName, new VectorStoreConfiguration(dataSources));
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FunctionToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FunctionToolExtensions.cs
new file mode 100644
index 0000000000..73bd9b41b2
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FunctionToolExtensions.cs
@@ -0,0 +1,67 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using Azure.AI.Agents.Persistent;
+using Microsoft.Shared.Diagnostics;
+using OpenAI.Responses;
+
+namespace Microsoft.Bot.ObjectModel;
+
+///
+/// Extension methods for .
+///
+public static class FunctionToolExtensions
+{
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+ internal static FunctionToolDefinition CreateFunctionToolDefinition(this InvokeClientTaskAction tool)
+ {
+ Throw.IfNull(tool);
+ Throw.IfNull(tool.Name);
+
+ BinaryData parameters = tool.GetParameters();
+
+ return new FunctionToolDefinition(
+ name: tool.Name,
+ description: tool.Description,
+ parameters: parameters);
+ }
+
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+ /// A new instance configured with the function name, parameters, and description.
+ internal static FunctionTool CreateFunctionTool(this InvokeClientTaskAction tool)
+ {
+ Throw.IfNull(tool);
+ Throw.IfNull(tool.Name);
+
+ BinaryData parameters = tool.GetParameters();
+
+ return new FunctionTool(
+ functionName: tool.Name,
+ functionParameters: parameters,
+ strictModeEnabled: null)
+ {
+ FunctionDescription = tool.Description
+ };
+ }
+
+ ///
+ /// Creates the parameters schema for a .
+ ///
+ /// Instance of
+ internal static BinaryData GetParameters(this InvokeClientTaskAction tool)
+ {
+ Throw.IfNull(tool);
+
+ var parameters = tool.ClientActionInputSchema?.GetSchema().ToString() ?? DefaultSchema;
+
+ return new BinaryData(parameters);
+ }
+
+ private const string DefaultSchema = "{\"type\":\"object\",\"properties\":{},\"additionalProperties\":false}";
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedCodeInterpreterToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedCodeInterpreterToolExtensions.cs
new file mode 100644
index 0000000000..da769856dd
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedCodeInterpreterToolExtensions.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Azure.AI.Agents.Persistent;
+using Microsoft.Bot.ObjectModel;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Extensions.AI;
+
+///
+/// Extension methods for .
+///
+internal static class HostedCodeInterpreterToolExtensions
+{
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+ internal static CodeInterpreterToolDefinition CreateHostedCodeInterpreterToolDefinition(this HostedCodeInterpreterTool tool)
+ {
+ Throw.IfNull(tool);
+
+ return new CodeInterpreterToolDefinition();
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedFileSearchToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedFileSearchToolExtensions.cs
new file mode 100644
index 0000000000..846e28f226
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedFileSearchToolExtensions.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Azure.AI.Agents.Persistent;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Extensions.AI;
+
+///
+/// Extension methods for .
+///
+internal static class HostedFileSearchToolExtensions
+{
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+ internal static FileSearchToolDefinition CreateFileSearchToolDefinition(this HostedFileSearchTool tool)
+ {
+ Throw.IfNull(tool);
+
+ // TODO: Add support for FileSearchToolDefinitionDetails.
+
+ return new FileSearchToolDefinition();
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedMcpServerToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedMcpServerToolExtensions.cs
new file mode 100644
index 0000000000..a879a105bc
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedMcpServerToolExtensions.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Linq;
+using Azure.AI.Agents.Persistent;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Extensions.AI;
+
+///
+/// Extension methods for .
+///
+internal static class HostedMcpServerToolExtensions
+{
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+ internal static MCPToolDefinition CreateMcpToolDefinition(this HostedMcpServerTool tool)
+ {
+ Throw.IfNull(tool);
+ Throw.IfNull(tool.ServerName);
+ Throw.IfNull(tool.ServerAddress);
+
+ var definition = new MCPToolDefinition(tool.ServerName, tool.ServerAddress);
+ tool.AllowedTools?.ToList().ForEach(definition.AllowedTools.Add);
+ return definition;
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedWebSearchToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedWebSearchToolExtensions.cs
new file mode 100644
index 0000000000..f13c0ec2d4
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedWebSearchToolExtensions.cs
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Azure.AI.Agents.Persistent;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Extensions.AI;
+
+///
+/// Extension methods for .
+///
+internal static class HostedWebSearchToolExtensions
+{
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+ internal static BingGroundingToolDefinition CreateBingGroundingToolDefinition(this HostedWebSearchTool tool)
+ {
+ Throw.IfNull(tool);
+
+ // TODO: Add support for BingGroundingSearchToolParameters.
+ var parameters = new BingGroundingSearchToolParameters([]);
+
+ return new BingGroundingToolDefinition(parameters);
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/McpServerToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/McpServerToolExtensions.cs
new file mode 100644
index 0000000000..0e74f53e9a
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/McpServerToolExtensions.cs
@@ -0,0 +1,53 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using Azure.AI.Agents.Persistent;
+using Microsoft.Shared.Diagnostics;
+using OpenAI.Responses;
+
+namespace Microsoft.Bot.ObjectModel;
+
+///
+/// Extension methods for .
+///
+internal static class McpServerToolExtensions
+{
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+ internal static MCPToolDefinition CreateMcpToolDefinition(this McpServerTool tool)
+ {
+ Throw.IfNull(tool);
+ Throw.IfNull(tool.ServerName?.LiteralValue);
+ Throw.IfNull(tool.Connection);
+
+ // TODO: Add support for additional properties
+
+ var connection = tool.Connection as AnonymousConnection ?? throw new ArgumentException($"Only AnonymousConnection is supported for MCP Server Tool connections. Actual connection type: {tool.Connection.GetType().Name}", nameof(tool));
+ var serverUrl = connection.Endpoint?.LiteralValue;
+ Throw.IfNullOrEmpty(serverUrl, nameof(connection.Endpoint));
+
+ return new MCPToolDefinition(tool.ServerName?.LiteralValue, serverUrl);
+ }
+
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+ /// A new instance configured with the server name and URL.
+ internal static McpTool CreateMcpTool(this McpServerTool tool)
+ {
+ Throw.IfNull(tool);
+ Throw.IfNull(tool.ServerName?.LiteralValue);
+ Throw.IfNull(tool.Connection);
+
+ // TODO: Add support for headers
+
+ var connection = tool.Connection as AnonymousConnection ?? throw new ArgumentException("Only AnonymousConnection is supported for MCP Server Tool connections.", nameof(tool));
+ var serverUrl = connection.Endpoint?.LiteralValue;
+ Throw.IfNullOrEmpty(serverUrl, nameof(connection.Endpoint));
+
+ return new McpTool(tool.ServerName?.LiteralValue, serverUrl);
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/PromptAgentExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/PromptAgentExtensions.cs
new file mode 100644
index 0000000000..3fb7c64c1b
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/PromptAgentExtensions.cs
@@ -0,0 +1,142 @@
+// Copyright (c) Microsoft. All rights reserved.
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Azure.AI.Agents.Persistent;
+using Microsoft.Shared.Diagnostics;
+using OpenAI.Responses;
+
+namespace Microsoft.Bot.ObjectModel;
+
+///
+/// Extension methods for .
+///
+internal static class PromptAgentExtensions
+{
+ ///
+ /// Return the Foundry tool definitions which corresponds with the provided .
+ ///
+ /// Instance of
+ internal static IEnumerable GetToolDefinitions(this GptComponentMetadata promptAgent)
+ {
+ Throw.IfNull(promptAgent);
+
+ return promptAgent.Tools.Select(tool =>
+ {
+ return tool switch
+ {
+ CodeInterpreterTool codeInterpreterTool => codeInterpreterTool.CreateCodeInterpreterToolDefinition(),
+ InvokeClientTaskAction functionTool => functionTool.CreateFunctionToolDefinition(),
+ FileSearchTool fileSearchTool => fileSearchTool.CreateFileSearchToolDefinition(),
+ WebSearchTool webSearchTool => webSearchTool.CreateBingGroundingToolDefinition(),
+ McpServerTool mcpServerTool => mcpServerTool.CreateMcpToolDefinition(),
+ // TODO: Add other tool types as custom tools
+ // AzureAISearch
+ // AzureFunction
+ // OpenApi
+ _ => throw new NotSupportedException($"Unable to create tool definition because of unsupported tool type: {tool.Kind}"),
+ };
+ }).ToList();
+ }
+
+ ///
+ /// Return the Foundry tool resources which corresponds with the provided .
+ ///
+ /// Instance of
+ internal static ToolResources GetToolResources(this GptComponentMetadata promptAgent)
+ {
+ Throw.IfNull(promptAgent);
+
+ var toolResources = new ToolResources();
+
+ var codeInterpreter = promptAgent.GetCodeInterpreterToolResource();
+ if (codeInterpreter is not null)
+ {
+ toolResources.CodeInterpreter = codeInterpreter;
+ }
+
+ var fileSearch = promptAgent.GetFileSearchToolResource();
+ if (fileSearch is not null)
+ {
+ toolResources.FileSearch = fileSearch;
+ }
+
+ // TODO Handle MCP tool resources
+
+ return toolResources;
+ }
+
+ ///
+ /// Returns the Foundry response tools which correspond with the provided .
+ ///
+ /// Instance of .
+ /// A collection of instances corresponding to the tools defined in the agent.
+ internal static IEnumerable GetResponseTools(this GptComponentMetadata promptAgent)
+ {
+ Throw.IfNull(promptAgent);
+
+ return promptAgent.Tools.Select(tool =>
+ {
+ return tool switch
+ {
+ CodeInterpreterTool codeInterpreterTool => codeInterpreterTool.CreateCodeInterpreterTool(),
+ InvokeClientTaskAction functionTool => functionTool.CreateFunctionTool(),
+ FileSearchTool fileSearchTool => fileSearchTool.CreateFileSearchTool(),
+ WebSearchTool webSearchTool => webSearchTool.CreateWebSearchTool(),
+ McpServerTool mcpServerTool => mcpServerTool.CreateMcpTool(),
+ // TODO: Add other tool types as custom tools
+ // AzureAISearch
+ // AzureFunction
+ // OpenApi
+ _ => throw new NotSupportedException($"Unable to create response tool because of unsupported tool type: {tool.Kind}"),
+ };
+ }).ToList();
+ }
+
+ #region private
+ private static CodeInterpreterToolResource? GetCodeInterpreterToolResource(this GptComponentMetadata promptAgent)
+ {
+ Throw.IfNull(promptAgent);
+
+ CodeInterpreterToolResource? resource = null;
+
+ var codeInterpreter = (CodeInterpreterTool?)promptAgent.GetFirstAgentTool();
+ if (codeInterpreter is not null)
+ {
+ var fileIds = codeInterpreter.GetFileIds();
+ var dataSources = codeInterpreter.GetDataSources();
+ if (fileIds is not null || dataSources is not null)
+ {
+ resource = new CodeInterpreterToolResource();
+ fileIds?.ForEach(id => resource.FileIds.Add(id));
+ dataSources?.ForEach(ds => resource.DataSources.Add(ds));
+ }
+ }
+
+ return resource;
+ }
+
+ private static FileSearchToolResource? GetFileSearchToolResource(this GptComponentMetadata promptAgent)
+ {
+ Throw.IfNull(promptAgent);
+
+ var fileSearch = (FileSearchTool?)promptAgent.GetFirstAgentTool();
+ if (fileSearch is not null)
+ {
+ var vectorStoreIds = fileSearch.GetVectorStoreIds();
+ var vectorStores = fileSearch.GetVectorStoreConfigurations();
+ if (vectorStoreIds is not null || vectorStores is not null)
+ {
+ return new FileSearchToolResource(vectorStoreIds, vectorStores);
+ }
+ }
+
+ return null;
+ }
+
+ private static TaskAction? GetFirstAgentTool(this GptComponentMetadata promptAgent)
+ {
+ return promptAgent.Tools.FirstOrDefault(tool => tool is T);
+ }
+ #endregion
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataTypeExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataTypeExtensions.cs
new file mode 100644
index 0000000000..24c172c888
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataTypeExtensions.cs
@@ -0,0 +1,45 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using Microsoft.Extensions.AI;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Bot.ObjectModel;
+
+///
+/// Extension methods for .
+///
+internal static class RecordDataTypeExtensions
+{
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
+#pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
+ internal static BinaryData? AsBinaryData(this RecordDataType recordDataType)
+ {
+ Throw.IfNull(recordDataType);
+
+ if (recordDataType.Properties.Count == 0)
+ {
+ return null;
+ }
+
+ return BinaryData.FromObjectAsJson(
+ new
+ {
+ type = "json_schema",
+ schema =
+ new
+ {
+ type = "object",
+ properties = recordDataType.Properties.AsObjectDictionary(),
+ additionalProperties = false
+ }
+ }
+ );
+ }
+#pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
+#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataValueExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataValueExtensions.cs
new file mode 100644
index 0000000000..a2c4d490d6
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataValueExtensions.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Collections.Generic;
+using System.Linq;
+using Azure.AI.Agents.Persistent;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Bot.ObjectModel;
+
+///
+/// Extension methods for .
+///
+internal static class RecordDataValueExtensions
+{
+ ///
+ /// Gets the data sources from the specified .
+ ///
+ internal static List? GetDataSources(this RecordDataValue value)
+ {
+ var dataSources = value.GetPropertyOrNull(InitializablePropertyPath.Create("options.data_sources"));
+ return dataSources?.Values.Select(dataSource => dataSource.CreateDataSource()).ToList();
+ }
+
+ ///
+ /// Creates a new instance of using the specified .
+ ///
+ internal static VectorStoreDataSource CreateDataSource(this RecordDataValue value)
+ {
+ Throw.IfNull(value);
+
+ string? assetIdentifier = value.GetPropertyOrNull(InitializablePropertyPath.Create("assetIdentifier"))?.Value;
+ Throw.IfNullOrEmpty(assetIdentifier);
+
+ string? assetType = value.GetPropertyOrNull(InitializablePropertyPath.Create("assetType"))?.Value;
+ Throw.IfNullOrEmpty(assetType);
+
+ return new VectorStoreDataSource(assetIdentifier, new VectorStoreDataSourceAssetType(assetType));
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/WebSearchToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/WebSearchToolExtensions.cs
new file mode 100644
index 0000000000..b0f65442af
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/WebSearchToolExtensions.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Azure.AI.Agents.Persistent;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Bot.ObjectModel;
+
+///
+/// Extension methods for .
+///
+internal static class WebSearchToolExtensions
+{
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+ internal static BingGroundingToolDefinition CreateBingGroundingToolDefinition(this WebSearchTool tool)
+ {
+ Throw.IfNull(tool);
+
+ // TODO: Add support for BingGroundingSearchToolParameters.
+ var parameters = new BingGroundingSearchToolParameters([]);
+
+ return new BingGroundingToolDefinition(parameters);
+ }
+
+ ///
+ /// Creates a from a .
+ ///
+ /// Instance of
+ /// A new instance.
+ internal static OpenAI.Responses.WebSearchTool CreateWebSearchTool(this WebSearchTool tool)
+ {
+ Throw.IfNull(tool);
+
+ return new OpenAI.Responses.WebSearchTool();
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryAgentFactory.cs
new file mode 100644
index 0000000000..5d18c7a25c
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryAgentFactory.cs
@@ -0,0 +1,111 @@
+// Copyright (c) Microsoft. All rights reserved.
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.AI.Agents;
+using Azure.AI.Agents.Persistent;
+using Azure.Core;
+using Microsoft.Bot.ObjectModel;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Agents.AI;
+
+///
+/// Provides an which creates instances of using a .
+///
+public sealed class FoundryAgentFactory : AgentFactory
+{
+ private readonly AgentClient? _agentClient;
+ private readonly TokenCredential? _tokenCredential;
+
+ ///
+ /// Creates a new instance of the class with an associated .
+ ///
+ /// The instance to use for creating agents.
+ /// The instance to use for configuration.
+ public FoundryAgentFactory(AgentClient agentClient, IConfiguration? configuration = null) : base(configuration)
+ {
+ Throw.IfNull(agentClient);
+
+ this._agentClient = agentClient;
+ }
+
+ ///
+ /// Creates a new instance of the class with an associated .
+ ///
+ /// The to use for authenticating requests.
+ /// The instance to use for configuration.
+ public FoundryAgentFactory(TokenCredential tokenCredential, IConfiguration? configuration = null) : base(configuration)
+ {
+ Throw.IfNull(tokenCredential);
+
+ this._tokenCredential = tokenCredential;
+ }
+
+ ///
+ public override async Task TryCreateAsync(GptComponentMetadata promptAgent, CancellationToken cancellationToken = default)
+ {
+ Throw.IfNull(promptAgent);
+
+ var agentClient = this._agentClient ?? this.CreateAgentClient(promptAgent);
+
+ var modelId = promptAgent.Model?.ModelNameHint;
+ if (string.IsNullOrEmpty(modelId))
+ {
+ throw new InvalidOperationException("The model id must be specified in the agent definition model to create a foundry agent.");
+ }
+
+ var modelOptions = promptAgent.Model?.Options;
+
+ var promptAgentDefinition = new PromptAgentDefinition(model: modelId)
+ {
+ Instructions = promptAgent.Instructions?.ToTemplateString(),
+ Temperature = (float?)modelOptions?.Temperature?.LiteralValue,
+ TopP = (float?)modelOptions?.TopP?.LiteralValue,
+ };
+
+ foreach (var tool in promptAgent.GetResponseTools())
+ {
+ promptAgentDefinition.Tools.Add(tool);
+ }
+
+ var agentVersionCreationOptions = new AgentVersionCreationOptions(promptAgentDefinition);
+
+ var metadata = promptAgent.Metadata?.ToDictionary();
+ if (metadata is not null)
+ {
+ foreach (var kvp in metadata)
+ {
+ agentVersionCreationOptions.Metadata.Add(kvp.Key, kvp.Value);
+ }
+ }
+
+ var agentVersion = await agentClient.CreateAgentVersionAsync(agentName: promptAgent.Name, options: agentVersionCreationOptions, cancellationToken: cancellationToken).ConfigureAwait(false);
+
+ return agentClient.GetAIAgent(agentVersion, cancellationToken: cancellationToken);
+ }
+
+ private AgentClient CreateAgentClient(GptComponentMetadata promptAgent)
+ {
+ var externalModel = promptAgent.Model as CurrentModels;
+ var connection = externalModel?.Connection as RemoteConnection;
+ if (connection is not null)
+ {
+ var endpoint = connection.Endpoint?.Eval(this.Engine);
+ if (string.IsNullOrEmpty(endpoint))
+ {
+ throw new InvalidOperationException("The endpoint must be specified in the agent definition model connection to create an AgentClient.");
+ }
+
+ if (this._tokenCredential is null)
+ {
+ throw new InvalidOperationException("A TokenCredential must be registered in the service provider to create an AgentClient.");
+ }
+
+ return new AgentClient(new Uri(endpoint), this._tokenCredential);
+ }
+
+ throw new InvalidOperationException("An AgentClient must be registered in the service provider or a RemoteConnection must be specified in the agent definition model connection to create an AgentClient.");
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryPersistentAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryPersistentAgentFactory.cs
new file mode 100644
index 0000000000..ae9bc7756e
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryPersistentAgentFactory.cs
@@ -0,0 +1,94 @@
+// Copyright (c) Microsoft. All rights reserved.
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.AI.Agents.Persistent;
+using Azure.Core;
+using Microsoft.Bot.ObjectModel;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Agents.AI;
+
+///
+/// Provides an which creates instances of using a .
+///
+public sealed class FoundryPersistentAgentFactory : AgentFactory
+{
+ private readonly PersistentAgentsClient? _agentClient;
+ private readonly TokenCredential? _tokenCredential;
+
+ ///
+ /// Creates a new instance of the class with an associated .
+ ///
+ /// The instance to use for creating agents.
+ /// The instance to use for configuration.
+ public FoundryPersistentAgentFactory(PersistentAgentsClient agentClient, IConfiguration? configuration = null) : base(configuration)
+ {
+ Throw.IfNull(agentClient);
+
+ this._agentClient = agentClient;
+ }
+
+ ///
+ /// Creates a new instance of the class with an associated .
+ ///
+ /// The to use for authenticating requests.
+ /// The instance to use for configuration.
+ public FoundryPersistentAgentFactory(TokenCredential tokenCredential, IConfiguration? configuration = null) : base(configuration)
+ {
+ Throw.IfNull(tokenCredential);
+
+ this._tokenCredential = tokenCredential;
+ }
+
+ ///
+ public override async Task TryCreateAsync(GptComponentMetadata promptAgent, CancellationToken cancellationToken = default)
+ {
+ Throw.IfNull(promptAgent);
+
+ var agentClient = this._agentClient ?? this.CreatePersistentAgentClient(promptAgent);
+
+ var modelId = promptAgent.Model?.ModelNameHint;
+ if (string.IsNullOrEmpty(modelId))
+ {
+ throw new InvalidOperationException("The model id must be specified in the agent definition model to create a foundry agent.");
+ }
+
+ //var outputSchema = promptAgent.OutputType; TODO: Fix converting RecordDataType to BinaryData
+ var modelOptions = promptAgent.Model?.Options;
+
+ return await agentClient.CreateAIAgentAsync(
+ model: modelId,
+ name: promptAgent.Name,
+ instructions: promptAgent.Instructions?.ToTemplateString(),
+ tools: promptAgent.GetToolDefinitions(),
+ toolResources: promptAgent.GetToolResources(),
+ temperature: (float?)modelOptions?.Temperature?.LiteralValue,
+ topP: (float?)modelOptions?.TopP?.LiteralValue,
+ //responseFormat: outputSchema.AsBinaryData(), TODO: Fix converting RecordDataType to BinaryData
+ metadata: promptAgent.Metadata?.ToDictionary(),
+ cancellationToken: cancellationToken).ConfigureAwait(false);
+ }
+
+ private PersistentAgentsClient CreatePersistentAgentClient(GptComponentMetadata promptAgent)
+ {
+ var externalModel = promptAgent.Model as CurrentModels;
+ var connection = externalModel?.Connection as RemoteConnection;
+ if (connection is not null)
+ {
+ var endpoint = connection.Endpoint?.Eval(this.Engine);
+ if (string.IsNullOrEmpty(endpoint))
+ {
+ throw new InvalidOperationException("The endpoint must be specified in the agent definition model connection to create an PersistentAgentsClient.");
+ }
+ if (this._tokenCredential is null)
+ {
+ throw new InvalidOperationException("A TokenCredential must be registered in the service provider to create an PersistentAgentsClient.");
+ }
+ return new PersistentAgentsClient(endpoint, this._tokenCredential);
+ }
+
+ throw new InvalidOperationException("A PersistentAgentsClient must be registered in the service provider or a FoundryConnection must be specified in the agent definition model connection to create an PersistentAgentsClient.");
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/JsonSchemaFunctionParameters.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/JsonSchemaFunctionParameters.cs
new file mode 100644
index 0000000000..c406825d5b
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/JsonSchemaFunctionParameters.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.Collections.Generic;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Microsoft.Extensions.AI;
+
+namespace Microsoft.Agents.AI.Declarative.AzureAI;
+
+///
+/// A class to describe the parameters of an in a JSON Schema friendly way.
+///
+internal sealed class JsonSchemaFunctionParameters
+{
+ ///
+ /// The type of schema which is always "object" when describing function parameters.
+ ///
+ [JsonPropertyName("type")]
+ public string Type => "object";
+
+ ///
+ /// The list of required properties.
+ ///
+ [JsonPropertyName("required")]
+ public List Required { get; set; } = [];
+
+ ///
+ /// A dictionary of properties, keyed by name => JSON Schema.
+ ///
+ [JsonPropertyName("properties")]
+ public Dictionary Properties { get; set; } = [];
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Microsoft.Agents.AI.Declarative.AzureAI.Persistent.csproj b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Microsoft.Agents.AI.Declarative.AzureAI.Persistent.csproj
new file mode 100644
index 0000000000..05705a5675
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Microsoft.Agents.AI.Declarative.AzureAI.Persistent.csproj
@@ -0,0 +1,52 @@
+
+
+
+ $(ProjectsTargetFrameworks)
+ $(ProjectsDebugTargetFrameworks)
+ preview
+ $(NoWarn);MEAI001;OPENAI001
+
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+ Microsoft Agent Framework Declarative AzureAI
+ Provides Microsoft Agent Framework support for declarative AzureAI agents.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAgentFactory.cs
new file mode 100644
index 0000000000..a598292e75
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAgentFactory.cs
@@ -0,0 +1,183 @@
+// Copyright (c) Microsoft. All rights reserved.
+using System;
+using System.ClientModel;
+using Azure.AI.OpenAI;
+using Azure.Core;
+using Microsoft.Bot.ObjectModel;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Microsoft.Shared.Diagnostics;
+using OpenAI;
+using OpenAI.Assistants;
+using OpenAI.Chat;
+using OpenAI.Responses;
+
+namespace Microsoft.Agents.AI;
+
+///
+/// Provides an abstract base class.
+///
+public abstract class OpenAIAgentFactory : AgentFactory
+{
+ ///
+ /// Creates a new instance of the class.
+ ///
+ protected OpenAIAgentFactory(IConfiguration? configuration, ILoggerFactory? loggerFactory) : base(configuration)
+ {
+ this.LoggerFactory = loggerFactory;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ protected OpenAIAgentFactory(Uri endpoint, TokenCredential tokenCredential, IConfiguration? configuration, ILoggerFactory? loggerFactory) : base(configuration)
+ {
+ Throw.IfNull(endpoint);
+ Throw.IfNull(tokenCredential);
+
+ this._endpoint = endpoint;
+ this._tokenCredential = tokenCredential;
+ this.LoggerFactory = loggerFactory;
+ }
+
+ ///
+ /// Gets the instance used for creating loggers.
+ ///
+ protected ILoggerFactory? LoggerFactory { get; }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ protected ChatClient? CreateChatClient(GptComponentMetadata promptAgent)
+ {
+ var model = promptAgent.Model as CurrentModels;
+ var provider = model?.Provider?.Value ?? ModelProvider.OpenAI;
+ if (provider == ModelProvider.OpenAI)
+ {
+ return this.CreateOpenAIChatClient(promptAgent);
+ }
+ else if (provider == ModelProvider.AzureOpenAI)
+ {
+ Throw.IfNull(this._endpoint, "A endpoint must be specified to create an Azure OpenAI client");
+ Throw.IfNull(this._tokenCredential, "A token credential must be specified to create an Azure OpenAI client");
+ return CreateAzureOpenAIChatClient(promptAgent, this._endpoint, this._tokenCredential);
+ }
+
+ return null;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ protected AssistantClient? CreateAssistantClient(GptComponentMetadata promptAgent)
+ {
+ var model = promptAgent.Model as CurrentModels;
+ var provider = model?.Provider?.Value ?? ModelProvider.OpenAI;
+ if (provider == ModelProvider.OpenAI)
+ {
+ return this.CreateOpenAIAssistantClient(promptAgent);
+ }
+ else if (provider == ModelProvider.AzureOpenAI)
+ {
+ Throw.IfNull(this._endpoint, "The connection endpoint must be specified to create an Azure OpenAI client.");
+ Throw.IfNull(this._tokenCredential, "A token credential must be specified to create an Azure OpenAI client");
+ return CreateAzureOpenAIAssistantClient(promptAgent, this._endpoint, this._tokenCredential);
+ }
+
+ return null;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ protected OpenAIResponseClient? CreateResponseClient(GptComponentMetadata promptAgent)
+ {
+ var model = promptAgent.Model as CurrentModels;
+ var provider = model?.Provider?.Value ?? ModelProvider.OpenAI;
+ if (provider == ModelProvider.OpenAI)
+ {
+ return this.CreateOpenAIResponseClient(promptAgent);
+ }
+ else if (provider == ModelProvider.AzureOpenAI)
+ {
+ Throw.IfNull(this._endpoint, "The connection endpoint must be specified to create an Azure OpenAI client.");
+ Throw.IfNull(this._tokenCredential, "A token credential must be specified to create an Azure OpenAI client");
+ return CreateAzureOpenAIResponseClient(promptAgent, this._endpoint, this._tokenCredential);
+ }
+
+ return null;
+ }
+
+ #region private
+ private readonly Uri? _endpoint;
+ private readonly TokenCredential? _tokenCredential;
+
+ private ChatClient CreateOpenAIChatClient(GptComponentMetadata promptAgent)
+ {
+ var modelId = promptAgent.Model?.ModelNameHint;
+ Throw.IfNullOrEmpty(modelId, "The model id must be specified in the agent definition to create an OpenAI agent.");
+
+ return this.CreateOpenAIClient(promptAgent).GetChatClient(modelId);
+ }
+
+ private static ChatClient CreateAzureOpenAIChatClient(GptComponentMetadata promptAgent, Uri endpoint, TokenCredential tokenCredential)
+ {
+ var deploymentName = promptAgent.Model?.ModelNameHint;
+ Throw.IfNullOrEmpty(deploymentName, "The deployment name (using model.id) must be specified in the agent definition to create an Azure OpenAI agent.");
+
+ return new AzureOpenAIClient(endpoint, tokenCredential).GetChatClient(deploymentName);
+ }
+
+ private AssistantClient CreateOpenAIAssistantClient(GptComponentMetadata promptAgent)
+ {
+ var modelId = promptAgent.Model?.ModelNameHint;
+ Throw.IfNullOrEmpty(modelId, "The model id must be specified in the agent definition to create an OpenAI agent.");
+
+ return this.CreateOpenAIClient(promptAgent).GetAssistantClient();
+ }
+
+ private static AssistantClient CreateAzureOpenAIAssistantClient(GptComponentMetadata promptAgent, Uri endpoint, TokenCredential tokenCredential)
+ {
+ var deploymentName = promptAgent.Model?.ModelNameHint;
+ Throw.IfNullOrEmpty(deploymentName, "The deployment name (using model.id) must be specified in the agent definition to create an Azure OpenAI agent.");
+
+ return new AzureOpenAIClient(endpoint, tokenCredential).GetAssistantClient();
+ }
+
+ private OpenAIResponseClient CreateOpenAIResponseClient(GptComponentMetadata promptAgent)
+ {
+ var modelId = promptAgent.Model?.ModelNameHint;
+ Throw.IfNullOrEmpty(modelId, "The model id must be specified in the agent definition to create an OpenAI agent.");
+
+ return this.CreateOpenAIClient(promptAgent).GetOpenAIResponseClient(modelId);
+ }
+
+ private static OpenAIResponseClient CreateAzureOpenAIResponseClient(GptComponentMetadata promptAgent, Uri endpoint, TokenCredential tokenCredential)
+ {
+ var deploymentName = promptAgent.Model?.ModelNameHint;
+ Throw.IfNullOrEmpty(deploymentName, "The deployment name (using model.id) must be specified in the agent definition to create an Azure OpenAI agent.");
+
+ return new AzureOpenAIClient(endpoint, tokenCredential).GetOpenAIResponseClient(deploymentName);
+ }
+
+ private OpenAIClient CreateOpenAIClient(GptComponentMetadata promptAgent)
+ {
+ var model = promptAgent.Model as CurrentModels;
+
+ var keyConnection = model?.Connection as ApiKeyConnection;
+ Throw.IfNull(keyConnection, "A key connection must be specified when create an OpenAI client");
+
+ var apiKey = keyConnection.Key!.Eval(this.Engine);
+ Throw.IfNullOrEmpty(apiKey, "The connection key must be specified in the agent definition to create an OpenAI client.");
+
+ var clientOptions = new OpenAIClientOptions();
+ var endpoint = keyConnection.Endpoint?.Eval(this.Engine);
+ if (!string.IsNullOrEmpty(endpoint))
+ {
+ clientOptions.Endpoint = new Uri(endpoint);
+ }
+
+ return new OpenAIClient(new ApiKeyCredential(apiKey), clientOptions);
+ }
+ #endregion
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAssistantAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAssistantAgentFactory.cs
new file mode 100644
index 0000000000..621736e6dd
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAssistantAgentFactory.cs
@@ -0,0 +1,92 @@
+// Copyright (c) Microsoft. All rights reserved.
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.AI.Agents.Persistent;
+using Azure.Core;
+using Microsoft.Bot.ObjectModel;
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Microsoft.Shared.Diagnostics;
+using OpenAI;
+using OpenAI.Assistants;
+
+namespace Microsoft.Agents.AI;
+
+///
+/// Provides an which creates instances of using a .
+///
+public sealed class OpenAIAssistantAgentFactory : OpenAIAgentFactory
+{
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenAIAssistantAgentFactory(IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(configuration, loggerFactory)
+ {
+ this._functions = functions;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenAIAssistantAgentFactory(AssistantClient assistantClient, IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(configuration, loggerFactory)
+ {
+ Throw.IfNull(assistantClient);
+
+ this._assistantClient = assistantClient;
+ this._functions = functions;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenAIAssistantAgentFactory(Uri endpoint, TokenCredential tokenCredential, IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(endpoint, tokenCredential, configuration, loggerFactory)
+ {
+ this._functions = functions;
+ }
+
+ ///
+ public override async Task TryCreateAsync(GptComponentMetadata promptAgent, CancellationToken cancellationToken = default)
+ {
+ Throw.IfNull(promptAgent);
+
+ var model = promptAgent.Model as CurrentModels;
+ var apiType = model?.ApiType;
+ if (apiType?.IsUnknown() == false || apiType?.UnknownValue?.Equals(API_TYPE_ASSISTANTS, StringComparison.OrdinalIgnoreCase) == false)
+ {
+ return null;
+ }
+
+ var options = new ChatClientAgentOptions()
+ {
+ Name = promptAgent.Name,
+ Description = promptAgent.Description,
+ Instructions = promptAgent.Instructions?.ToTemplateString(),
+ ChatOptions = promptAgent.GetChatOptions(this._functions),
+ };
+
+ AssistantClient? assistantClient = this._assistantClient ?? this.CreateAssistantClient(promptAgent);
+ if (assistantClient is not null)
+ {
+ var modelId = promptAgent.Model?.ModelNameHint;
+ Throw.IfNullOrEmpty(modelId, "The model id must be specified in the agent definition to create an OpenAI Assistant.");
+ Throw.IfNullOrEmpty(promptAgent.Instructions?.ToTemplateString(), "The instructions must be specified in the agent definition to create an OpenAI Assistant.");
+
+ return await assistantClient.CreateAIAgentAsync(
+ modelId,
+ options
+ ).ConfigureAwait(false);
+ }
+
+ return null;
+ }
+
+ #region private
+ private readonly AssistantClient? _assistantClient;
+ private readonly IList? _functions;
+
+ private const string API_TYPE_ASSISTANTS = "ASSISTANTS";
+ #endregion
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIChatAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIChatAgentFactory.cs
new file mode 100644
index 0000000000..f27c8ca6a5
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIChatAgentFactory.cs
@@ -0,0 +1,85 @@
+// Copyright (c) Microsoft. All rights reserved.
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.AI.Agents.Persistent;
+using Azure.Core;
+using Microsoft.Bot.ObjectModel;
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Microsoft.Shared.Diagnostics;
+using OpenAI.Chat;
+
+namespace Microsoft.Agents.AI;
+
+///
+/// Provides an which creates instances of using a .
+///
+public sealed class OpenAIChatAgentFactory : OpenAIAgentFactory
+{
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenAIChatAgentFactory(IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(configuration, loggerFactory)
+ {
+ this._functions = functions;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenAIChatAgentFactory(ChatClient chatClient, IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(configuration, loggerFactory)
+ {
+ Throw.IfNull(chatClient);
+
+ this._chatClient = chatClient;
+ this._functions = functions;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenAIChatAgentFactory(Uri endpoint, TokenCredential tokenCredential, IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(endpoint, tokenCredential, configuration, loggerFactory)
+ {
+ this._functions = functions;
+ }
+
+ ///
+ public override async Task TryCreateAsync(GptComponentMetadata promptAgent, CancellationToken cancellationToken = default)
+ {
+ Throw.IfNull(promptAgent);
+
+ var model = promptAgent.Model as CurrentModels;
+ var apiType = model?.ApiType;
+ if (apiType?.IsUnknown() == true || apiType?.Value != ModelApiType.Chat)
+ {
+ return null;
+ }
+
+ var options = new ChatClientAgentOptions()
+ {
+ Name = promptAgent.Name,
+ Description = promptAgent.Description,
+ Instructions = promptAgent.Instructions?.ToTemplateString(),
+ ChatOptions = promptAgent.GetChatOptions(this._functions),
+ };
+
+ ChatClient? chatClient = this._chatClient ?? this.CreateChatClient(promptAgent);
+ if (chatClient is not null)
+ {
+ return new ChatClientAgent(
+ chatClient.AsIChatClient(),
+ options,
+ this.LoggerFactory);
+ }
+
+ return null;
+ }
+
+ #region private
+ private readonly ChatClient? _chatClient;
+ private readonly IList? _functions;
+ #endregion
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIResponseAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIResponseAgentFactory.cs
new file mode 100644
index 0000000000..6da009135d
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIResponseAgentFactory.cs
@@ -0,0 +1,85 @@
+// Copyright (c) Microsoft. All rights reserved.
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.AI.Agents.Persistent;
+using Azure.Core;
+using Microsoft.Bot.ObjectModel;
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Microsoft.Shared.Diagnostics;
+using OpenAI.Responses;
+
+namespace Microsoft.Agents.AI;
+
+///
+/// Provides an which creates instances of using a .
+///
+public sealed class OpenAIResponseAgentFactory : OpenAIAgentFactory
+{
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenAIResponseAgentFactory(IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(configuration, loggerFactory)
+ {
+ this._functions = functions;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenAIResponseAgentFactory(OpenAIResponseClient responseClient, IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(configuration, loggerFactory)
+ {
+ Throw.IfNull(responseClient);
+
+ this._responseClient = responseClient;
+ this._functions = functions;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenAIResponseAgentFactory(Uri endpoint, TokenCredential tokenCredential, IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(endpoint, tokenCredential, configuration, loggerFactory)
+ {
+ this._functions = functions;
+ }
+
+ ///
+ public override async Task TryCreateAsync(GptComponentMetadata promptAgent, CancellationToken cancellationToken = default)
+ {
+ Throw.IfNull(promptAgent);
+
+ var model = promptAgent.Model as CurrentModels;
+ var apiType = model?.ApiType;
+ if (apiType?.IsUnknown() == true || apiType?.Value != ModelApiType.Responses)
+ {
+ return null;
+ }
+
+ var options = new ChatClientAgentOptions()
+ {
+ Name = promptAgent.Name,
+ Description = promptAgent.Description,
+ Instructions = promptAgent.Instructions?.ToTemplateString(),
+ ChatOptions = promptAgent.GetChatOptions(this._functions),
+ };
+
+ var responseClient = this._responseClient ?? this.CreateResponseClient(promptAgent);
+ if (responseClient is not null)
+ {
+ return new ChatClientAgent(
+ responseClient.AsIChatClient(),
+ options,
+ this.LoggerFactory);
+ }
+
+ return null;
+ }
+
+ #region private
+ private readonly OpenAIResponseClient? _responseClient;
+ private readonly IList? _functions;
+ #endregion
+}
From 2ba1a257a54ebd57e4fa9fede20f15f923cae52e Mon Sep 17 00:00:00 2001
From: markwallace-microsoft
<127216156+markwallace-microsoft@users.noreply.github.com>
Date: Mon, 12 Jan 2026 14:23:42 +0000
Subject: [PATCH 2/8] Start to fix compile errors due to refactoring
---
dotnet/agent-framework-dotnet.slnx | 1 +
.../FoundryAgentFactory.cs | 41 ++++++++++++++-----
...s.AI.Declarative.AzureAI.Persistent.csproj | 23 +++++------
3 files changed, 42 insertions(+), 23 deletions(-)
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 002efdbab1..3ee33ae909 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -381,6 +381,7 @@
+
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryAgentFactory.cs
index 5d18c7a25c..148e251b18 100644
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryAgentFactory.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryAgentFactory.cs
@@ -2,29 +2,30 @@
using System;
using System.Threading;
using System.Threading.Tasks;
-using Azure.AI.Agents;
using Azure.AI.Agents.Persistent;
using Azure.Core;
using Microsoft.Bot.ObjectModel;
using Microsoft.Extensions.Configuration;
+using Microsoft.PowerFx;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI;
///
-/// Provides an which creates instances of using a .
+/// Provides an which creates instances of using a .
///
-public sealed class FoundryAgentFactory : AgentFactory
+public sealed class FoundryAgentFactory : PromptAgentFactory
{
- private readonly AgentClient? _agentClient;
+ private readonly PersistentAgentsClient? _agentClient;
private readonly TokenCredential? _tokenCredential;
///
- /// Creates a new instance of the class with an associated .
+ /// Creates a new instance of the class with an associated .
///
- /// The instance to use for creating agents.
+ /// The instance to use for creating agents.
+ /// Optional , if none is provided a default instance will be created.
/// The instance to use for configuration.
- public FoundryAgentFactory(AgentClient agentClient, IConfiguration? configuration = null) : base(configuration)
+ public FoundryAgentFactory(PersistentAgentsClient agentClient, RecalcEngine? engine = null, IConfiguration? configuration = null) : base(engine, configuration)
{
Throw.IfNull(agentClient);
@@ -35,8 +36,9 @@ public FoundryAgentFactory(AgentClient agentClient, IConfiguration? configuratio
/// Creates a new instance of the class with an associated .
///
/// The to use for authenticating requests.
+ /// Optional , if none is provided a default instance will be created.
/// The instance to use for configuration.
- public FoundryAgentFactory(TokenCredential tokenCredential, IConfiguration? configuration = null) : base(configuration)
+ public FoundryAgentFactory(TokenCredential tokenCredential, RecalcEngine? engine = null, IConfiguration? configuration = null) : base(engine, configuration)
{
Throw.IfNull(tokenCredential);
@@ -58,6 +60,7 @@ public FoundryAgentFactory(TokenCredential tokenCredential, IConfiguration? conf
var modelOptions = promptAgent.Model?.Options;
+ /*
var promptAgentDefinition = new PromptAgentDefinition(model: modelId)
{
Instructions = promptAgent.Instructions?.ToTemplateString(),
@@ -84,9 +87,25 @@ public FoundryAgentFactory(TokenCredential tokenCredential, IConfiguration? conf
var agentVersion = await agentClient.CreateAgentVersionAsync(agentName: promptAgent.Name, options: agentVersionCreationOptions, cancellationToken: cancellationToken).ConfigureAwait(false);
return agentClient.GetAIAgent(agentVersion, cancellationToken: cancellationToken);
+ */
+
+ var createPersistentAgentResponse = agentClient.Administration.CreateAgent(
+ model: modelId,
+ name: promptAgent.Name,
+ instructions: promptAgent.Instructions?.ToTemplateString(),
+ tools: tools,
+ toolResources: toolResources,
+ temperature: (float?)modelOptions?.Temperature?.LiteralValue,
+ topP: (float?)modelOptions?.TopP?.LiteralValue,
+ responseFormat: responseFormat,
+ metadata: promptAgent.Metadata?.ToDictionary(),
+ cancellationToken: cancellationToken);
+
+ // Get a local proxy for the agent to work with.
+ return agentClient.GetAIAgent(createPersistentAgentResponse.Value.Id, clientFactory: null, services: null, cancellationToken: cancellationToken);
}
- private AgentClient CreateAgentClient(GptComponentMetadata promptAgent)
+ private PersistentAgentsClient CreateAgentClient(GptComponentMetadata promptAgent)
{
var externalModel = promptAgent.Model as CurrentModels;
var connection = externalModel?.Connection as RemoteConnection;
@@ -103,9 +122,9 @@ private AgentClient CreateAgentClient(GptComponentMetadata promptAgent)
throw new InvalidOperationException("A TokenCredential must be registered in the service provider to create an AgentClient.");
}
- return new AgentClient(new Uri(endpoint), this._tokenCredential);
+ return new PersistentAgentsClient(endpoint, this._tokenCredential);
}
- throw new InvalidOperationException("An AgentClient must be registered in the service provider or a RemoteConnection must be specified in the agent definition model connection to create an AgentClient.");
+ throw new InvalidOperationException("A PersistentAgentsClient must be registered in the service provider or a RemoteConnection must be specified in the agent definition model connection to create a PersistentAgentsClient.");
}
}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Microsoft.Agents.AI.Declarative.AzureAI.Persistent.csproj b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Microsoft.Agents.AI.Declarative.AzureAI.Persistent.csproj
index 05705a5675..a74a845fef 100644
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Microsoft.Agents.AI.Declarative.AzureAI.Persistent.csproj
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Microsoft.Agents.AI.Declarative.AzureAI.Persistent.csproj
@@ -1,33 +1,30 @@
- $(ProjectsTargetFrameworks)
- $(ProjectsDebugTargetFrameworks)
preview
$(NoWarn);MEAI001;OPENAI001
+ false
true
- true
- true
true
+ true
- Microsoft Agent Framework Declarative AzureAI
- Provides Microsoft Agent Framework support for declarative AzureAI agents.
+ Microsoft Agent Framework Declarative Foundry Agents
+ Provides Microsoft Agent Framework support for declarative Foundry agents.
-
+
-
@@ -39,14 +36,16 @@
-
-
-
+
-
+
+
+
+
+
From 6ae3bdae4d9c20a1994e19bc3e4edf12c6a15384 Mon Sep 17 00:00:00 2001
From: markwallace-microsoft
<127216156+markwallace-microsoft@users.noreply.github.com>
Date: Fri, 30 Jan 2026 15:05:46 +0000
Subject: [PATCH 3/8] Remove declarative support for persistent agents
---
dotnet/agent-framework-dotnet.slnx | 2 +-
.../CodeInterpreterToolExtensions.cs | 64 --------
.../Extensions/FileSearchToolExtensions.cs | 67 ---------
.../Extensions/FunctionToolExtensions.cs | 67 ---------
.../HostedCodeInterpreterToolExtensions.cs | 24 ---
.../HostedFileSearchToolExtensions.cs | 25 ---
.../HostedMcpServerToolExtensions.cs | 28 ----
.../HostedWebSearchToolExtensions.cs | 26 ----
.../Extensions/McpServerToolExtensions.cs | 53 -------
.../Extensions/PromptAgentExtensions.cs | 142 ------------------
.../Extensions/RecordDataTypeExtensions.cs | 45 ------
.../Extensions/RecordDataValueExtensions.cs | 39 -----
.../Extensions/WebSearchToolExtensions.cs | 38 -----
.../FoundryAgentFactory.cs | 130 ----------------
.../FoundryPersistentAgentFactory.cs | 94 ------------
.../OpenAIAssistantAgentFactory.cs | 92 ------------
.../OpenAIResponseAgentFactory.cs | 85 -----------
.../AzureAIPromptAgentFactory.cs | 91 +++++++++++
.../BaseOpenAIPromptAgentFactory.cs} | 31 ++--
.../JsonSchemaFunctionParameters.cs | 0
...soft.Agents.AI.Declarative.AzureAI.csproj} | 10 +-
.../OpenAIPromptAgentFactory.cs} | 23 ++-
.../OpenAIResponsesPromptAgentFactory.cs | 84 +++++++++++
.../Extensions/PromptAgentExtensions.cs | 2 +-
24 files changed, 210 insertions(+), 1052 deletions(-)
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/CodeInterpreterToolExtensions.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FileSearchToolExtensions.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FunctionToolExtensions.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedCodeInterpreterToolExtensions.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedFileSearchToolExtensions.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedMcpServerToolExtensions.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedWebSearchToolExtensions.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/McpServerToolExtensions.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/PromptAgentExtensions.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataTypeExtensions.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataValueExtensions.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/WebSearchToolExtensions.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryAgentFactory.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryPersistentAgentFactory.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAssistantAgentFactory.cs
delete mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIResponseAgentFactory.cs
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/AzureAIPromptAgentFactory.cs
rename dotnet/src/{Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAgentFactory.cs => Microsoft.Agents.AI.Declarative.AzureAI/BaseOpenAIPromptAgentFactory.cs} (81%)
rename dotnet/src/{Microsoft.Agents.AI.Declarative.AzureAI.Persistent => Microsoft.Agents.AI.Declarative.AzureAI}/JsonSchemaFunctionParameters.cs (100%)
rename dotnet/src/{Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Microsoft.Agents.AI.Declarative.AzureAI.Persistent.csproj => Microsoft.Agents.AI.Declarative.AzureAI/Microsoft.Agents.AI.Declarative.AzureAI.csproj} (81%)
rename dotnet/src/{Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIChatAgentFactory.cs => Microsoft.Agents.AI.Declarative.AzureAI/OpenAIPromptAgentFactory.cs} (56%)
create mode 100644 dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/OpenAIResponsesPromptAgentFactory.cs
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 7baeecd6f2..5358c02f92 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -402,7 +402,7 @@
-
+
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/CodeInterpreterToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/CodeInterpreterToolExtensions.cs
deleted file mode 100644
index e45fe4c5e5..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/CodeInterpreterToolExtensions.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System.Collections.Generic;
-using System.Linq;
-using Azure.AI.Agents.Persistent;
-using Microsoft.Shared.Diagnostics;
-
-namespace Microsoft.Bot.ObjectModel;
-
-///
-/// Extension methods for .
-///
-internal static class CodeInterpreterToolExtensions
-{
- ///
- /// Creates a from a .
- ///
- /// Instance of
- internal static CodeInterpreterToolDefinition CreateCodeInterpreterToolDefinition(this CodeInterpreterTool tool)
- {
- Throw.IfNull(tool);
-
- return new CodeInterpreterToolDefinition();
- }
-
- ///
- /// Converts a to an .
- ///
- /// Instance of
- /// A new instance configured with the container ID from the tool's extension data.
- internal static OpenAI.Responses.CodeInterpreterTool CreateCodeInterpreterTool(this CodeInterpreterTool tool)
- {
- Throw.IfNull(tool);
-
- var containerId = tool.ExtensionData?.GetPropertyOrNull(InitializablePropertyPath.Create("containerId"))?.Value;
- Throw.IfNull(containerId, "The 'containerId' property must be specified in the CodeInterpreterTool's extension data to create a code interpreter tool.");
-
- return new OpenAI.Responses.CodeInterpreterTool(new OpenAI.Responses.CodeInterpreterToolContainer(containerId));
- }
-
- ///
- /// Collects the file IDs from the extension data of a .
- ///
- /// Instance of
- internal static List? GetFileIds(this CodeInterpreterTool tool)
- {
- var fileIds = tool.ExtensionData?.GetPropertyOrNull(InitializablePropertyPath.Create("fileIds"));
- return fileIds is not null
- ? [.. fileIds.Values.Select(fileId => fileId.GetPropertyOrNull(InitializablePropertyPath.Create("value"))?.Value)]
- : null;
- }
-
- ///
- /// Collects the data sources from the extension data of a .
- ///
- /// Instance of
- internal static List? GetDataSources(this CodeInterpreterTool tool)
- {
- var dataSources = tool.ExtensionData?.GetPropertyOrNull(InitializablePropertyPath.Create("dataSources"));
- return dataSources is not null
- ? dataSources.Values.Select(dataSource => dataSource.CreateDataSource()).ToList()
- : null;
- }
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FileSearchToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FileSearchToolExtensions.cs
deleted file mode 100644
index e582672f93..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FileSearchToolExtensions.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System.Collections.Generic;
-using System.Linq;
-using Azure.AI.Agents.Persistent;
-using Microsoft.Shared.Diagnostics;
-
-namespace Microsoft.Bot.ObjectModel;
-
-///
-/// Extension methods for .
-///
-internal static class FileSearchToolExtensions
-{
- ///
- /// Creates a from a .
- ///
- /// Instance of
- internal static FileSearchToolDefinition CreateFileSearchToolDefinition(this FileSearchTool tool)
- {
- Throw.IfNull(tool);
-
- // TODO: Add support for FileSearchToolDefinitionDetails.
-
- return new FileSearchToolDefinition();
- }
-
- ///
- /// Creates an from a .
- ///
- /// Instance of
- /// A new instance configured with the vector store IDs.
- internal static OpenAI.Responses.FileSearchTool CreateFileSearchTool(this FileSearchTool tool)
- {
- Throw.IfNull(tool);
-
- return new OpenAI.Responses.FileSearchTool(tool.GetVectorStoreIds());
- }
-
- ///
- /// Get the vector store IDs for the specified .
- ///
- /// Instance of
- internal static List? GetVectorStoreIds(this FileSearchTool tool)
- {
- return tool.VectorStoreIds?.LiteralValue.ToList();
- }
-
- internal static IList? GetVectorStoreConfigurations(this FileSearchTool tool)
- {
- var dataSources = tool.ExtensionData?.GetPropertyOrNull(InitializablePropertyPath.Create("options.configurations"));
- return dataSources?.Values.Select(value => value.CreateVectorStoreConfiguration()).ToList();
- }
-
- internal static VectorStoreConfigurations CreateVectorStoreConfiguration(this RecordDataValue value)
- {
- Throw.IfNull(value);
-
- var storeName = value.GetPropertyOrNull(InitializablePropertyPath.Create("storeName"))?.Value;
- Throw.IfNullOrEmpty(storeName);
-
- var dataSources = value.GetDataSources();
- Throw.IfNull(dataSources);
-
- return new VectorStoreConfigurations(storeName, new VectorStoreConfiguration(dataSources));
- }
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FunctionToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FunctionToolExtensions.cs
deleted file mode 100644
index 73bd9b41b2..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/FunctionToolExtensions.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System;
-using Azure.AI.Agents.Persistent;
-using Microsoft.Shared.Diagnostics;
-using OpenAI.Responses;
-
-namespace Microsoft.Bot.ObjectModel;
-
-///
-/// Extension methods for .
-///
-public static class FunctionToolExtensions
-{
- ///
- /// Creates a from a .
- ///
- /// Instance of
- internal static FunctionToolDefinition CreateFunctionToolDefinition(this InvokeClientTaskAction tool)
- {
- Throw.IfNull(tool);
- Throw.IfNull(tool.Name);
-
- BinaryData parameters = tool.GetParameters();
-
- return new FunctionToolDefinition(
- name: tool.Name,
- description: tool.Description,
- parameters: parameters);
- }
-
- ///
- /// Creates a from a .
- ///
- /// Instance of
- /// A new instance configured with the function name, parameters, and description.
- internal static FunctionTool CreateFunctionTool(this InvokeClientTaskAction tool)
- {
- Throw.IfNull(tool);
- Throw.IfNull(tool.Name);
-
- BinaryData parameters = tool.GetParameters();
-
- return new FunctionTool(
- functionName: tool.Name,
- functionParameters: parameters,
- strictModeEnabled: null)
- {
- FunctionDescription = tool.Description
- };
- }
-
- ///
- /// Creates the parameters schema for a .
- ///
- /// Instance of
- internal static BinaryData GetParameters(this InvokeClientTaskAction tool)
- {
- Throw.IfNull(tool);
-
- var parameters = tool.ClientActionInputSchema?.GetSchema().ToString() ?? DefaultSchema;
-
- return new BinaryData(parameters);
- }
-
- private const string DefaultSchema = "{\"type\":\"object\",\"properties\":{},\"additionalProperties\":false}";
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedCodeInterpreterToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedCodeInterpreterToolExtensions.cs
deleted file mode 100644
index da769856dd..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedCodeInterpreterToolExtensions.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using Azure.AI.Agents.Persistent;
-using Microsoft.Bot.ObjectModel;
-using Microsoft.Shared.Diagnostics;
-
-namespace Microsoft.Extensions.AI;
-
-///
-/// Extension methods for .
-///
-internal static class HostedCodeInterpreterToolExtensions
-{
- ///
- /// Creates a from a .
- ///
- /// Instance of
- internal static CodeInterpreterToolDefinition CreateHostedCodeInterpreterToolDefinition(this HostedCodeInterpreterTool tool)
- {
- Throw.IfNull(tool);
-
- return new CodeInterpreterToolDefinition();
- }
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedFileSearchToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedFileSearchToolExtensions.cs
deleted file mode 100644
index 846e28f226..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedFileSearchToolExtensions.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using Azure.AI.Agents.Persistent;
-using Microsoft.Shared.Diagnostics;
-
-namespace Microsoft.Extensions.AI;
-
-///
-/// Extension methods for .
-///
-internal static class HostedFileSearchToolExtensions
-{
- ///
- /// Creates a from a .
- ///
- /// Instance of
- internal static FileSearchToolDefinition CreateFileSearchToolDefinition(this HostedFileSearchTool tool)
- {
- Throw.IfNull(tool);
-
- // TODO: Add support for FileSearchToolDefinitionDetails.
-
- return new FileSearchToolDefinition();
- }
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedMcpServerToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedMcpServerToolExtensions.cs
deleted file mode 100644
index a879a105bc..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedMcpServerToolExtensions.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System.Linq;
-using Azure.AI.Agents.Persistent;
-using Microsoft.Shared.Diagnostics;
-
-namespace Microsoft.Extensions.AI;
-
-///
-/// Extension methods for .
-///
-internal static class HostedMcpServerToolExtensions
-{
- ///
- /// Creates a from a .
- ///
- /// Instance of
- internal static MCPToolDefinition CreateMcpToolDefinition(this HostedMcpServerTool tool)
- {
- Throw.IfNull(tool);
- Throw.IfNull(tool.ServerName);
- Throw.IfNull(tool.ServerAddress);
-
- var definition = new MCPToolDefinition(tool.ServerName, tool.ServerAddress);
- tool.AllowedTools?.ToList().ForEach(definition.AllowedTools.Add);
- return definition;
- }
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedWebSearchToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedWebSearchToolExtensions.cs
deleted file mode 100644
index f13c0ec2d4..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/HostedWebSearchToolExtensions.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using Azure.AI.Agents.Persistent;
-using Microsoft.Shared.Diagnostics;
-
-namespace Microsoft.Extensions.AI;
-
-///
-/// Extension methods for .
-///
-internal static class HostedWebSearchToolExtensions
-{
- ///
- /// Creates a from a .
- ///
- /// Instance of
- internal static BingGroundingToolDefinition CreateBingGroundingToolDefinition(this HostedWebSearchTool tool)
- {
- Throw.IfNull(tool);
-
- // TODO: Add support for BingGroundingSearchToolParameters.
- var parameters = new BingGroundingSearchToolParameters([]);
-
- return new BingGroundingToolDefinition(parameters);
- }
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/McpServerToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/McpServerToolExtensions.cs
deleted file mode 100644
index 0e74f53e9a..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/McpServerToolExtensions.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System;
-using Azure.AI.Agents.Persistent;
-using Microsoft.Shared.Diagnostics;
-using OpenAI.Responses;
-
-namespace Microsoft.Bot.ObjectModel;
-
-///
-/// Extension methods for .
-///
-internal static class McpServerToolExtensions
-{
- ///
- /// Creates a from a .
- ///
- /// Instance of
- internal static MCPToolDefinition CreateMcpToolDefinition(this McpServerTool tool)
- {
- Throw.IfNull(tool);
- Throw.IfNull(tool.ServerName?.LiteralValue);
- Throw.IfNull(tool.Connection);
-
- // TODO: Add support for additional properties
-
- var connection = tool.Connection as AnonymousConnection ?? throw new ArgumentException($"Only AnonymousConnection is supported for MCP Server Tool connections. Actual connection type: {tool.Connection.GetType().Name}", nameof(tool));
- var serverUrl = connection.Endpoint?.LiteralValue;
- Throw.IfNullOrEmpty(serverUrl, nameof(connection.Endpoint));
-
- return new MCPToolDefinition(tool.ServerName?.LiteralValue, serverUrl);
- }
-
- ///
- /// Creates a from a .
- ///
- /// Instance of
- /// A new instance configured with the server name and URL.
- internal static McpTool CreateMcpTool(this McpServerTool tool)
- {
- Throw.IfNull(tool);
- Throw.IfNull(tool.ServerName?.LiteralValue);
- Throw.IfNull(tool.Connection);
-
- // TODO: Add support for headers
-
- var connection = tool.Connection as AnonymousConnection ?? throw new ArgumentException("Only AnonymousConnection is supported for MCP Server Tool connections.", nameof(tool));
- var serverUrl = connection.Endpoint?.LiteralValue;
- Throw.IfNullOrEmpty(serverUrl, nameof(connection.Endpoint));
-
- return new McpTool(tool.ServerName?.LiteralValue, serverUrl);
- }
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/PromptAgentExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/PromptAgentExtensions.cs
deleted file mode 100644
index 3fb7c64c1b..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/PromptAgentExtensions.cs
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Azure.AI.Agents.Persistent;
-using Microsoft.Shared.Diagnostics;
-using OpenAI.Responses;
-
-namespace Microsoft.Bot.ObjectModel;
-
-///
-/// Extension methods for .
-///
-internal static class PromptAgentExtensions
-{
- ///
- /// Return the Foundry tool definitions which corresponds with the provided .
- ///
- /// Instance of
- internal static IEnumerable GetToolDefinitions(this GptComponentMetadata promptAgent)
- {
- Throw.IfNull(promptAgent);
-
- return promptAgent.Tools.Select(tool =>
- {
- return tool switch
- {
- CodeInterpreterTool codeInterpreterTool => codeInterpreterTool.CreateCodeInterpreterToolDefinition(),
- InvokeClientTaskAction functionTool => functionTool.CreateFunctionToolDefinition(),
- FileSearchTool fileSearchTool => fileSearchTool.CreateFileSearchToolDefinition(),
- WebSearchTool webSearchTool => webSearchTool.CreateBingGroundingToolDefinition(),
- McpServerTool mcpServerTool => mcpServerTool.CreateMcpToolDefinition(),
- // TODO: Add other tool types as custom tools
- // AzureAISearch
- // AzureFunction
- // OpenApi
- _ => throw new NotSupportedException($"Unable to create tool definition because of unsupported tool type: {tool.Kind}"),
- };
- }).ToList();
- }
-
- ///
- /// Return the Foundry tool resources which corresponds with the provided .
- ///
- /// Instance of
- internal static ToolResources GetToolResources(this GptComponentMetadata promptAgent)
- {
- Throw.IfNull(promptAgent);
-
- var toolResources = new ToolResources();
-
- var codeInterpreter = promptAgent.GetCodeInterpreterToolResource();
- if (codeInterpreter is not null)
- {
- toolResources.CodeInterpreter = codeInterpreter;
- }
-
- var fileSearch = promptAgent.GetFileSearchToolResource();
- if (fileSearch is not null)
- {
- toolResources.FileSearch = fileSearch;
- }
-
- // TODO Handle MCP tool resources
-
- return toolResources;
- }
-
- ///
- /// Returns the Foundry response tools which correspond with the provided .
- ///
- /// Instance of .
- /// A collection of instances corresponding to the tools defined in the agent.
- internal static IEnumerable GetResponseTools(this GptComponentMetadata promptAgent)
- {
- Throw.IfNull(promptAgent);
-
- return promptAgent.Tools.Select(tool =>
- {
- return tool switch
- {
- CodeInterpreterTool codeInterpreterTool => codeInterpreterTool.CreateCodeInterpreterTool(),
- InvokeClientTaskAction functionTool => functionTool.CreateFunctionTool(),
- FileSearchTool fileSearchTool => fileSearchTool.CreateFileSearchTool(),
- WebSearchTool webSearchTool => webSearchTool.CreateWebSearchTool(),
- McpServerTool mcpServerTool => mcpServerTool.CreateMcpTool(),
- // TODO: Add other tool types as custom tools
- // AzureAISearch
- // AzureFunction
- // OpenApi
- _ => throw new NotSupportedException($"Unable to create response tool because of unsupported tool type: {tool.Kind}"),
- };
- }).ToList();
- }
-
- #region private
- private static CodeInterpreterToolResource? GetCodeInterpreterToolResource(this GptComponentMetadata promptAgent)
- {
- Throw.IfNull(promptAgent);
-
- CodeInterpreterToolResource? resource = null;
-
- var codeInterpreter = (CodeInterpreterTool?)promptAgent.GetFirstAgentTool();
- if (codeInterpreter is not null)
- {
- var fileIds = codeInterpreter.GetFileIds();
- var dataSources = codeInterpreter.GetDataSources();
- if (fileIds is not null || dataSources is not null)
- {
- resource = new CodeInterpreterToolResource();
- fileIds?.ForEach(id => resource.FileIds.Add(id));
- dataSources?.ForEach(ds => resource.DataSources.Add(ds));
- }
- }
-
- return resource;
- }
-
- private static FileSearchToolResource? GetFileSearchToolResource(this GptComponentMetadata promptAgent)
- {
- Throw.IfNull(promptAgent);
-
- var fileSearch = (FileSearchTool?)promptAgent.GetFirstAgentTool();
- if (fileSearch is not null)
- {
- var vectorStoreIds = fileSearch.GetVectorStoreIds();
- var vectorStores = fileSearch.GetVectorStoreConfigurations();
- if (vectorStoreIds is not null || vectorStores is not null)
- {
- return new FileSearchToolResource(vectorStoreIds, vectorStores);
- }
- }
-
- return null;
- }
-
- private static TaskAction? GetFirstAgentTool(this GptComponentMetadata promptAgent)
- {
- return promptAgent.Tools.FirstOrDefault(tool => tool is T);
- }
- #endregion
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataTypeExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataTypeExtensions.cs
deleted file mode 100644
index 24c172c888..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataTypeExtensions.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System;
-using Microsoft.Extensions.AI;
-using Microsoft.Shared.Diagnostics;
-
-namespace Microsoft.Bot.ObjectModel;
-
-///
-/// Extension methods for .
-///
-internal static class RecordDataTypeExtensions
-{
- ///
- /// Creates a from a .
- ///
- /// Instance of
-#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
-#pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
- internal static BinaryData? AsBinaryData(this RecordDataType recordDataType)
- {
- Throw.IfNull(recordDataType);
-
- if (recordDataType.Properties.Count == 0)
- {
- return null;
- }
-
- return BinaryData.FromObjectAsJson(
- new
- {
- type = "json_schema",
- schema =
- new
- {
- type = "object",
- properties = recordDataType.Properties.AsObjectDictionary(),
- additionalProperties = false
- }
- }
- );
- }
-#pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
-#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataValueExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataValueExtensions.cs
deleted file mode 100644
index a2c4d490d6..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/RecordDataValueExtensions.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System.Collections.Generic;
-using System.Linq;
-using Azure.AI.Agents.Persistent;
-using Microsoft.Shared.Diagnostics;
-
-namespace Microsoft.Bot.ObjectModel;
-
-///
-/// Extension methods for .
-///
-internal static class RecordDataValueExtensions
-{
- ///
- /// Gets the data sources from the specified .
- ///
- internal static List? GetDataSources(this RecordDataValue value)
- {
- var dataSources = value.GetPropertyOrNull(InitializablePropertyPath.Create("options.data_sources"));
- return dataSources?.Values.Select(dataSource => dataSource.CreateDataSource()).ToList();
- }
-
- ///
- /// Creates a new instance of using the specified .
- ///
- internal static VectorStoreDataSource CreateDataSource(this RecordDataValue value)
- {
- Throw.IfNull(value);
-
- string? assetIdentifier = value.GetPropertyOrNull(InitializablePropertyPath.Create("assetIdentifier"))?.Value;
- Throw.IfNullOrEmpty(assetIdentifier);
-
- string? assetType = value.GetPropertyOrNull(InitializablePropertyPath.Create("assetType"))?.Value;
- Throw.IfNullOrEmpty(assetType);
-
- return new VectorStoreDataSource(assetIdentifier, new VectorStoreDataSourceAssetType(assetType));
- }
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/WebSearchToolExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/WebSearchToolExtensions.cs
deleted file mode 100644
index b0f65442af..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Extensions/WebSearchToolExtensions.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using Azure.AI.Agents.Persistent;
-using Microsoft.Shared.Diagnostics;
-
-namespace Microsoft.Bot.ObjectModel;
-
-///
-/// Extension methods for .
-///
-internal static class WebSearchToolExtensions
-{
- ///
- /// Creates a from a .
- ///
- /// Instance of
- internal static BingGroundingToolDefinition CreateBingGroundingToolDefinition(this WebSearchTool tool)
- {
- Throw.IfNull(tool);
-
- // TODO: Add support for BingGroundingSearchToolParameters.
- var parameters = new BingGroundingSearchToolParameters([]);
-
- return new BingGroundingToolDefinition(parameters);
- }
-
- ///
- /// Creates a from a .
- ///
- /// Instance of
- /// A new instance.
- internal static OpenAI.Responses.WebSearchTool CreateWebSearchTool(this WebSearchTool tool)
- {
- Throw.IfNull(tool);
-
- return new OpenAI.Responses.WebSearchTool();
- }
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryAgentFactory.cs
deleted file mode 100644
index 148e251b18..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryAgentFactory.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using Azure.AI.Agents.Persistent;
-using Azure.Core;
-using Microsoft.Bot.ObjectModel;
-using Microsoft.Extensions.Configuration;
-using Microsoft.PowerFx;
-using Microsoft.Shared.Diagnostics;
-
-namespace Microsoft.Agents.AI;
-
-///
-/// Provides an which creates instances of using a .
-///
-public sealed class FoundryAgentFactory : PromptAgentFactory
-{
- private readonly PersistentAgentsClient? _agentClient;
- private readonly TokenCredential? _tokenCredential;
-
- ///
- /// Creates a new instance of the class with an associated .
- ///
- /// The instance to use for creating agents.
- /// Optional , if none is provided a default instance will be created.
- /// The instance to use for configuration.
- public FoundryAgentFactory(PersistentAgentsClient agentClient, RecalcEngine? engine = null, IConfiguration? configuration = null) : base(engine, configuration)
- {
- Throw.IfNull(agentClient);
-
- this._agentClient = agentClient;
- }
-
- ///
- /// Creates a new instance of the class with an associated .
- ///
- /// The to use for authenticating requests.
- /// Optional , if none is provided a default instance will be created.
- /// The instance to use for configuration.
- public FoundryAgentFactory(TokenCredential tokenCredential, RecalcEngine? engine = null, IConfiguration? configuration = null) : base(engine, configuration)
- {
- Throw.IfNull(tokenCredential);
-
- this._tokenCredential = tokenCredential;
- }
-
- ///
- public override async Task TryCreateAsync(GptComponentMetadata promptAgent, CancellationToken cancellationToken = default)
- {
- Throw.IfNull(promptAgent);
-
- var agentClient = this._agentClient ?? this.CreateAgentClient(promptAgent);
-
- var modelId = promptAgent.Model?.ModelNameHint;
- if (string.IsNullOrEmpty(modelId))
- {
- throw new InvalidOperationException("The model id must be specified in the agent definition model to create a foundry agent.");
- }
-
- var modelOptions = promptAgent.Model?.Options;
-
- /*
- var promptAgentDefinition = new PromptAgentDefinition(model: modelId)
- {
- Instructions = promptAgent.Instructions?.ToTemplateString(),
- Temperature = (float?)modelOptions?.Temperature?.LiteralValue,
- TopP = (float?)modelOptions?.TopP?.LiteralValue,
- };
-
- foreach (var tool in promptAgent.GetResponseTools())
- {
- promptAgentDefinition.Tools.Add(tool);
- }
-
- var agentVersionCreationOptions = new AgentVersionCreationOptions(promptAgentDefinition);
-
- var metadata = promptAgent.Metadata?.ToDictionary();
- if (metadata is not null)
- {
- foreach (var kvp in metadata)
- {
- agentVersionCreationOptions.Metadata.Add(kvp.Key, kvp.Value);
- }
- }
-
- var agentVersion = await agentClient.CreateAgentVersionAsync(agentName: promptAgent.Name, options: agentVersionCreationOptions, cancellationToken: cancellationToken).ConfigureAwait(false);
-
- return agentClient.GetAIAgent(agentVersion, cancellationToken: cancellationToken);
- */
-
- var createPersistentAgentResponse = agentClient.Administration.CreateAgent(
- model: modelId,
- name: promptAgent.Name,
- instructions: promptAgent.Instructions?.ToTemplateString(),
- tools: tools,
- toolResources: toolResources,
- temperature: (float?)modelOptions?.Temperature?.LiteralValue,
- topP: (float?)modelOptions?.TopP?.LiteralValue,
- responseFormat: responseFormat,
- metadata: promptAgent.Metadata?.ToDictionary(),
- cancellationToken: cancellationToken);
-
- // Get a local proxy for the agent to work with.
- return agentClient.GetAIAgent(createPersistentAgentResponse.Value.Id, clientFactory: null, services: null, cancellationToken: cancellationToken);
- }
-
- private PersistentAgentsClient CreateAgentClient(GptComponentMetadata promptAgent)
- {
- var externalModel = promptAgent.Model as CurrentModels;
- var connection = externalModel?.Connection as RemoteConnection;
- if (connection is not null)
- {
- var endpoint = connection.Endpoint?.Eval(this.Engine);
- if (string.IsNullOrEmpty(endpoint))
- {
- throw new InvalidOperationException("The endpoint must be specified in the agent definition model connection to create an AgentClient.");
- }
-
- if (this._tokenCredential is null)
- {
- throw new InvalidOperationException("A TokenCredential must be registered in the service provider to create an AgentClient.");
- }
-
- return new PersistentAgentsClient(endpoint, this._tokenCredential);
- }
-
- throw new InvalidOperationException("A PersistentAgentsClient must be registered in the service provider or a RemoteConnection must be specified in the agent definition model connection to create a PersistentAgentsClient.");
- }
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryPersistentAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryPersistentAgentFactory.cs
deleted file mode 100644
index ae9bc7756e..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/FoundryPersistentAgentFactory.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using Azure.AI.Agents.Persistent;
-using Azure.Core;
-using Microsoft.Bot.ObjectModel;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Shared.Diagnostics;
-
-namespace Microsoft.Agents.AI;
-
-///
-/// Provides an which creates instances of using a .
-///
-public sealed class FoundryPersistentAgentFactory : AgentFactory
-{
- private readonly PersistentAgentsClient? _agentClient;
- private readonly TokenCredential? _tokenCredential;
-
- ///
- /// Creates a new instance of the class with an associated .
- ///
- /// The instance to use for creating agents.
- /// The instance to use for configuration.
- public FoundryPersistentAgentFactory(PersistentAgentsClient agentClient, IConfiguration? configuration = null) : base(configuration)
- {
- Throw.IfNull(agentClient);
-
- this._agentClient = agentClient;
- }
-
- ///
- /// Creates a new instance of the class with an associated .
- ///
- /// The to use for authenticating requests.
- /// The instance to use for configuration.
- public FoundryPersistentAgentFactory(TokenCredential tokenCredential, IConfiguration? configuration = null) : base(configuration)
- {
- Throw.IfNull(tokenCredential);
-
- this._tokenCredential = tokenCredential;
- }
-
- ///
- public override async Task TryCreateAsync(GptComponentMetadata promptAgent, CancellationToken cancellationToken = default)
- {
- Throw.IfNull(promptAgent);
-
- var agentClient = this._agentClient ?? this.CreatePersistentAgentClient(promptAgent);
-
- var modelId = promptAgent.Model?.ModelNameHint;
- if (string.IsNullOrEmpty(modelId))
- {
- throw new InvalidOperationException("The model id must be specified in the agent definition model to create a foundry agent.");
- }
-
- //var outputSchema = promptAgent.OutputType; TODO: Fix converting RecordDataType to BinaryData
- var modelOptions = promptAgent.Model?.Options;
-
- return await agentClient.CreateAIAgentAsync(
- model: modelId,
- name: promptAgent.Name,
- instructions: promptAgent.Instructions?.ToTemplateString(),
- tools: promptAgent.GetToolDefinitions(),
- toolResources: promptAgent.GetToolResources(),
- temperature: (float?)modelOptions?.Temperature?.LiteralValue,
- topP: (float?)modelOptions?.TopP?.LiteralValue,
- //responseFormat: outputSchema.AsBinaryData(), TODO: Fix converting RecordDataType to BinaryData
- metadata: promptAgent.Metadata?.ToDictionary(),
- cancellationToken: cancellationToken).ConfigureAwait(false);
- }
-
- private PersistentAgentsClient CreatePersistentAgentClient(GptComponentMetadata promptAgent)
- {
- var externalModel = promptAgent.Model as CurrentModels;
- var connection = externalModel?.Connection as RemoteConnection;
- if (connection is not null)
- {
- var endpoint = connection.Endpoint?.Eval(this.Engine);
- if (string.IsNullOrEmpty(endpoint))
- {
- throw new InvalidOperationException("The endpoint must be specified in the agent definition model connection to create an PersistentAgentsClient.");
- }
- if (this._tokenCredential is null)
- {
- throw new InvalidOperationException("A TokenCredential must be registered in the service provider to create an PersistentAgentsClient.");
- }
- return new PersistentAgentsClient(endpoint, this._tokenCredential);
- }
-
- throw new InvalidOperationException("A PersistentAgentsClient must be registered in the service provider or a FoundryConnection must be specified in the agent definition model connection to create an PersistentAgentsClient.");
- }
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAssistantAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAssistantAgentFactory.cs
deleted file mode 100644
index 621736e6dd..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAssistantAgentFactory.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using Azure.AI.Agents.Persistent;
-using Azure.Core;
-using Microsoft.Bot.ObjectModel;
-using Microsoft.Extensions.AI;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Logging;
-using Microsoft.Shared.Diagnostics;
-using OpenAI;
-using OpenAI.Assistants;
-
-namespace Microsoft.Agents.AI;
-
-///
-/// Provides an which creates instances of using a .
-///
-public sealed class OpenAIAssistantAgentFactory : OpenAIAgentFactory
-{
- ///
- /// Creates a new instance of the class.
- ///
- public OpenAIAssistantAgentFactory(IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(configuration, loggerFactory)
- {
- this._functions = functions;
- }
-
- ///
- /// Creates a new instance of the class.
- ///
- public OpenAIAssistantAgentFactory(AssistantClient assistantClient, IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(configuration, loggerFactory)
- {
- Throw.IfNull(assistantClient);
-
- this._assistantClient = assistantClient;
- this._functions = functions;
- }
-
- ///
- /// Creates a new instance of the class.
- ///
- public OpenAIAssistantAgentFactory(Uri endpoint, TokenCredential tokenCredential, IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(endpoint, tokenCredential, configuration, loggerFactory)
- {
- this._functions = functions;
- }
-
- ///
- public override async Task TryCreateAsync(GptComponentMetadata promptAgent, CancellationToken cancellationToken = default)
- {
- Throw.IfNull(promptAgent);
-
- var model = promptAgent.Model as CurrentModels;
- var apiType = model?.ApiType;
- if (apiType?.IsUnknown() == false || apiType?.UnknownValue?.Equals(API_TYPE_ASSISTANTS, StringComparison.OrdinalIgnoreCase) == false)
- {
- return null;
- }
-
- var options = new ChatClientAgentOptions()
- {
- Name = promptAgent.Name,
- Description = promptAgent.Description,
- Instructions = promptAgent.Instructions?.ToTemplateString(),
- ChatOptions = promptAgent.GetChatOptions(this._functions),
- };
-
- AssistantClient? assistantClient = this._assistantClient ?? this.CreateAssistantClient(promptAgent);
- if (assistantClient is not null)
- {
- var modelId = promptAgent.Model?.ModelNameHint;
- Throw.IfNullOrEmpty(modelId, "The model id must be specified in the agent definition to create an OpenAI Assistant.");
- Throw.IfNullOrEmpty(promptAgent.Instructions?.ToTemplateString(), "The instructions must be specified in the agent definition to create an OpenAI Assistant.");
-
- return await assistantClient.CreateAIAgentAsync(
- modelId,
- options
- ).ConfigureAwait(false);
- }
-
- return null;
- }
-
- #region private
- private readonly AssistantClient? _assistantClient;
- private readonly IList? _functions;
-
- private const string API_TYPE_ASSISTANTS = "ASSISTANTS";
- #endregion
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIResponseAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIResponseAgentFactory.cs
deleted file mode 100644
index 6da009135d..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIResponseAgentFactory.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using Azure.AI.Agents.Persistent;
-using Azure.Core;
-using Microsoft.Bot.ObjectModel;
-using Microsoft.Extensions.AI;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Logging;
-using Microsoft.Shared.Diagnostics;
-using OpenAI.Responses;
-
-namespace Microsoft.Agents.AI;
-
-///
-/// Provides an which creates instances of using a .
-///
-public sealed class OpenAIResponseAgentFactory : OpenAIAgentFactory
-{
- ///
- /// Creates a new instance of the class.
- ///
- public OpenAIResponseAgentFactory(IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(configuration, loggerFactory)
- {
- this._functions = functions;
- }
-
- ///
- /// Creates a new instance of the class.
- ///
- public OpenAIResponseAgentFactory(OpenAIResponseClient responseClient, IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(configuration, loggerFactory)
- {
- Throw.IfNull(responseClient);
-
- this._responseClient = responseClient;
- this._functions = functions;
- }
-
- ///
- /// Creates a new instance of the class.
- ///
- public OpenAIResponseAgentFactory(Uri endpoint, TokenCredential tokenCredential, IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(endpoint, tokenCredential, configuration, loggerFactory)
- {
- this._functions = functions;
- }
-
- ///
- public override async Task TryCreateAsync(GptComponentMetadata promptAgent, CancellationToken cancellationToken = default)
- {
- Throw.IfNull(promptAgent);
-
- var model = promptAgent.Model as CurrentModels;
- var apiType = model?.ApiType;
- if (apiType?.IsUnknown() == true || apiType?.Value != ModelApiType.Responses)
- {
- return null;
- }
-
- var options = new ChatClientAgentOptions()
- {
- Name = promptAgent.Name,
- Description = promptAgent.Description,
- Instructions = promptAgent.Instructions?.ToTemplateString(),
- ChatOptions = promptAgent.GetChatOptions(this._functions),
- };
-
- var responseClient = this._responseClient ?? this.CreateResponseClient(promptAgent);
- if (responseClient is not null)
- {
- return new ChatClientAgent(
- responseClient.AsIChatClient(),
- options,
- this.LoggerFactory);
- }
-
- return null;
- }
-
- #region private
- private readonly OpenAIResponseClient? _responseClient;
- private readonly IList? _functions;
- #endregion
-}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/AzureAIPromptAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/AzureAIPromptAgentFactory.cs
new file mode 100644
index 0000000000..e8ec6d7028
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/AzureAIPromptAgentFactory.cs
@@ -0,0 +1,91 @@
+// Copyright (c) Microsoft. All rights reserved.
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.AI.Projects;
+using Azure.Core;
+using Microsoft.Agents.ObjectModel;
+using Microsoft.Extensions.Configuration;
+using Microsoft.PowerFx;
+using Microsoft.Shared.Diagnostics;
+
+namespace Microsoft.Agents.AI;
+
+///
+/// Provides an which creates instances of using a .
+///
+public sealed class AzureAIPromptAgentFactory : PromptAgentFactory
+{
+ private readonly AIProjectClient? _projectClient;
+ private readonly TokenCredential? _tokenCredential;
+
+ ///
+ /// Creates a new instance of the class with an associated .
+ ///
+ /// The instance to use for creating agents.
+ /// Optional , if none is provided a default instance will be created.
+ /// The instance to use for configuration.
+ public AzureAIPromptAgentFactory(AIProjectClient projectClient, RecalcEngine? engine = null, IConfiguration? configuration = null) : base(engine, configuration)
+ {
+ Throw.IfNull(projectClient);
+
+ this._projectClient = projectClient;
+ }
+
+ ///
+ /// Creates a new instance of the class with an associated .
+ ///
+ /// The to use for authenticating requests.
+ /// Optional , if none is provided a default instance will be created.
+ /// The instance to use for configuration.
+ public AzureAIPromptAgentFactory(TokenCredential tokenCredential, RecalcEngine? engine = null, IConfiguration? configuration = null) : base(engine, configuration)
+ {
+ Throw.IfNull(tokenCredential);
+
+ this._tokenCredential = tokenCredential;
+ }
+
+ ///
+ public override async Task TryCreateAsync(GptComponentMetadata promptAgent, CancellationToken cancellationToken = default)
+ {
+ Throw.IfNull(promptAgent);
+ Throw.IfNullOrEmpty(promptAgent.Name);
+
+ var projectClient = this._projectClient ?? this.CreateAIProjectClient(promptAgent);
+
+ var modelId = promptAgent.Model?.ModelNameHint;
+ if (string.IsNullOrEmpty(modelId))
+ {
+ throw new InvalidOperationException("The model id must be specified in the agent definition model to create a foundry agent.");
+ }
+
+ return await projectClient.CreateAIAgentAsync(
+ name: promptAgent.Name,
+ model: modelId,
+ instructions: promptAgent.Instructions?.ToTemplateString() ?? string.Empty,
+ description: promptAgent.Description,
+ tools: promptAgent.GetAITools(),
+ cancellationToken: cancellationToken).ConfigureAwait(false);
+ }
+
+ private AIProjectClient CreateAIProjectClient(GptComponentMetadata promptAgent)
+ {
+ var externalModel = promptAgent.Model as CurrentModels;
+ var connection = externalModel?.Connection as RemoteConnection;
+ if (connection is not null)
+ {
+ var endpoint = connection.Endpoint?.Eval(this.Engine);
+ if (string.IsNullOrEmpty(endpoint))
+ {
+ throw new InvalidOperationException("The endpoint must be specified in the agent definition model connection to create an AIProjectClient.");
+ }
+ if (this._tokenCredential is null)
+ {
+ throw new InvalidOperationException("A TokenCredential must be registered in the service provider to create an AIProjectClient.");
+ }
+ return new AIProjectClient(new Uri(endpoint), this._tokenCredential);
+ }
+
+ throw new InvalidOperationException("A AIProjectClient must be registered in the service provider or a FoundryConnection must be specified in the agent definition model connection to create an AIProjectClient.");
+ }
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/BaseOpenAIPromptAgentFactory.cs
similarity index 81%
rename from dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAgentFactory.cs
rename to dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/BaseOpenAIPromptAgentFactory.cs
index a598292e75..3f84776d67 100644
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIAgentFactory.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/BaseOpenAIPromptAgentFactory.cs
@@ -3,9 +3,10 @@
using System.ClientModel;
using Azure.AI.OpenAI;
using Azure.Core;
-using Microsoft.Bot.ObjectModel;
+using Microsoft.Agents.ObjectModel;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
+using Microsoft.PowerFx;
using Microsoft.Shared.Diagnostics;
using OpenAI;
using OpenAI.Assistants;
@@ -15,22 +16,22 @@
namespace Microsoft.Agents.AI;
///
-/// Provides an abstract base class.
+/// Provides an abstract base class.
///
-public abstract class OpenAIAgentFactory : AgentFactory
+public abstract class BaseOpenAIPromptAgentFactory : PromptAgentFactory
{
///
- /// Creates a new instance of the class.
+ /// Creates a new instance of the class.
///
- protected OpenAIAgentFactory(IConfiguration? configuration, ILoggerFactory? loggerFactory) : base(configuration)
+ protected BaseOpenAIPromptAgentFactory(RecalcEngine? engine = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(engine, configuration)
{
this.LoggerFactory = loggerFactory;
}
///
- /// Creates a new instance of the class.
+ /// Creates a new instance of the class.
///
- protected OpenAIAgentFactory(Uri endpoint, TokenCredential tokenCredential, IConfiguration? configuration, ILoggerFactory? loggerFactory) : base(configuration)
+ protected BaseOpenAIPromptAgentFactory(Uri endpoint, TokenCredential tokenCredential, RecalcEngine? engine = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(engine, configuration)
{
Throw.IfNull(endpoint);
Throw.IfNull(tokenCredential);
@@ -88,21 +89,21 @@ protected OpenAIAgentFactory(Uri endpoint, TokenCredential tokenCredential, ICon
}
///
- /// Creates a new instance of the class.
+ /// Creates a new instance of the class.
///
- protected OpenAIResponseClient? CreateResponseClient(GptComponentMetadata promptAgent)
+ protected ResponsesClient? CreateResponseClient(GptComponentMetadata promptAgent)
{
var model = promptAgent.Model as CurrentModels;
var provider = model?.Provider?.Value ?? ModelProvider.OpenAI;
if (provider == ModelProvider.OpenAI)
{
- return this.CreateOpenAIResponseClient(promptAgent);
+ return this.CreateResponsesClient(promptAgent);
}
else if (provider == ModelProvider.AzureOpenAI)
{
Throw.IfNull(this._endpoint, "The connection endpoint must be specified to create an Azure OpenAI client.");
Throw.IfNull(this._tokenCredential, "A token credential must be specified to create an Azure OpenAI client");
- return CreateAzureOpenAIResponseClient(promptAgent, this._endpoint, this._tokenCredential);
+ return CreateAzureResponsesClient(promptAgent, this._endpoint, this._tokenCredential);
}
return null;
@@ -144,20 +145,20 @@ private static AssistantClient CreateAzureOpenAIAssistantClient(GptComponentMeta
return new AzureOpenAIClient(endpoint, tokenCredential).GetAssistantClient();
}
- private OpenAIResponseClient CreateOpenAIResponseClient(GptComponentMetadata promptAgent)
+ private ResponsesClient CreateResponsesClient(GptComponentMetadata promptAgent)
{
var modelId = promptAgent.Model?.ModelNameHint;
Throw.IfNullOrEmpty(modelId, "The model id must be specified in the agent definition to create an OpenAI agent.");
- return this.CreateOpenAIClient(promptAgent).GetOpenAIResponseClient(modelId);
+ return this.CreateOpenAIClient(promptAgent).GetResponsesClient(modelId);
}
- private static OpenAIResponseClient CreateAzureOpenAIResponseClient(GptComponentMetadata promptAgent, Uri endpoint, TokenCredential tokenCredential)
+ private static ResponsesClient CreateAzureResponsesClient(GptComponentMetadata promptAgent, Uri endpoint, TokenCredential tokenCredential)
{
var deploymentName = promptAgent.Model?.ModelNameHint;
Throw.IfNullOrEmpty(deploymentName, "The deployment name (using model.id) must be specified in the agent definition to create an Azure OpenAI agent.");
- return new AzureOpenAIClient(endpoint, tokenCredential).GetOpenAIResponseClient(deploymentName);
+ return new AzureOpenAIClient(endpoint, tokenCredential).GetResponsesClient(deploymentName);
}
private OpenAIClient CreateOpenAIClient(GptComponentMetadata promptAgent)
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/JsonSchemaFunctionParameters.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/JsonSchemaFunctionParameters.cs
similarity index 100%
rename from dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/JsonSchemaFunctionParameters.cs
rename to dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/JsonSchemaFunctionParameters.cs
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Microsoft.Agents.AI.Declarative.AzureAI.Persistent.csproj b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/Microsoft.Agents.AI.Declarative.AzureAI.csproj
similarity index 81%
rename from dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Microsoft.Agents.AI.Declarative.AzureAI.Persistent.csproj
rename to dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/Microsoft.Agents.AI.Declarative.AzureAI.csproj
index a74a845fef..f2b63182ec 100644
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/Microsoft.Agents.AI.Declarative.AzureAI.Persistent.csproj
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/Microsoft.Agents.AI.Declarative.AzureAI.csproj
@@ -22,20 +22,22 @@
-
+
+
-
-
-
+
+
+
+
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIChatAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/OpenAIPromptAgentFactory.cs
similarity index 56%
rename from dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIChatAgentFactory.cs
rename to dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/OpenAIPromptAgentFactory.cs
index f27c8ca6a5..162e9dcebb 100644
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI.Persistent/OpenAIChatAgentFactory.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/OpenAIPromptAgentFactory.cs
@@ -3,34 +3,34 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
-using Azure.AI.Agents.Persistent;
using Azure.Core;
-using Microsoft.Bot.ObjectModel;
+using Microsoft.Agents.ObjectModel;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
+using Microsoft.PowerFx;
using Microsoft.Shared.Diagnostics;
using OpenAI.Chat;
namespace Microsoft.Agents.AI;
///
-/// Provides an which creates instances of using a .
+/// Provides an which creates instances of using a .
///
-public sealed class OpenAIChatAgentFactory : OpenAIAgentFactory
+public sealed class OpenAIPromptAgentFactory : BaseOpenAIPromptAgentFactory
{
///
- /// Creates a new instance of the class.
+ /// Creates a new instance of the class.
///
- public OpenAIChatAgentFactory(IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(configuration, loggerFactory)
+ public OpenAIPromptAgentFactory(IList? functions = null, RecalcEngine? engine = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(engine, configuration, loggerFactory)
{
this._functions = functions;
}
///
- /// Creates a new instance of the class.
+ /// Creates a new instance of the class.
///
- public OpenAIChatAgentFactory(ChatClient chatClient, IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(configuration, loggerFactory)
+ public OpenAIPromptAgentFactory(ChatClient chatClient, IList? functions = null, RecalcEngine? engine = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(engine, configuration, loggerFactory)
{
Throw.IfNull(chatClient);
@@ -39,9 +39,9 @@ public OpenAIChatAgentFactory(ChatClient chatClient, IList? function
}
///
- /// Creates a new instance of the class.
+ /// Creates a new instance of the class.
///
- public OpenAIChatAgentFactory(Uri endpoint, TokenCredential tokenCredential, IList? functions = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(endpoint, tokenCredential, configuration, loggerFactory)
+ public OpenAIPromptAgentFactory(Uri endpoint, TokenCredential tokenCredential, IList? functions = null, RecalcEngine? engine = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(endpoint, tokenCredential, engine, configuration, loggerFactory)
{
this._functions = functions;
}
@@ -62,8 +62,7 @@ public OpenAIChatAgentFactory(Uri endpoint, TokenCredential tokenCredential, ILi
{
Name = promptAgent.Name,
Description = promptAgent.Description,
- Instructions = promptAgent.Instructions?.ToTemplateString(),
- ChatOptions = promptAgent.GetChatOptions(this._functions),
+ ChatOptions = promptAgent.GetChatOptions(this.Engine, this._functions),
};
ChatClient? chatClient = this._chatClient ?? this.CreateChatClient(promptAgent);
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/OpenAIResponsesPromptAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/OpenAIResponsesPromptAgentFactory.cs
new file mode 100644
index 0000000000..d71365a855
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/OpenAIResponsesPromptAgentFactory.cs
@@ -0,0 +1,84 @@
+// Copyright (c) Microsoft. All rights reserved.
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.Core;
+using Microsoft.Agents.ObjectModel;
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Microsoft.PowerFx;
+using Microsoft.Shared.Diagnostics;
+using OpenAI.Responses;
+
+namespace Microsoft.Agents.AI;
+
+///
+/// Provides an which creates instances of using a .
+///
+public sealed class OpenAIResponsesPromptAgentFactory : BaseOpenAIPromptAgentFactory
+{
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenAIResponsesPromptAgentFactory(IList? functions = null, RecalcEngine? engine = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(engine, configuration, loggerFactory)
+ {
+ this._functions = functions;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenAIResponsesPromptAgentFactory(ResponsesClient responsesClient, IList? functions = null, RecalcEngine? engine = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(engine, configuration, loggerFactory)
+ {
+ Throw.IfNull(responsesClient);
+
+ this._responsesClient = responsesClient;
+ this._functions = functions;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public OpenAIResponsesPromptAgentFactory(Uri endpoint, TokenCredential tokenCredential, IList? functions = null, RecalcEngine? engine = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(endpoint, tokenCredential, engine, configuration, loggerFactory)
+ {
+ this._functions = functions;
+ }
+
+ ///
+ public override async Task TryCreateAsync(GptComponentMetadata promptAgent, CancellationToken cancellationToken = default)
+ {
+ Throw.IfNull(promptAgent);
+
+ var model = promptAgent.Model as CurrentModels;
+ var apiType = model?.ApiType;
+ if (apiType?.IsUnknown() == true || apiType?.Value != ModelApiType.Responses)
+ {
+ return null;
+ }
+
+ var options = new ChatClientAgentOptions()
+ {
+ Name = promptAgent.Name,
+ Description = promptAgent.Description,
+ ChatOptions = promptAgent.GetChatOptions(this.Engine, this._functions),
+ };
+
+ var responseClient = this._responsesClient ?? this.CreateResponseClient(promptAgent);
+ if (responseClient is not null)
+ {
+ return new ChatClientAgent(
+ responseClient.AsIChatClient(),
+ options,
+ this.LoggerFactory);
+ }
+
+ return null;
+ }
+
+ #region private
+ private readonly ResponsesClient? _responsesClient;
+ private readonly IList? _functions;
+ #endregion
+}
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative/Extensions/PromptAgentExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Declarative/Extensions/PromptAgentExtensions.cs
index 0da3f18f85..4255738c96 100644
--- a/dotnet/src/Microsoft.Agents.AI.Declarative/Extensions/PromptAgentExtensions.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative/Extensions/PromptAgentExtensions.cs
@@ -58,7 +58,7 @@ public static class PromptAgentExtensions
///
/// Instance of
/// Instance of
- internal static List? GetAITools(this GptComponentMetadata promptAgent, IList? functions)
+ public static List? GetAITools(this GptComponentMetadata promptAgent, IList? functions = null)
{
return promptAgent.Tools.Select(tool =>
{
From a1d5a3546651786b6e18cf2a947fa616bda6571e Mon Sep 17 00:00:00 2001
From: markwallace-microsoft
<127216156+markwallace-microsoft@users.noreply.github.com>
Date: Fri, 30 Jan 2026 15:26:49 +0000
Subject: [PATCH 4/8] Add unit test project for
Microsoft.Agents.AI.Declarative.AzureAI
---
dotnet/agent-framework-dotnet.slnx | 1 +
.../Microsoft.Agents.AI.Declarative.AzureAI.csproj | 1 +
...oft.Agents.AI.Declarative.AzureAI.UnitTests.csproj | 11 +++++++++++
3 files changed, 13 insertions(+)
create mode 100644 dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests.csproj
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 60276808fd..2dc7ef14f9 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -447,6 +447,7 @@
+
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/Microsoft.Agents.AI.Declarative.AzureAI.csproj b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/Microsoft.Agents.AI.Declarative.AzureAI.csproj
index f2b63182ec..3af7c1d385 100644
--- a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/Microsoft.Agents.AI.Declarative.AzureAI.csproj
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/Microsoft.Agents.AI.Declarative.AzureAI.csproj
@@ -47,6 +47,7 @@
+
diff --git a/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests.csproj b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests.csproj
new file mode 100644
index 0000000000..5c304f1572
--- /dev/null
+++ b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests.csproj
@@ -0,0 +1,11 @@
+
+
+
+ $(NoWarn);IDE1006;VSTHRD200
+
+
+
+
+
+
+
From 668bc7dbf7ce4876b491c53e1690a10f00b454ed Mon Sep 17 00:00:00 2001
From: markwallace-microsoft
<127216156+markwallace-microsoft@users.noreply.github.com>
Date: Fri, 30 Jan 2026 17:35:05 +0000
Subject: [PATCH 5/8] Add unit tests for
Microsoft.Agents.AI.Declarative.AzureAI
---
.../Microsoft.Agents.AI.Declarative.csproj | 1 +
.../AzureAIPromptAgentFactoryTests.cs | 137 +++++++++++++++++
...ts.AI.Declarative.AzureAI.UnitTests.csproj | 2 +-
.../OpenAIPromptAgentFactoryTests.cs | 135 +++++++++++++++++
.../OpenAIResponsesPromptAgentFactoryTests.cs | 138 ++++++++++++++++++
5 files changed, 412 insertions(+), 1 deletion(-)
create mode 100644 dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/AzureAIPromptAgentFactoryTests.cs
create mode 100644 dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIPromptAgentFactoryTests.cs
create mode 100644 dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIResponsesPromptAgentFactoryTests.cs
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative/Microsoft.Agents.AI.Declarative.csproj b/dotnet/src/Microsoft.Agents.AI.Declarative/Microsoft.Agents.AI.Declarative.csproj
index 3b75b63236..c9f09ce90d 100644
--- a/dotnet/src/Microsoft.Agents.AI.Declarative/Microsoft.Agents.AI.Declarative.csproj
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative/Microsoft.Agents.AI.Declarative.csproj
@@ -39,6 +39,7 @@
+
diff --git a/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/AzureAIPromptAgentFactoryTests.cs b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/AzureAIPromptAgentFactoryTests.cs
new file mode 100644
index 0000000000..bc4f6cfb9d
--- /dev/null
+++ b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/AzureAIPromptAgentFactoryTests.cs
@@ -0,0 +1,137 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using System.Threading.Tasks;
+using Azure.AI.Projects;
+using Azure.Core;
+using Microsoft.Agents.ObjectModel;
+using Moq;
+
+namespace Microsoft.Agents.AI.Declarative.AzureAI.UnitTests;
+
+///
+/// Unit tests for .
+///
+public sealed class AzureAIPromptAgentFactoryTests
+{
+ [Fact]
+ public void Constructor_WithProjectClient_ThrowsForNull()
+ {
+ // Arrange & Act & Assert
+ Assert.Throws(() => new AzureAIPromptAgentFactory(projectClient: null!));
+ }
+
+ [Fact]
+ public void Constructor_WithTokenCredential_ThrowsForNull()
+ {
+ // Arrange & Act & Assert
+ Assert.Throws(() => new AzureAIPromptAgentFactory(tokenCredential: null!));
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ThrowsForNullPromptAgentAsync()
+ {
+ // Arrange
+ Mock mockCredential = new();
+ AzureAIPromptAgentFactory factory = new(mockCredential.Object);
+
+ // Act & Assert
+ await Assert.ThrowsAsync(() => factory.TryCreateAsync(null!));
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ThrowsForNullOrEmptyNameAsync()
+ {
+ // Arrange
+ Mock mockCredential = new();
+ AzureAIPromptAgentFactory factory = new(mockCredential.Object);
+ GptComponentMetadata promptAgent = new(name: null!);
+
+ // Act & Assert
+ await Assert.ThrowsAsync(() => factory.TryCreateAsync(promptAgent));
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ThrowsForEmptyNameAsync()
+ {
+ // Arrange
+ Mock mockCredential = new();
+ AzureAIPromptAgentFactory factory = new(mockCredential.Object);
+ GptComponentMetadata promptAgent = new(name: string.Empty);
+
+ // Act & Assert
+ await Assert.ThrowsAsync(() => factory.TryCreateAsync(promptAgent));
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ThrowsWhenModelIdIsNullAsync()
+ {
+ // Arrange
+ Mock mockCredential = new();
+ AzureAIPromptAgentFactory factory = new(mockCredential.Object);
+ GptComponentMetadata promptAgent = new("TestAgent");
+
+ // Act & Assert
+ InvalidOperationException exception = await Assert.ThrowsAsync(() => factory.TryCreateAsync(promptAgent));
+ Assert.Contains("model id must be specified", exception.Message);
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ThrowsWhenNoProjectClientAndNoConnectionAsync()
+ {
+ // Arrange
+ Mock mockCredential = new();
+ AzureAIPromptAgentFactory factory = new(mockCredential.Object);
+ GptComponentMetadata promptAgent = CreateTestPromptAgentWithoutConnection();
+
+ // Act & Assert
+ InvalidOperationException exception = await Assert.ThrowsAsync(() => factory.TryCreateAsync(promptAgent));
+ Assert.Contains("AIProjectClient must be registered", exception.Message);
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ThrowsWhenEndpointIsEmptyAsync()
+ {
+ // Arrange
+ Mock mockCredential = new();
+ AzureAIPromptAgentFactory factory = new(mockCredential.Object);
+ GptComponentMetadata promptAgent = CreateTestPromptAgentWithEmptyEndpoint();
+
+ // Act & Assert
+ InvalidOperationException exception = await Assert.ThrowsAsync(() => factory.TryCreateAsync(promptAgent));
+ Assert.Contains("endpoint must be specified", exception.Message);
+ }
+
+ private static GptComponentMetadata CreateTestPromptAgentWithoutConnection()
+ {
+ string agentYaml =
+ """
+ kind: Prompt
+ name: Test Agent
+ description: Test Description
+ instructions: You are a helpful assistant.
+ model:
+ id: gpt-4o
+ """;
+
+ return AgentBotElementYaml.FromYaml(agentYaml);
+ }
+
+ private static GptComponentMetadata CreateTestPromptAgentWithEmptyEndpoint()
+ {
+ string agentYaml =
+ """
+ kind: Prompt
+ name: Test Agent
+ description: Test Description
+ instructions: You are a helpful assistant.
+ model:
+ id: gpt-4o
+ connection:
+ kind: Remote
+ endpoint: ""
+ """;
+
+ return AgentBotElementYaml.FromYaml(agentYaml);
+ }
+}
diff --git a/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests.csproj b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests.csproj
index 5c304f1572..fe9fb91041 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests.csproj
+++ b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests.csproj
@@ -1,4 +1,4 @@
-
+
$(NoWarn);IDE1006;VSTHRD200
diff --git a/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIPromptAgentFactoryTests.cs b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIPromptAgentFactoryTests.cs
new file mode 100644
index 0000000000..3bdc654d4e
--- /dev/null
+++ b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIPromptAgentFactoryTests.cs
@@ -0,0 +1,135 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using System.Threading.Tasks;
+using Microsoft.Agents.ObjectModel;
+using Moq;
+using OpenAI.Chat;
+
+namespace Microsoft.Agents.AI.Declarative.AzureAI.UnitTests;
+
+///
+/// Unit tests for .
+///
+public sealed class OpenAIPromptAgentFactoryTests
+{
+ [Fact]
+ public void Constructor_WithChatClient_ThrowsForNull()
+ {
+ // Arrange & Act & Assert
+ Assert.Throws(() => new OpenAIPromptAgentFactory(chatClient: null!));
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ThrowsForNullPromptAgentAsync()
+ {
+ // Arrange
+ OpenAIPromptAgentFactory factory = new();
+
+ // Act & Assert
+ await Assert.ThrowsAsync(() => factory.TryCreateAsync(null!));
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ThrowsWhenModelIsNullAsync()
+ {
+ // Arrange
+ OpenAIPromptAgentFactory factory = new();
+ GptComponentMetadata promptAgent = new("TestAgent");
+
+ // Act & Assert
+ await Assert.ThrowsAsync(() => factory.TryCreateAsync(null!));
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ReturnsNull_WhenApiTypeIsUnknownAsync()
+ {
+ // Arrange
+ OpenAIPromptAgentFactory factory = new();
+ GptComponentMetadata promptAgent = CreateTestPromptAgent(apiType: "Unknown");
+
+ // Act
+ AIAgent? result = await factory.TryCreateAsync(promptAgent);
+
+ // Assert
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ReturnsNull_WhenApiTypeIsResponsesAsync()
+ {
+ // Arrange
+ OpenAIPromptAgentFactory factory = new();
+ GptComponentMetadata promptAgent = CreateTestPromptAgent(apiType: "Responses");
+
+ // Act
+ AIAgent? result = await factory.TryCreateAsync(promptAgent);
+
+ // Assert
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ReturnsNull_WhenApiTypeIsAssistantsAsync()
+ {
+ // Arrange
+ OpenAIPromptAgentFactory factory = new();
+ GptComponentMetadata promptAgent = CreateTestPromptAgent(apiType: "Assistants");
+
+ // Act
+ AIAgent? result = await factory.TryCreateAsync(promptAgent);
+
+ // Assert
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ReturnsChatClientAgent_WhenChatClientProvidedAsync()
+ {
+ // Arrange
+ ChatClient chatClient = new("gpt-4o", "test-api-key");
+ OpenAIPromptAgentFactory factory = new(chatClient);
+ GptComponentMetadata promptAgent = CreateTestPromptAgent(apiType: "Chat");
+
+ // Act
+ AIAgent? result = await factory.TryCreateAsync(promptAgent);
+
+ // Assert
+ Assert.NotNull(result);
+ Assert.IsType(result);
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ReturnsChatClientAgent_WithCorrectOptionsAsync()
+ {
+ // Arrange
+ ChatClient chatClient = new("gpt-4o", "test-api-key");
+ OpenAIPromptAgentFactory factory = new(chatClient);
+ GptComponentMetadata promptAgent = CreateTestPromptAgent(apiType: "Chat");
+
+ // Act
+ AIAgent? result = await factory.TryCreateAsync(promptAgent);
+
+ // Assert
+ Assert.NotNull(result);
+ ChatClientAgent agent = Assert.IsType(result);
+ Assert.Equal("Test Agent", agent.Name);
+ Assert.Equal("Test Description", agent.Description);
+ }
+
+ private static GptComponentMetadata CreateTestPromptAgent(string apiType)
+ {
+ string agentYaml =
+ $"""
+ kind: Prompt
+ name: Test Agent
+ description: Test Description
+ instructions: You are a helpful assistant.
+ model:
+ id: gpt-4o
+ apiType: {apiType}
+ """;
+
+ return AgentBotElementYaml.FromYaml(agentYaml);
+ }
+}
diff --git a/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIResponsesPromptAgentFactoryTests.cs b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIResponsesPromptAgentFactoryTests.cs
new file mode 100644
index 0000000000..f799eb543e
--- /dev/null
+++ b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIResponsesPromptAgentFactoryTests.cs
@@ -0,0 +1,138 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using System.Threading.Tasks;
+using Microsoft.Agents.ObjectModel;
+using OpenAI;
+using OpenAI.Responses;
+
+namespace Microsoft.Agents.AI.Declarative.AzureAI.UnitTests;
+
+///
+/// Unit tests for .
+///
+public sealed class OpenAIResponsesPromptAgentFactoryTests
+{
+ [Fact]
+ public void Constructor_WithResponsesClient_ThrowsForNull()
+ {
+ // Arrange & Act & Assert
+ Assert.Throws(() => new OpenAIResponsesPromptAgentFactory(responsesClient: null!));
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ThrowsForNullPromptAgentAsync()
+ {
+ // Arrange
+ OpenAIResponsesPromptAgentFactory factory = new();
+
+ // Act & Assert
+ await Assert.ThrowsAsync(() => factory.TryCreateAsync(null!));
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ReturnsNull_WhenModelIsNullAsync()
+ {
+ // Arrange
+ OpenAIResponsesPromptAgentFactory factory = new();
+ GptComponentMetadata promptAgent = new("TestAgent");
+
+ // Act
+ AIAgent? result = await factory.TryCreateAsync(promptAgent);
+
+ // Assert
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ReturnsNull_WhenApiTypeIsUnknownAsync()
+ {
+ // Arrange
+ OpenAIResponsesPromptAgentFactory factory = new();
+ GptComponentMetadata promptAgent = CreateTestPromptAgent(apiType: "Unknown");
+
+ // Act
+ AIAgent? result = await factory.TryCreateAsync(promptAgent);
+
+ // Assert
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ReturnsNull_WhenApiTypeIsChatAsync()
+ {
+ // Arrange
+ OpenAIResponsesPromptAgentFactory factory = new();
+ GptComponentMetadata promptAgent = CreateTestPromptAgent(apiType: "Chat");
+
+ // Act
+ AIAgent? result = await factory.TryCreateAsync(promptAgent);
+
+ // Assert
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ReturnsNull_WhenApiTypeIsAssistantsAsync()
+ {
+ // Arrange
+ OpenAIResponsesPromptAgentFactory factory = new();
+ GptComponentMetadata promptAgent = CreateTestPromptAgent(apiType: "Assistants");
+
+ // Act
+ AIAgent? result = await factory.TryCreateAsync(promptAgent);
+
+ // Assert
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ReturnsChatClientAgent_WhenResponsesClientProvidedAsync()
+ {
+ // Arrange
+ ResponsesClient responsesClient = new OpenAIClient("test-api-key").GetResponsesClient("gpt-4o");
+ OpenAIResponsesPromptAgentFactory factory = new(responsesClient);
+ GptComponentMetadata promptAgent = CreateTestPromptAgent(apiType: "Responses");
+
+ // Act
+ AIAgent? result = await factory.TryCreateAsync(promptAgent);
+
+ // Assert
+ Assert.NotNull(result);
+ Assert.IsType(result);
+ }
+
+ [Fact]
+ public async Task TryCreateAsync_ReturnsChatClientAgent_WithCorrectOptionsAsync()
+ {
+ // Arrange
+ ResponsesClient responsesClient = new OpenAIClient("test-api-key").GetResponsesClient("gpt-4o");
+ OpenAIResponsesPromptAgentFactory factory = new(responsesClient);
+ GptComponentMetadata promptAgent = CreateTestPromptAgent(apiType: "Responses");
+
+ // Act
+ AIAgent? result = await factory.TryCreateAsync(promptAgent);
+
+ // Assert
+ Assert.NotNull(result);
+ ChatClientAgent agent = Assert.IsType(result);
+ Assert.Equal("Test Agent", agent.Name);
+ Assert.Equal("Test Description", agent.Description);
+ }
+
+ private static GptComponentMetadata CreateTestPromptAgent(string apiType)
+ {
+ string agentYaml =
+ $"""
+ kind: Prompt
+ name: Test Agent
+ description: Test Description
+ instructions: You are a helpful assistant.
+ model:
+ id: gpt-4o
+ apiType: {apiType}
+ """;
+
+ return AgentBotElementYaml.FromYaml(agentYaml);
+ }
+}
From 14401f7c73f2e95edaee4871a6cbc97adff092ca Mon Sep 17 00:00:00 2001
From: markwallace-microsoft
<127216156+markwallace-microsoft@users.noreply.github.com>
Date: Fri, 30 Jan 2026 17:49:31 +0000
Subject: [PATCH 6/8] Fix formatting
---
.../AzureAIPromptAgentFactoryTests.cs | 7 +++----
.../OpenAIPromptAgentFactoryTests.cs | 1 -
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/AzureAIPromptAgentFactoryTests.cs b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/AzureAIPromptAgentFactoryTests.cs
index bc4f6cfb9d..270b109e56 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/AzureAIPromptAgentFactoryTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/AzureAIPromptAgentFactoryTests.cs
@@ -1,8 +1,7 @@
-// Copyright (c) Microsoft. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Threading.Tasks;
-using Azure.AI.Projects;
using Azure.Core;
using Microsoft.Agents.ObjectModel;
using Moq;
@@ -104,7 +103,7 @@ public async Task TryCreateAsync_ThrowsWhenEndpointIsEmptyAsync()
private static GptComponentMetadata CreateTestPromptAgentWithoutConnection()
{
- string agentYaml =
+ const string agentYaml =
"""
kind: Prompt
name: Test Agent
@@ -119,7 +118,7 @@ private static GptComponentMetadata CreateTestPromptAgentWithoutConnection()
private static GptComponentMetadata CreateTestPromptAgentWithEmptyEndpoint()
{
- string agentYaml =
+ const string agentYaml =
"""
kind: Prompt
name: Test Agent
diff --git a/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIPromptAgentFactoryTests.cs b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIPromptAgentFactoryTests.cs
index 3bdc654d4e..4cde729a88 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIPromptAgentFactoryTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIPromptAgentFactoryTests.cs
@@ -3,7 +3,6 @@
using System;
using System.Threading.Tasks;
using Microsoft.Agents.ObjectModel;
-using Moq;
using OpenAI.Chat;
namespace Microsoft.Agents.AI.Declarative.AzureAI.UnitTests;
From e92425e54f17558a7ad121edf0f307ef33892cde Mon Sep 17 00:00:00 2001
From: markwallace-microsoft
<127216156+markwallace-microsoft@users.noreply.github.com>
Date: Fri, 30 Jan 2026 18:01:40 +0000
Subject: [PATCH 7/8] More formatting
---
.../OpenAIResponsesPromptAgentFactoryTests.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIResponsesPromptAgentFactoryTests.cs b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIResponsesPromptAgentFactoryTests.cs
index f799eb543e..16c6402f8f 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIResponsesPromptAgentFactoryTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIResponsesPromptAgentFactoryTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Threading.Tasks;
From 1d19b694888e610cf8e0c5ae0d38088f42ba2fd6 Mon Sep 17 00:00:00 2001
From: markwallace-microsoft
<127216156+markwallace-microsoft@users.noreply.github.com>
Date: Thu, 5 Feb 2026 10:29:21 +0000
Subject: [PATCH 8/8] New sample for declarative OpenAI
---
agent-samples/openai/OpenAIAssistants.yaml | 28 ---------
dotnet/agent-framework-dotnet.slnx | 1 +
.../OpenAI/DeclarativeOpenAIAgents.csproj | 25 ++++++++
.../DeclarativeAgents/OpenAI/Program.cs | 61 ++++++++++++++++++
.../OpenAI/Properties/launchSettings.json | 16 +++++
.../DeclarativeAgents/OpenAI/README.md | 63 +++++++++++++++++++
6 files changed, 166 insertions(+), 28 deletions(-)
delete mode 100644 agent-samples/openai/OpenAIAssistants.yaml
create mode 100644 dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/DeclarativeOpenAIAgents.csproj
create mode 100644 dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/Program.cs
create mode 100644 dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/Properties/launchSettings.json
create mode 100644 dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/README.md
diff --git a/agent-samples/openai/OpenAIAssistants.yaml b/agent-samples/openai/OpenAIAssistants.yaml
deleted file mode 100644
index 1318051120..0000000000
--- a/agent-samples/openai/OpenAIAssistants.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-kind: Prompt
-name: Assistant
-description: Helpful assistant
-instructions: You are a helpful assistant. You answer questions in the language specified by the user. You return your answers in a JSON format. You must include Assistants as the type in your response.
-model:
- id: gpt-4.1-mini
- provider: OpenAI
- apiType: Assistants
- options:
- temperature: 0.9
- topP: 0.95
- connection:
- kind: ApiKey
- key: =Env.OPENAI_API_KEY
-outputSchema:
- properties:
- language:
- type: string
- required: true
- description: The language of the answer.
- answer:
- type: string
- required: true
- description: The answer text.
- type:
- type: string
- required: true
- description: The type of the response.
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 2dc7ef14f9..333ba4262d 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -98,6 +98,7 @@
+
diff --git a/dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/DeclarativeOpenAIAgents.csproj b/dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/DeclarativeOpenAIAgents.csproj
new file mode 100644
index 0000000000..7fd4be0da4
--- /dev/null
+++ b/dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/DeclarativeOpenAIAgents.csproj
@@ -0,0 +1,25 @@
+
+
+
+ Exe
+ net10.0
+
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/Program.cs b/dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/Program.cs
new file mode 100644
index 0000000000..2e66f08916
--- /dev/null
+++ b/dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/Program.cs
@@ -0,0 +1,61 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample shows how to load an AI agent from a YAML file and process a prompt using Azure OpenAI as the backend.
+// Unlike the ChatClient sample, this uses the OpenAIPromptAgentFactory which can create a ChatClient from the YAML model definition.
+
+using System.ComponentModel;
+using Azure.Identity;
+using Microsoft.Agents.AI;
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.Configuration;
+
+string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
+
+// Read command-line arguments
+if (args.Length < 2)
+{
+ Console.WriteLine("Usage: DeclarativeOpenAIAgents ");
+ Console.WriteLine(" : The path to the YAML file containing the agent definition");
+ Console.WriteLine(" : The prompt to send to the agent");
+ return;
+}
+
+string yamlFilePath = args[0];
+string prompt = args[1];
+
+// Verify the YAML file exists
+if (!File.Exists(yamlFilePath))
+{
+ Console.WriteLine($"Error: File not found: {yamlFilePath}");
+ return;
+}
+
+// Read the YAML content from the file
+string text = await File.ReadAllTextAsync(yamlFilePath);
+
+// Example function tool that can be used by the agent.
+[Description("Get the weather for a given location.")]
+static string GetWeather(
+ [Description("The city and state, e.g. San Francisco, CA")] string location,
+ [Description("The unit of temperature. Possible values are 'celsius' and 'fahrenheit'.")] string unit)
+ => $"The weather in {location} is cloudy with a high of {(unit.Equals("celsius", StringComparison.Ordinal) ? "15°C" : "59°F")}.";
+
+// Create the configuration with the Azure OpenAI endpoint
+IConfiguration configuration = new ConfigurationBuilder()
+ .AddInMemoryCollection(new Dictionary
+ {
+ ["AzureOpenAI:Endpoint"] = endpoint,
+ })
+ .Build();
+
+// Create the agent from the YAML definition.
+// OpenAIPromptAgentFactory can create a ChatClient based on the model defined in the YAML file.
+OpenAIPromptAgentFactory agentFactory = new(
+ new Uri(endpoint),
+ new AzureCliCredential(),
+ [AIFunctionFactory.Create(GetWeather, "GetWeather")],
+ configuration: configuration);
+AIAgent? agent = await agentFactory.CreateFromYamlAsync(text);
+
+// Invoke the agent and output the text result.
+Console.WriteLine(await agent!.RunAsync(prompt));
diff --git a/dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/Properties/launchSettings.json b/dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/Properties/launchSettings.json
new file mode 100644
index 0000000000..d70b1eb090
--- /dev/null
+++ b/dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/Properties/launchSettings.json
@@ -0,0 +1,16 @@
+{
+ "profiles": {
+ "OpenAI": {
+ "commandName": "Project",
+ "commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\openai\\OpenAI.yaml \"What is the weather in Cambridge, MA in °C?\""
+ },
+ "OpenAIChat": {
+ "commandName": "Project",
+ "commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\openai\\OpenAIChat.yaml \"What is the weather in Cambridge, MA in °C?\""
+ },
+ "OpenAIResponses": {
+ "commandName": "Project",
+ "commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\openai\\OpenAIResponses.yaml \"What is the weather in Cambridge, MA in °C?\""
+ }
+ }
+}
\ No newline at end of file
diff --git a/dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/README.md b/dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/README.md
new file mode 100644
index 0000000000..2b93f40fe6
--- /dev/null
+++ b/dotnet/samples/GettingStarted/DeclarativeAgents/OpenAI/README.md
@@ -0,0 +1,63 @@
+# Declarative OpenAI Agents
+
+This sample demonstrates how to use the `OpenAIPromptAgentFactory` to create AI agents from YAML definitions.
+
+## Overview
+
+Unlike the `ChatClientPromptAgentFactory` which requires you to create an `IChatClient` upfront, the `OpenAIPromptAgentFactory` can create the chat client based on the model definition in the YAML file. This is useful when:
+
+- You want the model to be defined declaratively in the YAML file
+- You need to support multiple models without changing code
+- You want to use Azure OpenAI endpoints with token-based authentication
+
+## Prerequisites
+
+- .NET 10.0 SDK
+- Azure OpenAI endpoint access
+- Azure CLI installed and authenticated (`az login`)
+
+## Configuration
+
+Set the following environment variable:
+
+```bash
+# Required: Azure OpenAI endpoint URL
+set AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/
+```
+
+## Running the Sample
+
+```bash
+dotnet run --
+```
+
+### Example
+
+```bash
+dotnet run -- agent.yaml "What is the weather in Seattle?"
+```
+
+## Sample YAML Agent Definition
+
+Create a file named `agent.yaml` with the following content:
+
+```yaml
+name: WeatherAgent
+description: An agent that can provide weather information
+model:
+ api: chat
+ configuration:
+ azure_deployment: gpt-4o-mini
+instructions: |
+ You are a helpful assistant that provides weather information.
+ Use the GetWeather function when asked about weather conditions.
+```
+
+## Key Differences from ChatClient Sample
+
+| Feature | ChatClient Sample | OpenAI Sample |
+|---------|------------------|---------------|
+| Chat client creation | Manual (in code) | Automatic (from YAML model definition) |
+| Model selection | Code-specified | YAML-specified |
+| Factory class | `ChatClientPromptAgentFactory` | `OpenAIPromptAgentFactory` |
+| Authentication | Passed to `AzureOpenAIClient` | Passed to factory constructor |