File: Program.cs
Web Access
Project: src\playground\FoundryAgents\DotNetHostedAgent\DotNetHostedAgent.csproj (DotNetHostedAgent)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.ComponentModel;
using System.Data.Common;
using Azure.AI.Extensions.OpenAI;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry.Hosting;
using Microsoft.Extensions.AI;
 
string projectConnectionString = Environment.GetEnvironmentVariable("ConnectionStrings__projmyproject")
    ?? throw new InvalidOperationException("ConnectionStrings__projmyproject is not set.");
 
string chatConnectionString = Environment.GetEnvironmentVariable("ConnectionStrings__chat")
    ?? throw new InvalidOperationException("ConnectionStrings__chat is not set.");
 
DbConnectionStringBuilder projectConnectionBuilder = new() { ConnectionString = projectConnectionString };
DbConnectionStringBuilder chatConnectionBuilder = new() { ConnectionString = chatConnectionString };
 
string projectEndpoint = GetRequiredConnectionValue(projectConnectionBuilder, "Endpoint");
string deploymentName = GetRequiredConnectionValue(chatConnectionBuilder, "Deployment");
 
if (!Uri.TryCreate(projectEndpoint, UriKind.Absolute, out Uri? projectUri) || projectUri is null)
{
    throw new InvalidOperationException("ConnectionStrings__projmyproject contains an invalid Endpoint value.");
}
 
Console.WriteLine($"Project Endpoint: {projectUri}");
Console.WriteLine($"Model Deployment: {deploymentName}");
 
[Description("Get a weather forecast")]
WeatherForecast[] GetWeatherForecast()
{
    string[] summaries = ["Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"];
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
 
    return forecast;
}
 
DefaultAzureCredential credential = new(new DefaultAzureCredentialOptions
{
    ExcludeManagedIdentityCredential = string.Equals(
        Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"),
        "Development",
        StringComparison.OrdinalIgnoreCase)
});
 
var foundryProjectClient = new AIProjectClient(projectUri, credential);
var searchAgentReference = new AgentReference(name: Environment.GetEnvironmentVariable("SEARCHAGENT_AGENTNAME"));
var responseClient = foundryProjectClient.ProjectOpenAIClient.GetProjectResponsesClientForAgent(searchAgentReference);
var searchAgent = responseClient.AsIChatClient(deploymentName).AsAIAgent(Environment.GetEnvironmentVariable("SEARCHAGENT_AGENTNAME"), description: "I can search the web.");
 
AIAgent agent = new AIProjectClient(projectUri, credential)
    .AsAIAgent(
        model: deploymentName,
        name: "WeatherAgent",
        instructions: """You are the Weather Intelligence Agent that can return weather forecast using your tools.""",
        tools: [AIFunctionFactory.Create(GetWeatherForecast), searchAgent.AsAIFunction()]);
 
// Bind to the port allocated by Aspire via the DEFAULT_AD_PORT environment variable.
string port = Environment.GetEnvironmentVariable("DEFAULT_AD_PORT") ?? "8088";
 
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseUrls($"http://+:{port}");
builder.Services.AddFoundryResponses(agent);
 
if (builder.Environment.IsDevelopment())
{
    builder.Services.AddDevTemporaryLocalContributorSetup();
}
var app = builder.Build();
 
app.MapFoundryResponses();
app.MapDevTemporaryLocalAgentEndpoint();
app.MapGet("/liveness", () => Results.Ok("Healthy"));
app.MapGet("/readiness", () => Results.Ok("Ready"));
 
Console.WriteLine($"Weather Agent Server running on http://localhost:{port}");
app.Run();
 
string GetRequiredConnectionValue(DbConnectionStringBuilder connectionBuilder, string key)
{
    if (!connectionBuilder.TryGetValue(key, out object? rawValue) || rawValue is null)
    {
        throw new InvalidOperationException($"Connection string is missing '{key}'.");
    }
 
    string? value = rawValue.ToString();
 
    if (string.IsNullOrWhiteSpace(value))
    {
        throw new InvalidOperationException($"Connection string has an empty '{key}' value.");
    }
 
    return value;
}
 
internal sealed record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}