.NET: Enhance console samples while preserving copyability (#475)

* Enhance console samples while preserving copyability

* Add readme for minimal console demo

* Suppress pre-release version warning

* Address PR comments

* Change showing settings to opt-in

* Update comment
This commit is contained in:
westey
2025-08-22 15:58:10 +01:00
committed by GitHub
Unverified
parent 25291de8cb
commit 71a0bf22eb
9 changed files with 229 additions and 13 deletions
+8
View File
@@ -31,6 +31,10 @@
<File Path="../.github/workflows/dotnet-cosmosdb-integration-tests.yml" />
<File Path="../.github/workflows/dotnet-format.yml" />
</Folder>
<Folder Name="/Solution Items/demos/">
<File Path="demos/.editorconfig" />
<File Path="demos/Directory.Build.props" />
</Folder>
<Folder Name="/Solution Items/docs/" />
<Folder Name="/Solution Items/docs/decisions/">
<File Path="../docs/decisions/0001-agent-run-response.md" />
@@ -88,6 +92,10 @@
<File Path="src/LegacySupport/TrimAttributes/UnconditionalSuppressMessageAttribute.cs" />
</Folder>
<Folder Name="/Solution Items/src/Shared/" />
<Folder Name="/Solution Items/src/Shared/Demos/">
<File Path="src/Shared/Demos/README.md" />
<File Path="src/Shared/Demos/SampleEnvironment.cs" />
</Folder>
<Folder Name="/Solution Items/src/Shared/IntegrationTests/">
<File Path="src/Shared/IntegrationTests/AzureAIConfiguration.cs" />
<File Path="src/Shared/IntegrationTests/OpenAIConfiguration.cs" />
@@ -2,9 +2,11 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TargetFrameworks>$(ProjectsTargetFrameworks)</TargetFrameworks>
<TargetFrameworks Condition="'$(Configuration)' == 'Debug'">$(ProjectsDebugTargetFrameworks)</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
+1 -1
View File
@@ -97,7 +97,7 @@ logger.LogInformation("OTLP endpoint configured: {OtlpEndpoint}", otlpEndpoint);
logger.LogDebug("Service name: {ServiceName}, Source name: {SourceName}", ServiceName, SourceName);
// Create the chat client
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT", EnvironmentVariableTarget.Machine) ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT environment variable is not set.");
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";
logger.LogInformation("Initializing Azure OpenAI client with endpoint: {Endpoint}", endpoint);
+14 -6
View File
@@ -1,12 +1,20 @@
<Project>
<Import Project="../Directory.Build.props" />
<PropertyGroup>
<IsPackable>false</IsPackable>
<IsAotCompatible>false</IsAotCompatible>
<ProjectsTargetFrameworks>net472;net9.0</ProjectsTargetFrameworks>
<UserSecretsId>5ee045b0-aea3-4f08-8d31-32d1a6f8fed0</UserSecretsId>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<AnalysisLevel>latest</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Configurations>Debug;Release;Publish</Configurations>
<NoWarn>$(NoWarn);NU5104</NoWarn>
</PropertyGroup>
<ItemGroup>
<Using Include="SampleHelpers.SampleEnvironment" Alias="Environment" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)\..\src\Shared\Demos\*.cs" LinkBase="" Visible="false" />
</ItemGroup>
</Project>
@@ -2,8 +2,11 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>$(ProjectsTargetFrameworks)</TargetFrameworks>
<TargetFrameworks Condition="'$(Configuration)' == 'Debug'">$(ProjectsDebugTargetFrameworks)</TargetFrameworks>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
+5 -2
View File
@@ -8,14 +8,17 @@ using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using OpenAI;
var azureOpenAIEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var azureOpenAIDeploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
AIAgent agent = new AzureOpenAIClient(
new Uri(Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!),
new Uri(azureOpenAIEndpoint),
new AzureCliCredential())
.GetChatClient("gpt-4o-mini")
.GetChatClient(azureOpenAIDeploymentName)
.CreateAIAgent(
instructions: "You are a helpful assistant, you can help the user with weather information.",
tools: [AIFunctionFactory.Create(GetWeather)]);
+30
View File
@@ -0,0 +1,30 @@
# Minimal Console Application
This demo shows a very basic console application, that uses the agent framework with Azure OpenAI and function calling.
## Overview
## Prerequisites
- .NET 8.0 SDK or later
- Azure OpenAI service endpoint and deployment configured
- Azure CLI installed and authenticated (for Azure credential authentication)
## 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
```powershell
cd dotnet/demos/MinimalConsole
dotnet build
dotnet run --no-build
```
+20
View File
@@ -0,0 +1,20 @@
# Demos
Contains a helper that adds an override `System.Environment` class to a project.
This override version has an enhanced `GetEnvironmentVariable` method that prompts the user
to enter a value if the environment variable is not set.
The code is still fully copyable to another project. These sample projects just allow for a simplified user experience
for users who are new and just getting started.
To use this in your project, add the following to your `.csproj` file:
```xml
<ItemGroup>
<Using Include="SampleHelpers.SampleEnvironment" Alias="Environment" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)\..\src\Shared\Demos\*.cs" LinkBase="" Visible="false" />
</ItemGroup>
```
@@ -0,0 +1,142 @@
// Copyright (c) Microsoft. All rights reserved.
#pragma warning disable IDE0005 // Using directive is unnecessary. - need to suppress this, since this file is used in both projects with implicit usings and without.
using System;
using System.Collections;
using SystemEnvironment = System.Environment;
namespace SampleHelpers;
internal static class SampleEnvironment
{
public static string? GetEnvironmentVariable(string key)
{
// Allows for opting into showing all setting values in the console output, so that it is easy to troubleshoot sample setup issues.
var showAllSampleValues = SystemEnvironment.GetEnvironmentVariable("AF_SHOW_ALL_DEMO_SETTING_VALUES");
var shouldShowValue = showAllSampleValues?.ToUpperInvariant() == "Y";
var value = SystemEnvironment.GetEnvironmentVariable(key);
if (string.IsNullOrWhiteSpace(value))
{
var color = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("Setting '");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(key);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("' is not set in environment variables.");
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("Please provide the setting for '");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(key);
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("'> ");
Console.ForegroundColor = color;
value = Console.ReadLine();
value = string.IsNullOrWhiteSpace(value) ? null : value.Trim();
Console.WriteLine();
}
else if (shouldShowValue)
{
var color = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("Using setting: Source=");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("EnvironmentVariables");
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(", Key='");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(key);
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("', Value='");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(value);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("'");
Console.ForegroundColor = color;
Console.WriteLine();
}
return value;
}
// Methods that directly call System.Environment
public static string? GetEnvironmentVariable(string variable, EnvironmentVariableTarget target)
=> System.Environment.GetEnvironmentVariable(variable, target);
public static IDictionary GetEnvironmentVariables()
=> System.Environment.GetEnvironmentVariables();
public static IDictionary GetEnvironmentVariables(EnvironmentVariableTarget target)
=> System.Environment.GetEnvironmentVariables(target);
public static void SetEnvironmentVariable(string variable, string? value)
=> System.Environment.SetEnvironmentVariable(variable, value);
public static void SetEnvironmentVariable(string variable, string? value, EnvironmentVariableTarget target)
=> System.Environment.SetEnvironmentVariable(variable, value, target);
public static string[] GetCommandLineArgs()
=> System.Environment.GetCommandLineArgs();
public static string CommandLine
=> System.Environment.CommandLine;
public static string CurrentDirectory
{
get => System.Environment.CurrentDirectory;
set => System.Environment.CurrentDirectory = value;
}
public static string ExpandEnvironmentVariables(string name)
=> System.Environment.ExpandEnvironmentVariables(name);
public static string GetFolderPath(System.Environment.SpecialFolder folder)
=> System.Environment.GetFolderPath(folder);
public static string GetFolderPath(System.Environment.SpecialFolder folder, System.Environment.SpecialFolderOption option)
=> System.Environment.GetFolderPath(folder, option);
public static int ProcessorCount
=> System.Environment.ProcessorCount;
public static bool Is64BitProcess
=> System.Environment.Is64BitProcess;
public static bool Is64BitOperatingSystem
=> System.Environment.Is64BitOperatingSystem;
public static string MachineName
=> System.Environment.MachineName;
public static string NewLine
=> System.Environment.NewLine;
public static OperatingSystem OSVersion
=> System.Environment.OSVersion;
public static string StackTrace
=> System.Environment.StackTrace;
public static int SystemPageSize
=> System.Environment.SystemPageSize;
public static bool HasShutdownStarted
=> System.Environment.HasShutdownStarted;
#if NET9_0_OR_GREATER
public static int ProcessId
=> System.Environment.ProcessId;
public static string? ProcessPath
=> System.Environment.ProcessPath;
public static bool IsPrivilegedProcess
=> System.Environment.IsPrivilegedProcess;
#endif
}