mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
- Delete all launchSettings.json files (port 8088 now comes from ASPNETCORE_URLS in .env) - Add DotNetEnv to Hosted-Invocations-EchoAgent so it loads .env like the responses samples - Create .env.example for EchoAgent with ASPNETCORE_URLS and ASPNETCORE_ENVIRONMENT - Add AGENT_NAME to ChatClientAgent and FoundryAgent .env.example (required by those samples) - Add AZURE_BEARER_TOKEN=DefaultAzureCredential to all .env.example files - Update DevTemporaryTokenCredential in all 6 samples to treat the sentinel value as unavailable, allowing ChainedTokenCredential to fall through to DefaultAzureCredential - Update EchoAgent README with Configuration section
92 lines
3.4 KiB
C#
92 lines
3.4 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using Azure.AI.Projects;
|
|
using Azure.AI.Projects.Agents;
|
|
using Azure.Core;
|
|
using Azure.Identity;
|
|
using DotNetEnv;
|
|
using Microsoft.Agents.AI.Foundry;
|
|
using Microsoft.Agents.AI.Foundry.Hosting;
|
|
|
|
// Load .env file if present (for local development)
|
|
Env.TraversePath().Load();
|
|
|
|
var projectEndpoint = new Uri(Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT")
|
|
?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."));
|
|
var agentName = Environment.GetEnvironmentVariable("AGENT_NAME")
|
|
?? throw new InvalidOperationException("AGENT_NAME is not set.");
|
|
|
|
// Use a chained credential: try a temporary dev token first (for local Docker debugging),
|
|
// then fall back to DefaultAzureCredential (for local dev via dotnet run / managed identity running in foundry).
|
|
TokenCredential credential = new ChainedTokenCredential(
|
|
new DevTemporaryTokenCredential(),
|
|
new DefaultAzureCredential());
|
|
|
|
var aiProjectClient = new AIProjectClient(projectEndpoint, credential);
|
|
|
|
// Retrieve the Foundry-managed agent by name (latest version).
|
|
ProjectsAgentRecord agentRecord = await aiProjectClient
|
|
.AgentAdministrationClient.GetAgentAsync(agentName);
|
|
|
|
FoundryAgent agent = aiProjectClient.AsAIAgent(agentRecord);
|
|
|
|
// Host the agent as a Foundry Hosted Agent using the Responses API.
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
builder.Services.AddFoundryResponses(agent);
|
|
|
|
var app = builder.Build();
|
|
app.MapFoundryResponses();
|
|
|
|
// In Development, also map the OpenAI-compatible route that AIProjectClient uses.
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
app.MapFoundryResponses("openai/v1");
|
|
}
|
|
|
|
app.Run();
|
|
|
|
/// <summary>
|
|
/// A <see cref="TokenCredential"/> for local Docker debugging only.
|
|
///
|
|
/// When debugging and testing a hosted agent in a local Docker container, Azure CLI
|
|
/// and other interactive credentials are not available. This credential reads a
|
|
/// pre-fetched bearer token from the <c>AZURE_BEARER_TOKEN</c> environment variable.
|
|
///
|
|
/// This should NOT be used in production — tokens expire (~1 hour) and cannot be refreshed.
|
|
/// In production, the Foundry platform injects a managed identity automatically.
|
|
///
|
|
/// Generate a token on your host and pass it to the container:
|
|
/// export AZURE_BEARER_TOKEN=$(az account get-access-token --resource https://ai.azure.com --query accessToken -o tsv)
|
|
/// docker run -e AZURE_BEARER_TOKEN=$AZURE_BEARER_TOKEN ...
|
|
/// </summary>
|
|
internal sealed class DevTemporaryTokenCredential : TokenCredential
|
|
{
|
|
private const string EnvironmentVariable = "AZURE_BEARER_TOKEN";
|
|
private readonly string? _token;
|
|
|
|
public DevTemporaryTokenCredential()
|
|
{
|
|
this._token = Environment.GetEnvironmentVariable(EnvironmentVariable);
|
|
}
|
|
|
|
public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
|
|
{
|
|
return this.GetAccessToken();
|
|
}
|
|
|
|
public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
|
|
{
|
|
return new ValueTask<AccessToken>(this.GetAccessToken());
|
|
}
|
|
|
|
private AccessToken GetAccessToken()
|
|
{
|
|
if (string.IsNullOrEmpty(this._token) || this._token == "DefaultAzureCredential")
|
|
{
|
|
throw new CredentialUnavailableException($"{EnvironmentVariable} environment variable is not set.");
|
|
}
|
|
|
|
return new AccessToken(this._token, DateTimeOffset.UtcNow.AddHours(1));
|
|
}
|
|
}
|