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 630afbd6a5..333ba4262d 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -98,6 +98,7 @@
+
@@ -402,6 +403,7 @@
+
@@ -446,6 +448,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 |
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/BaseOpenAIPromptAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/BaseOpenAIPromptAgentFactory.cs
new file mode 100644
index 0000000000..3f84776d67
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/BaseOpenAIPromptAgentFactory.cs
@@ -0,0 +1,184 @@
+// Copyright (c) Microsoft. All rights reserved.
+using System;
+using System.ClientModel;
+using Azure.AI.OpenAI;
+using Azure.Core;
+using Microsoft.Agents.ObjectModel;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Microsoft.PowerFx;
+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 BaseOpenAIPromptAgentFactory : PromptAgentFactory
+{
+ ///
+ /// Creates a new instance of the class.
+ ///
+ protected BaseOpenAIPromptAgentFactory(RecalcEngine? engine = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(engine, configuration)
+ {
+ this.LoggerFactory = loggerFactory;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ protected BaseOpenAIPromptAgentFactory(Uri endpoint, TokenCredential tokenCredential, RecalcEngine? engine = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(engine, 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 ResponsesClient? CreateResponseClient(GptComponentMetadata promptAgent)
+ {
+ var model = promptAgent.Model as CurrentModels;
+ var provider = model?.Provider?.Value ?? ModelProvider.OpenAI;
+ if (provider == ModelProvider.OpenAI)
+ {
+ 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 CreateAzureResponsesClient(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 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).GetResponsesClient(modelId);
+ }
+
+ 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).GetResponsesClient(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/JsonSchemaFunctionParameters.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/JsonSchemaFunctionParameters.cs
new file mode 100644
index 0000000000..c406825d5b
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/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/Microsoft.Agents.AI.Declarative.AzureAI.csproj b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/Microsoft.Agents.AI.Declarative.AzureAI.csproj
new file mode 100644
index 0000000000..3af7c1d385
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/Microsoft.Agents.AI.Declarative.AzureAI.csproj
@@ -0,0 +1,54 @@
+
+
+
+ preview
+ $(NoWarn);MEAI001;OPENAI001
+ false
+
+
+
+ true
+ true
+ true
+
+
+
+
+
+
+ Microsoft Agent Framework Declarative Foundry Agents
+ Provides Microsoft Agent Framework support for declarative Foundry agents.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/OpenAIPromptAgentFactory.cs b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/OpenAIPromptAgentFactory.cs
new file mode 100644
index 0000000000..162e9dcebb
--- /dev/null
+++ b/dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/OpenAIPromptAgentFactory.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.Chat;
+
+namespace Microsoft.Agents.AI;
+
+///
+/// Provides an which creates instances of using a .
+///
+public sealed class OpenAIPromptAgentFactory : BaseOpenAIPromptAgentFactory
+{
+ ///
+ /// Creates a new instance of the class.
+ ///
+ 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.
+ ///
+ public OpenAIPromptAgentFactory(ChatClient chatClient, IList? functions = null, RecalcEngine? engine = null, IConfiguration? configuration = null, ILoggerFactory? loggerFactory = null) : base(engine, configuration, loggerFactory)
+ {
+ Throw.IfNull(chatClient);
+
+ this._chatClient = chatClient;
+ this._functions = functions;
+ }
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ 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;
+ }
+
+ ///
+ 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,
+ ChatOptions = promptAgent.GetChatOptions(this.Engine, 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/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 =>
{
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..e19794f673
--- /dev/null
+++ b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/AzureAIPromptAgentFactoryTests.cs
@@ -0,0 +1,136 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using System.Threading.Tasks;
+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("AIProjectClient", 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()
+ {
+ const 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()
+ {
+ const 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
new file mode 100644
index 0000000000..fe9fb91041
--- /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
+
+
+
+
+
+
+
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..4cde729a88
--- /dev/null
+++ b/dotnet/tests/Microsoft.Agents.AI.Declarative.AzureAI.UnitTests/OpenAIPromptAgentFactoryTests.cs
@@ -0,0 +1,134 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using System.Threading.Tasks;
+using Microsoft.Agents.ObjectModel;
+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..16c6402f8f
--- /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);
+ }
+}