.NET: Organize the .Net samples (#578)

* Organize the .Net samples

* Organize the .Net samples

* Merge latest from main

* Update sample to also include function calling telemetry (#577)

* Move package installation instructions to user-guide (#572)

* Move package installation instructions to user-guide

* Update user-documentation-dotnet/getting-started/README.md

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

* Update docs/docs-templates/getting-started/README.md

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

---------

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

* .NET: Add SK-AF Migration Samples for Responses API. (#575)

* Responses wip

* Adding OpenAI Responses Migration samples

* Address all samples and code for Azure and OpenAI Responses Migration code

* Update dotnet/samples/SemanticKernelMigration/OpenAIResponses/Step02_ReasoningModel/Program.cs

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

---------

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

* Organize the .Net samples

* Organize the .Net samples

* Merge latest from main

* Use Agent rather than AIAgent

* Rename agents getting started samples

* Use singular Agent

---------

Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Mark Wallace
2025-09-02 10:52:07 +00:00
committed by GitHub
co-authored by Copilot Roger Barreto
parent 9b61c72e18
commit 7dee184ae4
78 changed files with 239 additions and 698 deletions
@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
<PackageReference Include="Microsoft.Extensions.Logging" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
<PackageReference Include="OpenAI" />
<PackageReference Include="OpenTelemetry" />
<PackageReference Include="OpenTelemetry.Exporter.Console" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,216 @@
// Copyright (c) Microsoft. All rights reserved.
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.Metrics;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using OpenTelemetry;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
#region Setup Telemetry
const string SourceName = "OpenTelemetryAspire.ConsoleApp";
const string ServiceName = "AgentOpenTelemetry";
// Enable telemetry for agents
AppContext.SetSwitch("Microsoft.Extensions.AI.Agents.EnableTelemetry", true);
// Configure OpenTelemetry for Aspire dashboard
var otlpEndpoint = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318";
// Create a resource to identify this service
var resource = ResourceBuilder.CreateDefault()
.AddService(ServiceName, serviceVersion: "1.0.0")
.AddAttributes(new Dictionary<string, object>
{
["service.instance.id"] = Environment.MachineName,
["deployment.environment"] = "development"
})
.Build();
// Setup tracing with resource
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(ServiceName, serviceVersion: "1.0.0"))
.AddSource(SourceName) // Our custom activity source
.AddSource("Microsoft.Extensions.AI.Agents") // Agent Framework telemetry
.AddHttpClientInstrumentation() // Capture HTTP calls to OpenAI
.AddOtlpExporter(options => { options.Endpoint = new Uri(otlpEndpoint); })
.Build();
// Setup metrics with resource and instrument name filtering
using var meterProvider = Sdk.CreateMeterProviderBuilder()
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(ServiceName, serviceVersion: "1.0.0"))
.AddMeter(SourceName) // Our custom meter
.AddMeter("Microsoft.Extensions.AI.Agents") // Agent Framework metrics
.AddHttpClientInstrumentation() // HTTP client metrics
.AddRuntimeInstrumentation() // .NET runtime metrics
.AddOtlpExporter(options => { options.Endpoint = new Uri(otlpEndpoint); })
.Build();
// Setup structured logging with OpenTelemetry
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging(loggingBuilder => loggingBuilder
.SetMinimumLevel(LogLevel.Debug)
.AddOpenTelemetry(options =>
{
options.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(ServiceName, serviceVersion: "1.0.0"));
options.AddOtlpExporter(otlpOptions =>
{
otlpOptions.Endpoint = new Uri(otlpEndpoint);
});
options.IncludeScopes = true;
options.IncludeFormattedMessage = true;
}));
using var activitySource = new ActivitySource(SourceName);
using var meter = new Meter(SourceName);
// Create custom metrics
var interactionCounter = meter.CreateCounter<int>("agent_interactions_total", description: "Total number of agent interactions");
var responseTimeHistogram = meter.CreateHistogram<double>("agent_response_time_seconds", description: "Agent response time in seconds");
#endregion
var serviceProvider = serviceCollection.BuildServiceProvider();
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
var appLogger = loggerFactory.CreateLogger<Program>();
Console.WriteLine("""
=== OpenTelemetry Aspire Demo ===
This demo shows OpenTelemetry integration with the Agent Framework.
You can view the telemetry data in the Aspire Dashboard.
Type your message and press Enter. Type 'exit' or empty message to quit.
""");
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT environment variable is not set.");
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
// Log application startup
appLogger.LogInformation("OpenTelemetry Aspire Demo application started");
[Description("Get the weather for a given location.")]
static async Task<string> GetWeather([Description("The location to get the weather for.")] string location)
{
await Task.Delay(2000);
return $"The weather in {location} is cloudy with a high of 15°C.";
}
// To ensure chat client's function calling is captured in the open telemetry, the chat client needs to have UseOpenTelemetry after UseFunctionInvocation
using var instrumentedChatClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetChatClient(deploymentName)
.AsIChatClient() // Converts a native OpenAI SDK ChatClient into a Microsoft.Extensions.AI.IChatClient
.AsBuilder()
.UseFunctionInvocation()
.UseOpenTelemetry(loggerFactory: loggerFactory, sourceName: SourceName, (cfg) => { cfg.EnableSensitiveData = true; })
.Build();
appLogger.LogInformation("Creating Agent with OpenTelemetry instrumentation");
// Create the agent with the instrumented chat client
using var agent = new ChatClientAgent(instrumentedChatClient,
name: "OpenTelemetryDemoAgent",
instructions: "You are a helpful assistant that provides concise and informative responses.",
tools: [AIFunctionFactory.Create(GetWeather)])
.WithOpenTelemetry(loggerFactory, SourceName); // Enable telemetry on the agent
var thread = agent.GetNewThread();
appLogger.LogInformation("Agent created successfully with ID: {AgentId}", agent.Id);
// Create a parent span for the entire agent session
using var sessionActivity = activitySource.StartActivity("Agent Session");
var sessionId = thread.ConversationId ?? Guid.NewGuid().ToString();
sessionActivity?.SetTag("agent.name", "OpenTelemetryDemoAgent");
sessionActivity?.SetTag("session.id", sessionId);
sessionActivity?.SetTag("session.start_time", DateTimeOffset.UtcNow.ToString("O"));
appLogger.LogInformation("Starting agent session with ID: {SessionId}", sessionId);
using (appLogger.BeginScope(new Dictionary<string, object> { ["SessionId"] = sessionId, ["AgentName"] = "OpenTelemetryDemoAgent" }))
{
var interactionCount = 0;
while (true)
{
Console.Write("You: ");
var userInput = Console.ReadLine();
if (string.IsNullOrWhiteSpace(userInput) || userInput.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
appLogger.LogInformation("User requested to exit the session");
break;
}
interactionCount++;
appLogger.LogInformation("Processing user interaction #{InteractionNumber}: {UserInput}", interactionCount, userInput);
// Create a child span for each individual interaction
using var activity = activitySource.StartActivity("Agent Interaction");
activity?.SetTag("user.input", userInput);
activity?.SetTag("agent.name", "OpenTelemetryDemoAgent");
activity?.SetTag("interaction.number", interactionCount);
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
try
{
appLogger.LogDebug("Starting agent execution for interaction #{InteractionNumber}", interactionCount);
Console.Write("Agent: ");
// Run the agent (this will create its own internal telemetry spans)
await foreach (var update in agent.RunStreamingAsync(userInput, thread))
{
Console.Write(update.Text);
}
Console.WriteLine();
stopwatch.Stop();
var responseTime = stopwatch.Elapsed.TotalSeconds;
// Record metrics (similar to Python example)
interactionCounter.Add(1, new KeyValuePair<string, object?>("status", "success"));
responseTimeHistogram.Record(responseTime,
new KeyValuePair<string, object?>("status", "success"));
activity?.SetTag("response.success", true);
appLogger.LogInformation("Agent interaction #{InteractionNumber} completed successfully in {ResponseTime:F2} seconds",
interactionCount, responseTime);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine();
stopwatch.Stop();
var responseTime = stopwatch.Elapsed.TotalSeconds;
// Record error metrics
interactionCounter.Add(1, new KeyValuePair<string, object?>("status", "error"));
responseTimeHistogram.Record(responseTime,
new KeyValuePair<string, object?>("status", "error"));
activity?.SetTag("response.success", false);
activity?.SetTag("error.message", ex.Message);
activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
appLogger.LogError(ex, "Agent interaction #{InteractionNumber} failed after {ResponseTime:F2} seconds: {ErrorMessage}",
interactionCount, responseTime, ex.Message);
}
}
// Add session summary to the parent span
sessionActivity?.SetTag("session.total_interactions", interactionCount);
sessionActivity?.SetTag("session.end_time", DateTimeOffset.UtcNow.ToString("O"));
appLogger.LogInformation("Agent session completed. Total interactions: {TotalInteractions}", interactionCount);
} // End of logging scope
appLogger.LogInformation("OpenTelemetry Aspire Demo application shutting down");
@@ -0,0 +1,210 @@
# OpenTelemetry Aspire Demo with Azure OpenAI
This demo showcases the integration of OpenTelemetry with the Microsoft Agent Framework using Azure OpenAI and .NET Aspire Dashboard for telemetry visualization.
## Overview
The demo consists of two main components:
1. **Aspire Dashboard** - Provides a web-based interface to visualize OpenTelemetry data
2. **Console Application** - An interactive console application that demonstrates agent interactions with proper OpenTelemetry instrumentation
## Architecture
```mermaid
graph TD
A["Console App<br/>(Interactive)"] --> B["Agent Framework<br/>with OpenTel<br/>Instrumentation"]
B --> C["Azure OpenAI<br/>Service"]
A --> D["Aspire Dashboard<br/>(OpenTelemetry Visualization)"]
B --> D
```
## Prerequisites
- .NET 8.0 SDK or later
- Azure OpenAI service endpoint and deployment configured
- Azure CLI installed and authenticated (for Azure credential authentication)
- Docker installed (for running Aspire Dashboard)
## Configuration
### Azure OpenAI Setup
Set the following environment variables:
```powershell
$env:AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/"
$env:AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini" # Optional, defaults to gpt-4o-mini
```
**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Azure OpenAI resource.
## Running the Demo
### Quick Start (Using Script)
The easiest way to run the demo is using the provided PowerShell script:
```powershell
.\start-demo.ps1
```
This script will automatically:
- ✅ Check prerequisites (Docker, Azure OpenAI configuration)
- 🔨 Build the console application
- 🐳 Start the Aspire Dashboard via Docker (with anonymous access)
- ⏳ Wait for dashboard to be ready (polls port until listening)
- 🌐 Open your browser with the dashboard
- 📊 Configure telemetry endpoints (http://localhost:4317)
- 🎯 Start the interactive console application
### Manual Setup (Step by Step)
If you prefer to run the components manually:
#### Step 1: Start the Aspire Dashboard via Docker
```powershell
docker run -d --name aspire-dashboard -p 4318:18888 -p 4317:18889 -e DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS=true mcr.microsoft.com/dotnet/aspire-dashboard:9.0
```
#### Step 2: Access the Dashboard
Open your browser to: http://localhost:4318
#### Step 3: Run the Console Application
```powershell
cd dotnet/demos/AgentOpenTelemetry
$env:OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
dotnet run
```
#### Interacting with the Console Application
You should see a welcome message like:
```
=== OpenTelemetry Aspire Demo ===
This demo shows OpenTelemetry integration with the Agent Framework.
You can view the telemetry data in the Aspire Dashboard.
Type your message and press Enter. Type 'exit' or empty message to quit.
You:
```
1. Type your message and press Enter to interact with the AI agent
2. The agent will respond, and you can continue the conversation
3. Type `exit` to stop the application
**Note**: Make sure the Aspire Dashboard is running before starting the console application, as the telemetry data will be sent to the dashboard.
#### Step 4: Test the Integration
1. **Start the Aspire Dashboard** (if not already running)
2. **Run the Console Application** in a separate terminal
3. **Send a test message** like "Hello, how are you?"
4. **Check the Aspire Dashboard** - you should see:
- New traces appearing in the **Traces** tab
- Each trace showing the complete agent interaction flow
- Metrics in the **Metrics** tab showing token usage and duration
- Logs in the **Structured Logs** tab with detailed information
## Viewing Telemetry Data
### Traces
1. In the Aspire Dashboard, navigate to the **Traces** tab
2. You'll see traces for each agent interaction
3. Each trace contains:
- An outer span for the entire agent interaction
- Inner spans from the Agent Framework's OpenTelemetry instrumentation
- Spans from HTTP calls to Azure OpenAI
### Metrics
1. Navigate to the **Metrics** tab
2. View metrics related to:
- Agent execution duration
- Token usage (input/output tokens)
- Request counts
### Logs
1. Navigate to the **Structured Logs** tab
2. Filter by the console application to see detailed logs
3. Logs include information about user inputs, agent responses, and any errors
## Key Features Demonstrated
### OpenTelemetry Integration
- **Automatic instrumentation** of Agent Framework operations
- **Custom spans** for user interactions
- **Proper span lifecycle management** (create → execute → close)
- **Telemetry correlation** across the entire request flow
### Agent Framework Features
- **ChatClientAgent** with Azure OpenAI integration
- **OpenTelemetry wrapper** using `.WithOpenTelemetry()`
- **Conversation threading** for multi-turn conversations
- **Error handling** with telemetry correlation
### Aspire Dashboard Features
- **Real-time telemetry visualization**
- **Distributed tracing** across services
- **Metrics and logging** integration
- **Resource management** and monitoring
## Available Script
The demo includes a PowerShell script to make running the demo easy:
### `start-demo.ps1`
Complete demo startup script that handles everything automatically.
**Usage:**
```powershell
.\start-demo.ps1 # Start the complete demo
```
**Features:**
- **Automatic configuration detection** - Checks for Azure OpenAI configuration
- **Project building** - Automatically builds projects before running
- **Error handling** - Provides clear error messages if something goes wrong
- **Multi-window support** - Opens dashboard in separate window for better experience
- **Browser auto-launch** - Automatically opens the Aspire Dashboard in your browser
- **Docker integration** - Uses Docker to run the Aspire Dashboard
**Docker Endpoints:**
- **Aspire Dashboard**: `http://localhost:4318`
- **OTLP Telemetry**: `http://localhost:4317`
## Troubleshooting
### Port Conflicts
If you encounter port binding errors, try:
1. Stop any existing Docker containers using the same ports (`docker stop aspire-dashboard`)
2. Or kill any processes using the conflicting ports
### Authentication Issues
- Ensure your Azure OpenAI endpoint is correctly configured
- Check that the environment variables are set in the correct terminal session
- Verify you're logged in with Azure CLI (`az login`) and have access to the Azure OpenAI resource
- Ensure the Azure OpenAI deployment name matches your actual deployment
### Build Issues
- Ensure you're using .NET 9.0 SDK
- Run `dotnet restore` if you encounter package restore issues
- Check that all project references are correctly resolved
## Project Structure
```
AgentOpenTelemetry/
├── AgentOpenTelemetry.csproj # Project file with dependencies
├── Program.cs # Main application with Azure OpenAI agent integration
├── start-demo.ps1 # PowerShell script to start the demo
└── README.md # This file
```
## Next Steps
- Experiment with different prompts to see various telemetry patterns
- Explore the Aspire Dashboard's filtering and search capabilities
- Try modifying the OpenTelemetry configuration to add custom metrics or spans
- Integrate additional services to see distributed tracing in action
@@ -0,0 +1,139 @@
# OpenTelemetry Console Demo with Aspire Dashboard (Docker)
# This script starts the Aspire Dashboard via Docker and the Console Application
Write-Host "Starting OpenTelemetry Console Demo..." -ForegroundColor Green
Write-Host ""
# Check if we're in the right directory
if (!(Test-Path "AgentOpenTelemetry.csproj")) {
Write-Host "Error: Please run this script from the AgentOpenTelemetry directory" -ForegroundColor Red
Write-Host "Expected to find AgentOpenTelemetry.csproj file" -ForegroundColor Red
exit 1
}
# Check if Docker is running
try {
docker version | Out-Null
Write-Host "Docker is running" -ForegroundColor Green
} catch {
Write-Host "Docker is not running or not installed" -ForegroundColor Red
Write-Host "Please start Docker Desktop and try again" -ForegroundColor Red
exit 1
}
# Check for Azure OpenAI configuration
if ($env:AZURE_OPENAI_ENDPOINT) {
Write-Host "Found Azure OpenAI endpoint: $($env:AZURE_OPENAI_ENDPOINT)" -ForegroundColor Green
if ($env:AZURE_OPENAI_DEPLOYMENT_NAME) {
Write-Host "Using deployment: $($env:AZURE_OPENAI_DEPLOYMENT_NAME)" -ForegroundColor Green
} else {
Write-Host "Using default deployment: gpt-4o-mini" -ForegroundColor Cyan
}
} else {
Write-Host "Warning: AZURE_OPENAI_ENDPOINT not found!" -ForegroundColor Yellow
Write-Host "Please set the AZURE_OPENAI_ENDPOINT environment variable" -ForegroundColor Yellow
Write-Host "Example: `$env:AZURE_OPENAI_ENDPOINT='https://your-resource.openai.azure.com/'" -ForegroundColor Yellow
Write-Host ""
}
# Build console application
Write-Host ""
Write-Host "Building console application..." -ForegroundColor Cyan
$buildResult = dotnet build --verbosity quiet
if ($LASTEXITCODE -ne 0) {
Write-Host "Failed to build Console App" -ForegroundColor Red
exit 1
}
Write-Host "Build completed successfully" -ForegroundColor Green
Write-Host ""
Write-Host "Starting Aspire Dashboard via Docker..." -ForegroundColor Cyan
# Stop any existing Aspire Dashboard container
Write-Host "Stopping any existing Aspire Dashboard container..." -ForegroundColor Gray
docker stop aspire-dashboard-afdemo 2>$null | Out-Null
docker rm aspire-dashboard-afdemo 2>$null | Out-Null
# Start Aspire Dashboard in Docker daemon mode with fixed token
Write-Host "Starting Aspire Dashboard container..." -ForegroundColor Green
$fixedToken = "demo-token-12345"
$dockerResult = docker run -d `
--name aspire-dashboard-afdemo `
-p 4318:18888 `
-p 4317:18889 `
-e DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS=true `
--restart unless-stopped `
mcr.microsoft.com/dotnet/aspire-dashboard:9.0
if ($LASTEXITCODE -ne 0) {
Write-Host "Failed to start Aspire Dashboard container" -ForegroundColor Red
Write-Host "Make sure Docker is running and try again" -ForegroundColor Red
exit 1
}
Write-Host "Aspire Dashboard started successfully!" -ForegroundColor Green
Write-Host "OTLP Endpoint: http://localhost:4318" -ForegroundColor Cyan
# Wait for dashboard to be ready by polling the port
Write-Host "Waiting for dashboard to be ready..." -ForegroundColor Gray
$maxWaitSeconds = 10
$waitCount = 0
$dashboardReady = $false
while ($waitCount -lt $maxWaitSeconds -and !$dashboardReady) {
try {
$tcpConnection = Test-NetConnection -ComputerName "localhost" -Port 4317 -InformationLevel Quiet -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
if ($tcpConnection) {
$dashboardReady = $true
Write-Host "Dashboard is ready! (took $waitCount seconds)" -ForegroundColor Green
} else {
Write-Host "." -NoNewline -ForegroundColor Gray
Start-Sleep -Seconds 1
$waitCount++
}
} catch {
Write-Host "." -NoNewline -ForegroundColor Gray
Start-Sleep -Seconds 1
$waitCount++
}
}
if (!$dashboardReady) {
Write-Host ""
Write-Host "Dashboard port 4317 not responding after $maxWaitSeconds seconds" -ForegroundColor Yellow
Write-Host " Continuing anyway - dashboard might still be starting..." -ForegroundColor Yellow
} else {
Write-Host ""
}
# Open the dashboard in browser (anonymous access enabled)
Write-Host "Opening dashboard in browser..." -ForegroundColor Green
Write-Host "Dashboard URL: http://localhost:4318" -ForegroundColor Cyan
Start-Process "http://localhost:4318"
Write-Host ""
Write-Host "Starting Console Application..." -ForegroundColor Cyan
Write-Host "You can now interact with the AI agent!" -ForegroundColor Green
Write-Host ""
# Set the OTLP endpoint for the console application (Docker Aspire Dashboard)
$otlpEndpoint = "http://localhost:4317"
Write-Host "Using OTLP endpoint: $otlpEndpoint" -ForegroundColor Cyan
$env:OTEL_EXPORTER_OTLP_ENDPOINT = $otlpEndpoint
# Start the console application in the current window
Write-Host ""
Write-Host "Starting the console application..." -ForegroundColor Green
Write-Host "Tip: The dashboard should now be open in your browser!" -ForegroundColor Cyan
Write-Host ""
dotnet run --no-build
Write-Host ""
Write-Host "Demo completed!" -ForegroundColor Green
Write-Host "The Aspire Dashboard is still running in Docker." -ForegroundColor Gray
Write-Host "You can view telemetry data in the browser tab that opened." -ForegroundColor Gray
Write-Host "To stop the dashboard: docker stop aspire-dashboard-afdemo" -ForegroundColor Gray
@@ -40,10 +40,10 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.Agents.Orchestration\Microsoft.Agents.Orchestration.csproj" />
<ProjectReference Include="..\..\src\Microsoft.Extensions.AI.Agents.AzureAI\Microsoft.Extensions.AI.Agents.AzureAI.csproj" />
<ProjectReference Include="..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Agents.Orchestration\Microsoft.Agents.Orchestration.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.AzureAI\Microsoft.Extensions.AI.Agents.AzureAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
<ItemGroup>
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -16,7 +16,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.A2A\Microsoft.Extensions.AI.Agents.A2A.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.A2A\Microsoft.Extensions.AI.Agents.A2A.csproj" />
</ItemGroup>
</Project>
</Project>
@@ -15,8 +15,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.AzureAI\Microsoft.Extensions.AI.Agents.AzureAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.AzureAI\Microsoft.Extensions.AI.Agents.AzureAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -16,8 +16,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -16,8 +16,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -14,7 +14,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -10,8 +10,8 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -10,8 +10,8 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -16,8 +16,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -16,8 +16,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -17,8 +17,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -18,8 +18,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -18,8 +18,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -17,8 +17,8 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,75 @@
# Getting started with agents
The getting started with agents samples demonstrate the fundamental concepts and functionalities
of single agents and can be used with any agent type.
While the functionality can be used with any agent type, these samples use Azure OpenAI as the AI provider
and use ChatCompletion as the type of service.
For other samples that demonstrate how to create and configure each type of agent that come with the agent framework,
see the [How to create an agent for each provider](../AgentProviders/README.md) samples.
## Getting started with agents prerequisites
Before you begin, ensure you have the following prerequisites:
- .NET 8.0 SDK or later
- Azure OpenAI service endpoint and deployment configured
- Azure CLI installed and authenticated (for Azure credential authentication)
**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Azure OpenAI resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively).
## Samples
|Sample|Description|
|---|---|
|[Running a simple agent](./Agents_Step01_Running/)|This sample demonstrates how to create and run a basic agent with instructions|
|[Multi-turn conversation with a simple agent](./Agents_Step02_MultiturnConversation/)|This sample demonstrates how to implement a multi-turn conversation with a simple agent|
|[Using function tools with a simple agent](./Agents_Step03_UsingFunctionTools/)|This sample demonstrates how to use function tools with a simple agent|
|[Using function tools with approvals](./Agents_Step04_UsingFunctionToolsWithApprovals/)|This sample demonstrates how to use function tools where approvals require human in the loop approvals before execution|
|[Structured output with a simple agent](./Agents_Step05_StructuredOutput/)|This sample demonstrates how to use structured output with a simple agent|
|[Persisted conversations with a simple agent](./Agents_Step06_PersistedConversations/)|This sample demonstrates how to persist conversations and reload them later. This is useful for cases where an agent is hosted in a stateless service|
|[3rd party thread storage with a simple agent](./Agents_Step07_3rdPartyThreadStorage/)|This sample demonstrates how to store conversation history in a 3rd party storage solution|
|[Telemetry with a simple agent](./Agents_Step08_Telemetry/)|This sample demonstrates how to add telemetry to a simple agent|
|[Dependency injection with a simple agent](./Agents_Step09_DependencyInjection/)|This sample demonstrates how to add and resolve an agent with a dependency injection container|
## Running the samples from the console
To run the samples, navigate to the desired sample directory, e.g.
```powershell
cd Agents_Step01_Running
```
Set the following environment variables:
```powershell
$env:AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/" # Replace with your Azure OpenAI resource endpoint
$env:AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini" # Optional, defaults to gpt-4o-mini
```
If the variables are not set, you will be prompted for the values when running the samples.
Execute the following command to build the sample:
```powershell
dotnet build
```
Execute the following command to run the sample:
```powershell
dotnet run --no-build
```
Or just build and run in one step:
```powershell
dotnet run
```
## Running the samples from Visual Studio
Open the solution in Visual Studio and set the desired sample project as the startup project. Then, run the project using the built-in debugger or by pressing `F5`.
You will be prompted for any required environment variables if they are not already set.
@@ -1,41 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Extensions.Logging;
using Microsoft.Shared.Samples;
using OpenAI;
using OpenAI.Chat;
namespace Custom;
/// <summary>
/// End-to-end sample showing how to use a custom <see cref="OpenAIChatClientAgent"/>.
/// </summary>
public sealed class Custom_OpenAIChatClientAgent(ITestOutputHelper output) : AgentSample(output)
{
/// <summary>
/// This will create an instance of <see cref="MyOpenAIChatClientAgent"/> and run it.
/// </summary>
[Fact]
public async Task RunCustomChatClientAgent()
{
var chatClient = new OpenAIClient(TestConfiguration.OpenAI.ApiKey).GetChatClient(TestConfiguration.OpenAI.ChatModelId);
var agent = new MyOpenAIChatClientAgent(chatClient);
var chatMessage = new UserChatMessage("Tell me a joke about a pirate.");
var chatCompletion = await agent.RunAsync(chatMessage);
Console.WriteLine(chatCompletion.Content.Last().Text);
}
}
public class MyOpenAIChatClientAgent : OpenAIChatClientAgent
{
private const string JokerName = "Joker";
private const string JokerInstructions = "You are good at telling jokes.";
public MyOpenAIChatClientAgent(ChatClient client, ILoggerFactory? loggerFactory = null) :
base(client, instructions: JokerInstructions, name: JokerName, loggerFactory: loggerFactory)
{
}
}
@@ -1,58 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Extensions.AI.Agents;
using Microsoft.Shared.Samples;
using OpenAI;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
namespace Providers;
/// <summary>
/// End-to-end sample showing how to use <see cref="AIAgent"/> with OpenAI Assistants.
/// </summary>
public sealed class AIAgent_With_OpenAIAssistant(ITestOutputHelper output) : AgentSample(output)
{
private const string JokerName = "Joker";
private const string JokerInstructions = "You are good at telling jokes.";
[Fact]
public async Task RunWithAssistant()
{
// Get a client to create server side agents with.
var openAIClient = new OpenAIClient(TestConfiguration.OpenAI.ApiKey);
// Get the agent directly from OpenAIClient.
AIAgent agent = openAIClient
.GetAssistantClient()
.CreateAIAgent(
model: TestConfiguration.OpenAI.ChatModelId,
name: JokerName,
instructions: JokerInstructions
);
// Start a new thread for the agent conversation.
AgentThread thread = agent.GetNewThread();
// Respond to user input
await RunAgentAsync("Tell me a joke about a pirate.");
await RunAgentAsync("Now add some emojis to the joke.");
// Local function to invoke agent and display the conversation messages for the thread.
async Task RunAgentAsync(string input)
{
Console.WriteLine(
$"""
User: {input}
Assistant:
{await agent.RunAsync(input, thread)}
""");
}
// Cleanup
var assistantClient = openAIClient.GetAssistantClient();
await assistantClient.DeleteThreadAsync(thread.ConversationId);
await assistantClient.DeleteAssistantAsync(agent.Id);
}
}
+12
View File
@@ -0,0 +1,12 @@
# Getting started
The getting started samples demonstrate the fundamental concepts and functionalities
of the agent framework.
## Samples
|Sample|Description|
|---|---|
|[Agents](./Agents/README.md)|Getting started with agents|
|[Agent Providers](./AgentProviders/README.md)|Getting started with creating agents using various providers|
|[Agent Open Telemetry](./AgentOpenTelemetry/README.md)|Getting started with OpenTelemetry for agents|
@@ -1,125 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text;
using Azure.AI.Agents.Persistent;
using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using Microsoft.Shared.Samples;
using OpenAI.Files;
namespace Steps;
/// <summary>
/// Demonstrates how to use <see cref="ChatClientAgent"/> with code interpreter tools and file references.
/// Shows uploading files to different providers and using them with code interpreter capabilities to analyze data and generate responses.
/// </summary>
public sealed class Step03_ChatClientAgent_UsingCodeInterpreterTools(ITestOutputHelper output) : AgentSample(output)
{
[Theory]
[InlineData(ChatClientProviders.AzureAIAgentsPersistent)]
[InlineData(ChatClientProviders.OpenAIAssistant)]
public async Task RunningWithFileReferenceAsync(ChatClientProviders provider)
{
var codeInterpreterTool = new HostedCodeInterpreterTool()
{
Inputs = [new HostedFileContent(await UploadFileAsync("Resources/groceries.txt", provider))]
};
var agentOptions = new ChatClientAgentOptions(
name: "HelpfulAssistant",
instructions: "You are a helpful assistant.",
tools: [codeInterpreterTool]);
// Create the server-side agent Id when applicable (depending on the provider).
agentOptions.Id = await base.AgentCreateAsync(provider, agentOptions);
using var chatClient = base.GetChatClient(provider, agentOptions);
ChatClientAgent agent = new(chatClient, agentOptions);
var thread = agent.GetNewThread();
// Prompt which allows to verify that the data was processed from file correctly and current datetime is returned.
const string Prompt = "Calculate the total number of items, identify the most frequently purchased item and return the result with today's datetime.";
var assistantOutput = new StringBuilder();
var codeInterpreterOutput = new StringBuilder();
await foreach (var update in agent.RunStreamingAsync(Prompt, thread))
{
if (!string.IsNullOrWhiteSpace(update.Text))
{
assistantOutput.Append(update.Text);
}
if (update.RawRepresentation is ChatResponseUpdate chatUpdate && chatUpdate.RawRepresentation is not null)
{
codeInterpreterOutput.Append(GetCodeInterpreterOutput(chatUpdate.RawRepresentation, provider));
}
}
Console.WriteLine("Assistant Output:");
Console.WriteLine(assistantOutput.ToString());
Console.WriteLine("Code interpreter Output:");
Console.WriteLine(codeInterpreterOutput.ToString());
// Clean up the server-side agent after use when applicable (depending on the provider).
await base.AgentCleanUpAsync(provider, agent, thread);
}
#region private
/// <summary>
/// Uploads a file to the specified chat client provider and returns the file ID.
/// </summary>
/// <param name="filePath">Path to the file to be uploaded.</param>
/// <param name="provider">The chat client provider to use for uploading the file.</param>
/// <returns>The ID of the uploaded file.</returns>
/// <exception cref="NotSupportedException"></exception>
private async Task<string> UploadFileAsync(string filePath, ChatClientProviders provider)
{
switch (provider)
{
case ChatClientProviders.OpenAIAssistant:
var fileClient = new OpenAIFileClient(TestConfiguration.OpenAI.ApiKey);
OpenAIFile openAIFileInfo = await fileClient.UploadFileAsync(filePath, FileUploadPurpose.Assistants);
return openAIFileInfo.Id;
case ChatClientProviders.AzureAIAgentsPersistent:
var persistentAgentsClient = new PersistentAgentsClient(TestConfiguration.AzureAI.Endpoint, new AzureCliCredential());
PersistentAgentFileInfo persistentAgentFileInfo = await persistentAgentsClient.Files.UploadFileAsync(filePath, PersistentAgentFilePurpose.Agents);
return persistentAgentFileInfo.Id;
default:
throw new NotSupportedException($"Client provider {provider} is not supported.");
}
}
/// <summary>
/// Depending on the provider, different strategies are used to extract the code interpreter output from the response raw representation.
/// </summary>
/// <param name="rawRepresentation">Raw representation of the response containing code interpreter output.</param>
/// <param name="provider">Provider of the chat client that is used to determine how to extract the output.</param>
/// <returns>The code interpreter output as a string.</returns>
private static string? GetCodeInterpreterOutput(object rawRepresentation, ChatClientProviders provider)
=> provider switch
{
ChatClientProviders.OpenAIAssistant
when rawRepresentation is OpenAI.Assistants.RunStepDetailsUpdate stepDetails => $"{stepDetails.CodeInterpreterInput}{string.Join(
string.Empty,
stepDetails.CodeInterpreterOutputs.SelectMany(l => l.Logs)
)}",
ChatClientProviders.AzureAIAgentsPersistent
when rawRepresentation is Azure.AI.Agents.Persistent.RunStepDetailsUpdate stepDetails => $"{stepDetails.CodeInterpreterInput}{string.Join(
string.Empty,
stepDetails.CodeInterpreterOutputs.OfType<RunStepDeltaCodeInterpreterLogOutput>().SelectMany(l => l.Logs)
)}",
_ => null,
};
#endregion
}
@@ -1,131 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text;
using Azure.AI.Agents.Persistent;
using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using Microsoft.Shared.Samples;
using OpenAI.Files;
using OpenAI.VectorStores;
namespace Steps;
/// <summary>
/// Demonstrates how to use <see cref="ChatClientAgent"/> with file search tools and file references.
/// Shows uploading files to different providers and using them with file search capabilities to retrieve and analyze information from documents.
/// </summary>
public sealed class Step07_ChatClientAgent_UsingFileSearchTools(ITestOutputHelper output) : AgentSample(output)
{
[Theory]
[InlineData(ChatClientProviders.AzureAIAgentsPersistent)]
[InlineData(ChatClientProviders.OpenAIAssistant)]
public async Task RunningWithFileReferenceAsync(ChatClientProviders provider)
{
// Upload a file to the specified provider.
var fileId = await UploadFileAsync("Resources/employees.pdf", provider);
// Create a vector store for the uploaded file to enable file search capabilities.
var vectorStoreId = await CreateVectorStoreAsync([fileId], provider);
// Create a file search tool that can access the vector store.
var fileSearchTool = new HostedFileSearchTool()
{
Inputs = [new HostedVectorStoreContent(vectorStoreId)],
};
var agentOptions = new ChatClientAgentOptions
{
Name = "FileSearchAssistant",
Instructions = "You are a helpful assistant that can search through uploaded documents to answer questions. Use the file search tool to find relevant information from the uploaded files.",
ChatOptions = new() { Tools = [fileSearchTool] }
};
// Create the server-side agent Id when applicable (depending on the provider).
agentOptions.Id = await base.AgentCreateAsync(provider, agentOptions);
using var chatClient = base.GetChatClient(provider, agentOptions);
ChatClientAgent agent = new(chatClient, agentOptions);
var thread = agent.GetNewThread();
// Prompt which allows to verify that the file search functionality works correctly with the uploaded document.
const string Prompt = "Who is the youngest employee?";
var assistantOutput = new StringBuilder();
await foreach (var update in agent.RunStreamingAsync(Prompt, thread))
{
if (!string.IsNullOrWhiteSpace(update.Text))
{
assistantOutput.Append(update.Text);
}
}
Console.WriteLine("Assistant Output:");
Console.WriteLine(assistantOutput.ToString());
// Clean up the server-side agent after use when applicable (depending on the provider).
await base.AgentCleanUpAsync(provider, agent, thread);
}
#region private
/// <summary>
/// Uploads a file to the specified chat client provider and returns the file ID.
/// </summary>
/// <param name="filePath">Path to the file to be uploaded.</param>
/// <param name="provider">The chat client provider to use for uploading the file.</param>
/// <returns>The ID of the uploaded file.</returns>
/// <exception cref="NotSupportedException"></exception>
private async Task<string> UploadFileAsync(string filePath, ChatClientProviders provider)
{
switch (provider)
{
case ChatClientProviders.OpenAIAssistant:
var fileClient = new OpenAIFileClient(TestConfiguration.OpenAI.ApiKey);
OpenAIFile openAIFileInfo = await fileClient.UploadFileAsync(filePath, FileUploadPurpose.Assistants);
return openAIFileInfo.Id;
case ChatClientProviders.AzureAIAgentsPersistent:
var persistentAgentsClient = new PersistentAgentsClient(TestConfiguration.AzureAI.Endpoint, new AzureCliCredential());
PersistentAgentFileInfo persistentAgentFileInfo = await persistentAgentsClient.Files.UploadFileAsync(filePath, PersistentAgentFilePurpose.Agents);
return persistentAgentFileInfo.Id;
default:
throw new NotSupportedException($"Client provider {provider} is not supported.");
}
}
private Task<string> CreateVectorStoreAsync(IEnumerable<string> fileIds, ChatClientProviders provider)
=> provider switch
{
ChatClientProviders.OpenAIAssistant => CreateVectorStoreOpenAIAssistantAsync(fileIds),
ChatClientProviders.AzureAIAgentsPersistent => CreateVectorStoreAzureAIAgentsPersistentAsync(fileIds),
_ => throw new NotSupportedException($"Client provider {provider} is not supported."),
};
private async Task<string> CreateVectorStoreOpenAIAssistantAsync(IEnumerable<string> fileIds)
{
var vectorStoreClient = new VectorStoreClient(TestConfiguration.OpenAI.ApiKey);
VectorStoreCreationOptions options = new();
foreach (var fileId in fileIds)
{
options.FileIds.Add(fileId);
}
var vectorStore = await vectorStoreClient.CreateVectorStoreAsync(waitUntilCompleted: true, options);
return vectorStore.VectorStoreId;
}
private async Task<string> CreateVectorStoreAzureAIAgentsPersistentAsync(IEnumerable<string> fileIds)
{
var client = new PersistentAgentsClient(TestConfiguration.AzureAI.Endpoint, new AzureCliCredential());
var vectorStore = await client.VectorStores.CreateVectorStoreAsync(fileIds);
return vectorStore.Value.Id;
}
#endregion
}
@@ -1,75 +0,0 @@
# Getting started steps
The getting started steps samples demonstrate the fundamental concepts and functionalities
of the agent framework and can be used with any agent type.
While the functionality can be used with any agent type, these samples use Azure OpenAI as the AI provider
and use ChatCompletion as the type of service.
For other samples that demonstrate how to create and configure each type of agent that come with the agent framework,
see the [How to create an AIAgent for each provider](../HowToCreateAnAIAgentByProvider/README.md) samples.
## Getting started steps prerequisites
Before you begin, ensure you have the following prerequisites:
- .NET 8.0 SDK or later
- Azure OpenAI service endpoint and deployment configured
- Azure CLI installed and authenticated (for Azure credential authentication)
**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Azure OpenAI resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively).
## Samples
|Sample|Description|
|---|---|
|[Running a simple agent](./Step01_ChatClientAgent_Running/)|This sample demonstrates how to create and run a basic agent with instructions|
|[Multi-turn conversation with a simple agent](./Step02_ChatClientAgent_MultiturnConversation/)|This sample demonstrates how to implement a multi-turn conversation with a simple agent|
|[Using function tools with a simple agent](./Step03_ChatClientAgent_UsingFunctionTools/)|This sample demonstrates how to use function tools with a simple agent|
|[Using function tools with approvals](./Step04_ChatClientAgent_UsingFunctionToolsWithApprovals/)|This sample demonstrates how to use function tools where approvals require human in the loop approvals before execution|
|[Structured output with a simple agent](./Step05_ChatClientAgent_StructuredOutput/)|This sample demonstrates how to use structured output with a simple agent|
|[Persisted conversations with a simple agent](./Step06_ChatClientAgent_PersistedConversations/)|This sample demonstrates how to persist conversations and reload them later. This is useful for cases where an agent is hosted in a stateless service|
|[3rd party thread storage with a simple agent](./Step07_ChatClientAgent_3rdPartyThreadStorage/)|This sample demonstrates how to store conversation history in a 3rd party storage solution|
|[Telemetry with a simple agent](./Step08_ChatClientAgent_Telemetry/)|This sample demonstrates how to add telemetry to a simple agent|
|[Dependency injection with a simple agent](./Step09_ChatClientAgent_DependencyInjection/)|This sample demonstrates how to add and resolve an agent with a dependency injection container|
## Running the samples from the console
To run the samples, navigate to the desired sample directory, e.g.
```powershell
cd Step01_ChatClientAgent_Running
```
Set the following environment variables:
```powershell
$env:AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/" # Replace with your Azure OpenAI resource endpoint
$env:AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini" # Optional, defaults to gpt-4o-mini
```
If the variables are not set, you will be prompted for the values when running the samples.
Execute the following command to build the sample:
```powershell
dotnet build
```
Execute the following command to run the sample:
```powershell
dotnet run --no-build
```
Or just build and run in one step:
```powershell
dotnet run
```
## Running the samples from Visual Studio
Open the solution in Visual Studio and set the desired sample project as the startup project. Then, run the project using the built-in debugger or by pressing `F5`.
You will be prompted for any required environment variables if they are not already set.
@@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
@@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.Extensions.AI.Agents\Microsoft.Extensions.AI.Agents.csproj" />
</ItemGroup>
</Project>
+4 -4
View File
@@ -13,11 +13,11 @@ were local agents. These are supported using various `AIAgent` subclasses.
The samples are subdivided into the following categories:
- [Getting Started Steps](./GettingStartedSteps/README.md): Basic steps to get started with the agent framework.
- [Getting Started - Agents](./GettingStarted/Agents/README.md): Basic steps to get started with the agent framework.
These samples demonstrate the fundamental concepts and functionalities of the agent framework when using the
`ChatClientAgent` and can be used with any underlying service that the `ChatClientAgent` supports.
- [How to create an AIAgent for each provider](./HowToCreateAnAIAgentByProvider/README.md): Shows how to create an AIAgent instance for a selection of providers.
- [Agent specific features](./AgentSpecificFeatures/README.md): Samples that showcase features specific to each type of agent.
`AIAgent` and can be used with any underlying service that provides an `AIAgent` implementation.
- [Getting Started - Agent Providers](./GettingStarted/AgentProviders/README.md): Shows how to create an AIAgent instance for a selection of providers.
- [Getting Started - Agent Telemetry](./GettingStarted/AgentOpenTelemetry/README.md): Demo which showcases the integration of OpenTelemetry with the Microsoft Agent Framework using Azure OpenAI and .NET Aspire Dashboard for telemetry visualization.
## Prerequisites