Files
agent-framework/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/Program.cs
Copilot 7e98b0cd29 .NET: Update HostedAgents samples to Azure.AI.AgentServer.AgentFramework 1.0.0-beta.9 and MEAI 10.3.0 (#4477)
* Initial plan

* Update HostedAgents samples to Azure.AI.AgentServer.AgentFramework 1.0.0-beta.9 and MEAI 10.3.0

Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>

* Fix HostedAgents samples for Microsoft.Agents.AI 1.0.0-rc2 API changes

- Rename CreateAIAgent -> AsAIAgent (AgentThreadAndHITL, AgentWithHostedMCP, AgentWithTextSearchRag)
- Rename AsAgent -> AsAIAgent (AgentsInWorkflows)
- Replace AIContextProviderFactory with AIContextProviders and simplified TextSearchProvider ctor (AgentWithTextSearchRag)
- Update Microsoft.Agents.AI.OpenAI to 1.0.0-rc2 (AgentThreadAndHITL, AgentWithTextSearchRag, AgentWithTools)
- Update Microsoft.Agents.AI.Workflows to 1.0.0-rc2 (AgentsInWorkflows)
- Add Microsoft.Agents.AI 1.0.0-rc2 reference (AgentWithHostedMCP)

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

* Update HostedAgents samples for beta.9 API changes and add missing projects to slnx

- Use DefaultAzureCredential consistently across all samples
- Add AgentThreadAndHITL, AgentWithLocalTools, AgentWithTools to slnx
- Apply dotnet format

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

* Remove unnecessary Microsoft.Agents.AI.* package references (transitive from AgentFramework)

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

* Add DefaultAzureCredential production warning comments to all HostedAgents samples

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

* Update HostedAgents READMEs to reflect DefaultAzureCredential usage

Replace AzureCliCredential references with DefaultAzureCredential in all
HostedAgents README files to match the actual sample code.

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

* Replace Microsoft.Extensions.AI.OpenAI with Microsoft.Agents.AI.OpenAI and remove AsIChatClient()

Swap package references from Microsoft.Extensions.AI.OpenAI to
Microsoft.Agents.AI.OpenAI across all 6 HostedAgents samples. This enables
using the AsAIAgent() extension directly on ChatClient/ResponsesClient
(from OpenAI.Chat/OpenAI.Responses namespaces), removing the intermediate
AsIChatClient() call in 3 samples where it was unnecessary.

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

* Use explicit types and AsAIAgent() extensions across all HostedAgents samples

Replace var with explicit types for clarity in all 6 samples. Replace
new ChatClientAgent() constructor calls with chatClient.AsAIAgent()
extension method in AgentWithLocalTools and AgentsInWorkflows.

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

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-06 12:15:10 +00:00

133 lines
5.6 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
// Seattle Hotel Agent - A simple agent with a tool to find hotels in Seattle.
// Uses Microsoft Agent Framework with Azure AI Foundry.
// Ready for deployment to Foundry Hosted Agent service.
using System.ClientModel.Primitives;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using Azure.AI.AgentServer.AgentFramework.Extensions;
using Azure.AI.OpenAI;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT")
?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
Console.WriteLine($"Project Endpoint: {endpoint}");
Console.WriteLine($"Model Deployment: {deploymentName}");
Hotel[] seattleHotels =
[
new Hotel("Contoso Suites", 189, 4.5, "Downtown"),
new Hotel("Fabrikam Residences", 159, 4.2, "Pike Place Market"),
new Hotel("Alpine Ski House", 249, 4.7, "Seattle Center"),
new Hotel("Margie's Travel Lodge", 219, 4.4, "Waterfront"),
new Hotel("Northwind Inn", 139, 4.0, "Capitol Hill"),
new Hotel("Relecloud Hotel", 99, 3.8, "University District"),
];
[Description("Get available hotels in Seattle for the specified dates. This simulates a call to a hotel availability API.")]
string GetAvailableHotels(
[Description("Check-in date in YYYY-MM-DD format")] string checkInDate,
[Description("Check-out date in YYYY-MM-DD format")] string checkOutDate,
[Description("Maximum price per night in USD (optional, defaults to 500)")] int maxPrice = 500)
{
try
{
if (!DateTime.TryParseExact(checkInDate, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var checkIn))
{
return "Error parsing check-in date. Please use YYYY-MM-DD format.";
}
if (!DateTime.TryParseExact(checkOutDate, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var checkOut))
{
return "Error parsing check-out date. Please use YYYY-MM-DD format.";
}
if (checkOut <= checkIn)
{
return "Error: Check-out date must be after check-in date.";
}
int nights = (checkOut - checkIn).Days;
List<Hotel> availableHotels = seattleHotels.Where(h => h.PricePerNight <= maxPrice).ToList();
if (availableHotels.Count == 0)
{
return $"No hotels found in Seattle within your budget of ${maxPrice}/night.";
}
StringBuilder result = new();
result.AppendLine($"Available hotels in Seattle from {checkInDate} to {checkOutDate} ({nights} nights):");
result.AppendLine();
foreach (Hotel hotel in availableHotels)
{
int totalCost = hotel.PricePerNight * nights;
result.AppendLine($"**{hotel.Name}**");
result.AppendLine($" Location: {hotel.Location}");
result.AppendLine($" Rating: {hotel.Rating}/5");
result.AppendLine($" ${hotel.PricePerNight}/night (Total: ${totalCost})");
result.AppendLine();
}
return result.ToString();
}
catch (Exception ex)
{
return $"Error processing request. Details: {ex.Message}";
}
}
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
DefaultAzureCredential credential = new();
AIProjectClient projectClient = new(new Uri(endpoint), credential);
ClientConnection connection = projectClient.GetConnection(typeof(AzureOpenAIClient).FullName!);
if (!connection.TryGetLocatorAsUri(out Uri? openAiEndpoint) || openAiEndpoint is null)
{
throw new InvalidOperationException("Failed to get OpenAI endpoint from project connection.");
}
openAiEndpoint = new Uri($"https://{openAiEndpoint.Host}");
Console.WriteLine($"OpenAI Endpoint: {openAiEndpoint}");
IChatClient chatClient = new AzureOpenAIClient(openAiEndpoint, credential)
.GetChatClient(deploymentName)
.AsIChatClient()
.AsBuilder()
.UseOpenTelemetry(sourceName: "Agents", configure: cfg => cfg.EnableSensitiveData = false)
.Build();
AIAgent agent = chatClient.AsAIAgent(
name: "SeattleHotelAgent",
instructions: """
You are a helpful travel assistant specializing in finding hotels in Seattle, Washington.
When a user asks about hotels in Seattle:
1. Ask for their check-in and check-out dates if not provided
2. Ask about their budget preferences if not mentioned
3. Use the GetAvailableHotels tool to find available options
4. Present the results in a friendly, informative way
5. Offer to help with additional questions about the hotels or Seattle
Be conversational and helpful. If users ask about things outside of Seattle hotels,
politely let them know you specialize in Seattle hotel recommendations.
""",
tools: [AIFunctionFactory.Create(GetAvailableHotels)])
.AsBuilder()
.UseOpenTelemetry(sourceName: "Agents", configure: cfg => cfg.EnableSensitiveData = false)
.Build();
Console.WriteLine("Seattle Hotel Agent Server running on http://localhost:8088");
await agent.RunAIAgentAsync(telemetrySourceName: "Agents");
internal sealed record Hotel(string Name, int PricePerNight, double Rating, string Location);