.NET: Integrate RecalcEngine to compute Env variables (#2093)

* Integrate RecalcEngine to compute Env variables

* Update dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/OpenAIAgentFactory.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update dotnet/src/Microsoft.Agents.AI.Declarative.AzureAI/OpenAIResponseAgentFactory.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update dotnet/src/Microsoft.Agents.AI.Declarative/Extensions/StringExpressionExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update dotnet/samples/GettingStarted/DeclarativeAgents/Foundry/Program.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update dotnet/src/Microsoft.Agents.AI.Declarative/AgentFactory.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix some copilot logged issues

* Address code review feedback

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Mark Wallace
2025-11-12 10:11:59 +00:00
committed by GitHub
co-authored by Copilot
parent 7a261dd598
commit 44585156ef
24 changed files with 202 additions and 56 deletions
@@ -8,7 +8,6 @@ using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// Read command-line arguments
if (args.Length < 2)
@@ -32,9 +31,6 @@ if (!File.Exists(yamlFilePath))
// Read the YAML content from the file
var text = await File.ReadAllTextAsync(yamlFilePath);
// TODO: Remove this workaround when the agent framework supports environment variable substitution in YAML files.
text = text.Replace("=Env.AZURE_OPENAI_DEPLOYMENT_NAME", deploymentName, StringComparison.OrdinalIgnoreCase);
var endpointUri = new Uri(endpoint);
var tokenCredential = new AzureCliCredential();
@@ -0,0 +1,16 @@
{
"profiles": {
"Chat": {
"commandName": "Project",
"commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\azure\\AzureOpenAIChat.yaml \"What is the weather in Cambridge, MA in °C?\""
},
"Responses": {
"commandName": "Project",
"commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\azure\\AzureOpenAIResponses.yaml \"What is the weather in Cambridge, MA in °C?\""
},
"Assistants": {
"commandName": "Project",
"commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\azure\\AzureOpenAIAssistants.yaml \"What is the weather in Cambridge, MA in °C?\""
}
}
}
@@ -0,0 +1,12 @@
{
"profiles": {
"GetWeather": {
"commandName": "Project",
"commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\chatclient\\GetWeather.yaml \"What is the weather in Cambridge, MA in °C?\""
},
"Assistant": {
"commandName": "Project",
"commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\chatclient\\Assistant.yaml \"Tell me a joke about a pirate in Italian.\""
}
}
}
@@ -6,9 +6,9 @@ using System.ComponentModel;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
var model = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_MODEL_ID") ?? "gpt-4.1-mini";
// Read command-line arguments
if (args.Length < 2)
@@ -32,9 +32,13 @@ if (!File.Exists(yamlFilePath))
// Read the YAML content from the file
var text = await File.ReadAllTextAsync(yamlFilePath);
// TODO: Remove this workaround when the agent framework supports environment variable substitution in YAML files.
text = text.Replace("=Env.AZURE_FOUNDRY_PROJECT_ENDPOINT", endpoint, StringComparison.OrdinalIgnoreCase);
text = text.Replace("=Env.AZURE_FOUNDRY_PROJECT_MODEL_ID", model, StringComparison.OrdinalIgnoreCase);
// Set up configuration with the Azure Foundry project endpoint
IConfiguration configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["AZURE_FOUNDRY_PROJECT_ENDPOINT"] = endpoint
})
.Build();
// Example function tool that can be used by the agent.
[Description("Get the weather for a given location.")]
@@ -44,7 +48,7 @@ static string GetWeather(
=> $"The weather in {location} is cloudy with a high of {(unit.Equals("celsius", StringComparison.Ordinal) ? "15°C" : "59°F")}.";
// Create the agent from the YAML definition.
var agentFactory = new FoundryPersistentAgentFactory(new AzureCliCredential());
var agentFactory = new FoundryPersistentAgentFactory(new AzureCliCredential(), configuration);
var agent = await agentFactory.CreateFromYamlAsync(text);
// Create agent run options
@@ -0,0 +1,12 @@
{
"profiles": {
"PersistentAgent": {
"commandName": "Project",
"commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\foundry\\PersistentAgent.yaml \"What is the weather in Cambridge, MA in °C?\""
},
"MicrosoftLearnAgent": {
"commandName": "Project",
"commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\foundry\\MicrosoftLearnAgent.yaml \"Tell me a joke about a pirate in Italian.\""
}
}
}
@@ -5,9 +5,9 @@
using System.ComponentModel;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
var apiKey = Environment.GetEnvironmentVariable("OPENAI_APIKEY") ?? throw new InvalidOperationException("OPENAI_APIKEY is not set.");
var model = Environment.GetEnvironmentVariable("OPENAI_MODEL") ?? "gpt-4o-mini";
// Read command-line arguments
if (args.Length < 2)
@@ -31,16 +31,20 @@ if (!File.Exists(yamlFilePath))
// Read the YAML content from the file
var text = await File.ReadAllTextAsync(yamlFilePath);
// TODO: Remove this workaround when the agent framework supports environment variable substitution in YAML files.
text = text.Replace("=Env.OPENAI_APIKEY", apiKey, StringComparison.OrdinalIgnoreCase);
text = text.Replace("=Env.OPENAI_MODEL", model, StringComparison.OrdinalIgnoreCase);
// Set up configuration with the OpenAI API key
IConfiguration configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["OPENAI_APIKEY"] = apiKey
})
.Build();
// Create the agent from the YAML definition.
var agentFactory = new AggregatorAgentFactory(
[
new OpenAIChatAgentFactory(),
new OpenAIResponseAgentFactory(),
new OpenAIAssistantAgentFactory()
new OpenAIChatAgentFactory(configuration: configuration),
new OpenAIResponseAgentFactory(configuration: configuration),
new OpenAIAssistantAgentFactory(configuration: configuration)
]);
var agent = await agentFactory.CreateFromYamlAsync(text);
@@ -0,0 +1,16 @@
{
"profiles": {
"Chat": {
"commandName": "Project",
"commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\openai\\OpenAIChat.yaml \"What is the weather in Cambridge, MA in °C?\""
},
"Responses": {
"commandName": "Project",
"commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\openai\\OpenAIResponses.yaml \"What is the weather in Cambridge, MA in °C?\""
},
"Assistants": {
"commandName": "Project",
"commandLineArgs": "..\\..\\..\\..\\..\\..\\..\\..\\agent-samples\\openai\\OpenAIAssistants.yaml \"What is the weather in Cambridge, MA in °C?\""
}
}
}