Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/ProjectTemplates/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ package-lock.json
*/src/**/Directory.Build.props
*/src/**/ingestioncache.*

# launchSettings.json files are required for the templates.
!launchSettings.json
# The project templates include hard-coded launchSettings.json files
!*/src/ProjectTemplates/**/Properties/launchSettings.json

# Templates include JS dependencies in dist folders.
!**/dist/*
Expand Down
12 changes: 6 additions & 6 deletions src/ProjectTemplates/GeneratedContent.targets
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
-->
<_LocalChatTemplateVariant>aspire</_LocalChatTemplateVariant>

<_WebApiAgentRoot>$(MSBuildThisFileDirectory)Microsoft.Agents.AI.Templates\src\WebApiAgent\</_WebApiAgentRoot>
<_WebApiAgentRoot>$(MSBuildThisFileDirectory)Microsoft.Agents.AI.ProjectTemplates\src\WebApiAgent\</_WebApiAgentRoot>
<_ChatWithCustomDataContentRoot>$(MSBuildThisFileDirectory)Microsoft.Extensions.AI.Templates\src\ChatWithCustomData\</_ChatWithCustomDataContentRoot>
<_McpServerContentRoot>$(MSBuildThisFileDirectory)Microsoft.Extensions.AI.Templates\src\McpServer\</_McpServerContentRoot>
</PropertyGroup>
Expand Down Expand Up @@ -37,8 +37,8 @@
Specifies external packages that get referenced in generated template content.
-->
<PropertyGroup>
<TemplatePackageVersion_MicrosoftAgentsAI>1.0.0-preview.251104.1</TemplatePackageVersion_MicrosoftAgentsAI>
<TemplatePackageVersion_MicrosoftAgentsAIHostingOpenAI>1.0.0-alpha.251104.1</TemplatePackageVersion_MicrosoftAgentsAIHostingOpenAI>
<TemplatePackageVersion_MicrosoftAgentsAI>1.0.0-preview.251110.2</TemplatePackageVersion_MicrosoftAgentsAI>
<TemplatePackageVersion_MicrosoftAgentsAIHostingOpenAI>1.0.0-alpha.251110.2</TemplatePackageVersion_MicrosoftAgentsAIHostingOpenAI>
<TemplatePackageVersion_Aspire>9.5.1</TemplatePackageVersion_Aspire>
<TemplatePackageVersion_Aspire_Preview>9.5.1-preview.1.25502.11</TemplatePackageVersion_Aspire_Preview>
<TemplatePackageVersion_AzureAIProjects>1.0.0</TemplatePackageVersion_AzureAIProjects>
Expand Down Expand Up @@ -91,6 +91,9 @@
</PropertyGroup>

<ItemGroup>
<GeneratedContent
Include="$(_WebApiAgentRoot)WebApiAgent-CSharp\WebApiAgent-CSharp.csproj.in"
OutputPath="$(_WebApiAgentRoot)WebApiAgent-CSharp\WebApiAgent-CSharp.csproj" />
<GeneratedContent
Include="$(_ChatWithCustomDataContentRoot)ChatWithCustomData-CSharp.sln.in"
OutputPath="$(_ChatWithCustomDataContentRoot)ChatWithCustomData-CSharp.sln" />
Expand All @@ -100,9 +103,6 @@
<GeneratedContent
Include="$(_ChatWithCustomDataContentRoot)Directory.Build.props.in"
OutputPath="$(_ChatWithCustomDataContentRoot)Directory.Build.props" />
<GeneratedContent
Include="$(_WebApiAgentRoot)WebApiAgent-CSharp\WebApiAgent-CSharp.csproj.in"
OutputPath="$(_WebApiAgentRoot)WebApiAgent-CSharp\WebApiAgent-CSharp.csproj" />
<GeneratedContent
Include="$(_ChatWithCustomDataContentRoot)ChatWithCustomData-CSharp.Web\ChatWithCustomData-CSharp.Web.csproj.in"
OutputPath="$(_ChatWithCustomDataContentRoot)ChatWithCustomData-CSharp.Web\ChatWithCustomData-CSharp.Web.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@
<PackageTags>dotnet-new;templates;ai;agent</PackageTags>

<Stage>preview</Stage>
<PreReleaseVersionIteration>1</PreReleaseVersionIteration>

<!-- Set the version info to align with Microsoft.Agents.AI packages -->
<MajorVersion>1</MajorVersion>
<MinorVersion>0</MinorVersion>
<PatchVersion>0</PatchVersion>
<PreReleaseVersionLabel>preview</PreReleaseVersionLabel>
<VersionSuffix>preview.251110.2</VersionSuffix>

<Workstream>AI</Workstream>
<MinCodeCoverage>0</MinCodeCoverage>
<MinMutationScore>0</MinMutationScore>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Microsoft.Agents.AI.Templates
# Microsoft.Agents.AI.ProjectTemplates

Provides project templates for Microsoft.Agents.AI.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "http://json.schemastore.org/template",
"author": "Microsoft",
"classifications": [ "Common", "AI", "API", "Web", "Web API", "WebAPI", "Service" ],
"identity": "Microsoft.Agents.AI.Templates.WebApiAgent.CSharp",
"identity": "Microsoft.Agents.AI.ProjectTemplates.WebApiAgent.CSharp",
"name": "AI Agent Web API",
"description": "A project template for creating an AI Agent Web API application.",
"shortName": "aiagent-webapi",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,41 @@
using Azure.Identity;
#endif
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.DevUI;
using Microsoft.Agents.AI.Hosting;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Extensions.AI;
#if (IsOllama)
using OllamaSharp;
#elif (IsGHModels || IsOpenAI || IsAzureOpenAI)
#endif
#if (IsGHModels || IsAzureOpenAI)
using OpenAI;
#endif
#if (IsGHModels || IsOpenAI || IsAzureOpenAI)
using OpenAI.Chat;
#endif

var builder = WebApplication.CreateBuilder(args);

#if (IsGHModels)
// You will need to set the token to your own value
// You can do this using Visual Studio's "Manage User Secrets" UI, or on the command line:
// cd this-project-directory
// dotnet user-secrets set GitHubModels:Token YOUR-GITHUB-TOKEN
var credential = new ApiKeyCredential(builder.Configuration["GitHubModels:Token"] ?? throw new InvalidOperationException("Missing configuration: GitHubModels:Token. See README for details."));
var openAIOptions = new OpenAIClientOptions { Endpoint = new Uri("https://models.inference.ai.azure.com") };

var chatClient = new OpenAIClient(credential, openAIOptions)
.GetChatClient("gpt-4o-mini").AsIChatClient();
#elif (IsOllama)
// You will need to have Ollama running locally with the llama3.2 model installed
// Visit https://ollama.com for installation instructions
var chatClient = new OllamaApiClient(new Uri("http://localhost:11434"), "llama3.2");
// dotnet user-secrets set "GITHUB_TOKEN" "your-github-models-token-here"
var chatClient = new ChatClient(
"gpt-4o-mini",
new ApiKeyCredential(builder.Configuration["GITHUB_TOKEN"] ?? throw new InvalidOperationException("Missing configuration: GITHUB_TOKEN")),
new OpenAIClientOptions { Endpoint = new Uri("https://models.inference.ai.azure.com") })
.AsIChatClient();
#elif (IsOpenAI)
// You will need to set the API key to your own value
// You can do this using Visual Studio's "Manage User Secrets" UI, or on the command line:
// cd this-project-directory
// dotnet user-secrets set OpenAI:Key YOUR-API-KEY
var openAIClient = new OpenAIClient(
new ApiKeyCredential(builder.Configuration["OpenAI:Key"] ?? throw new InvalidOperationException("Missing configuration: OpenAI:Key. See README for details.")));

#pragma warning disable OPENAI001 // GetOpenAIResponseClient(string) is experimental and subject to change or removal in future updates.
var chatClient = openAIClient.GetOpenAIResponseClient("gpt-4o-mini").AsIChatClient();
#pragma warning restore OPENAI001
// dotnet user-secrets set "OPENAI_KEY" "your-openai-api-key-here"
var chatClient = new ChatClient(
"gpt-4o-mini",
new ApiKeyCredential(builder.Configuration["OPENAI_KEY"] ?? throw new InvalidOperationException("Missing configuration: OPENAI_KEY")))
.AsIChatClient();
#elif (IsAzureOpenAI)
// You will need to set the endpoint to your own value
// You can do this using Visual Studio's "Manage User Secrets" UI, or on the command line:
Expand All @@ -52,21 +51,27 @@
#if (!IsManagedIdentity)
// dotnet user-secrets set AzureOpenAI:Key YOUR-API-KEY
#endif
var azureOpenAIEndpoint = new Uri(new Uri(builder.Configuration["AzureOpenAI:Endpoint"] ?? throw new InvalidOperationException("Missing configuration: AzureOpenAI:Endpoint. See README for details.")), "/openai/v1");
#if (IsManagedIdentity)
#pragma warning disable OPENAI001 // OpenAIClient(AuthenticationPolicy, OpenAIClientOptions) and GetOpenAIResponseClient(string) are experimental and subject to change or removal in future updates.
var azureOpenAI = new OpenAIClient(
new BearerTokenPolicy(new DefaultAzureCredential(), "https://ai.azure.com/.default"),
new OpenAIClientOptions { Endpoint = azureOpenAIEndpoint });

#elif (!IsManagedIdentity)
var openAIOptions = new OpenAIClientOptions { Endpoint = azureOpenAIEndpoint };
var azureOpenAI = new OpenAIClient(new ApiKeyCredential(builder.Configuration["AzureOpenAI:Key"] ?? throw new InvalidOperationException("Missing configuration: AzureOpenAI:Key. See README for details.")), openAIOptions);
var azureOpenAIEndpoint = new Uri(new Uri(builder.Configuration["AzureOpenAI:Endpoint"] ?? throw new InvalidOperationException("Missing configuration: AzureOpenAI:Endpoint")), "/openai/v1");

#pragma warning disable OPENAI001 // GetOpenAIResponseClient(string) is experimental and subject to change or removal in future updates.
#endif
var chatClient = azureOpenAI.GetOpenAIResponseClient("gpt-4o-mini").AsIChatClient();
#if (IsManagedIdentity)
#pragma warning disable OPENAI001 // The overload accepting an AuthenticationPolicy is experimental and may change or be removed in future releases.
var chatClient = new ChatClient(
"gpt-4o-mini",
new BearerTokenPolicy(new DefaultAzureCredential(), "https://ai.azure.com/.default"),
new OpenAIClientOptions { Endpoint = azureOpenAIEndpoint })
.AsIChatClient();
#pragma warning restore OPENAI001
#else
var chatClient = new ChatClient(
"gpt-4o-mini",
new ApiKeyCredential(builder.Configuration["AzureOpenAI:Key"] ?? throw new InvalidOperationException("Missing configuration: AzureOpenAI:Key")),
new OpenAIClientOptions { Endpoint = azureOpenAIEndpoint })
.AsIChatClient();
#endif
#elif (IsOllama)
// You will need to have Ollama running locally with the llama3.2 model installed
// Visit https://ollama.com for installation instructions
var chatClient = new OllamaApiClient(new Uri("http://localhost:11434"), "llama3.2");
#endif

builder.Services.AddChatClient(chatClient);
Expand All @@ -76,8 +81,8 @@
builder.AddAIAgent("editor", (sp, key) => new ChatClientAgent(
chatClient,
name: key,
instructions: "You edit short stories to improve grammar and style. You ensure the stories are less than 300 words.",
tools: [ AIFunctionFactory.Create(FormatStory) ]
instructions: "You edit short stories to improve grammar and style, ensuring the stories are less than 300 words. Once finished editing, you select a title and format the story for publishing.",
tools: [AIFunctionFactory.Create(FormatStory)]
));

builder.AddWorkflow("publisher", (sp, key) => AgentWorkflowBuilder.BuildSequential(
Expand All @@ -86,17 +91,28 @@
sp.GetRequiredKeyedService<AIAgent>("editor")
)).AddAsAIAgent();

var app = builder.Build();
// Register services for OpenAI responses and conversations (also required for DevUI)
builder.Services.AddOpenAIResponses();
builder.Services.AddOpenAIConversations();

var app = builder.Build();
app.UseHttpsRedirection();

// Map endpoints for OpenAI responses and conversations (also required for DevUI)
app.MapOpenAIResponses();
app.MapOpenAIConversations();

if (builder.Environment.IsDevelopment())
{
// Map DevUI endpoint to /devui
app.MapDevUI();
}

app.Run();

[Description("Formats the story for display.")]
[Description("Formats the story for publication, revealing its title.")]
string FormatStory(string title, string story) => $"""
**Title**: {title}
**Date**: {DateTime.Today.ToShortDateString()}

{story}
""";
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"launchBrowser": true,
"launchUrl": "devui/",
"applicationUrl": "http://localhost:5056",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
Expand All @@ -13,7 +14,8 @@
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"launchBrowser": true,
"launchUrl": "devui/",
"applicationUrl": "https://localhost:7041;http://localhost:5056",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ This application uses GitHub Models (model: gpt-4o-mini) for AI functionality. Y
**Option A: Using User Secrets (Recommended for Development)**

```bash
dotnet user-secrets set "GitHubModels:Token" "your-github-models-token-here"
dotnet user-secrets set "GITHUB_TOKEN" "your-github-models-token-here"
```

**Option B: Using Environment Variables**

Set the `GitHubModels__Token` environment variable:
Set the `GITHUB_TOKEN` environment variable:

- **Windows (PowerShell)**:
```powershell
$env:GitHubModels__Token = "your-github-models-token-here"
$env:GITHUB_TOKEN = "your-github-models-token-here"
```

- **Linux/macOS**:
```bash
export GitHubModels__Token="your-github-models-token-here"
export GITHUB_TOKEN="your-github-models-token-here"
```

#### Get a GitHub Models Token
Expand All @@ -59,21 +59,21 @@ This application uses the OpenAI Platform (model: gpt-4o-mini). You'll need to c
**Using User Secrets (Recommended for Development)**

```bash
dotnet user-secrets set "OpenAI:Key" "your-openai-api-key-here"
dotnet user-secrets set "OPENAI_KEY" "your-openai-api-key-here"
```

**Using Environment Variables**

Set the `OpenAI__Key` environment variable:
Set the `OPENAI_KEY` environment variable:

- **Windows (PowerShell)**:
```powershell
$env:OpenAI__Key = "your-openai-api-key-here"
$env:OPENAI_KEY = "your-openai-api-key-here"
```

- **Linux/macOS**:
```bash
export OpenAI__Key="your-openai-api-key-here"
export OPENAI_KEY="your-openai-api-key-here"
```

#### Get an OpenAI API Key
Expand Down Expand Up @@ -165,6 +165,8 @@ The application will start and listen on:

The application exposes OpenAI-compatible API endpoints. You can interact with the AI agents using any OpenAI-compatible client or tools.

In development environments, a `/devui/` route is mapped to the Agent Framework development UI (DevUI), and when the app is launched through an IDE a browser will open to this URL. DevUI provides a web-based UI for interacting with agents and workflows. DevUI operates as an OpenAI-compatible client using the Responses and Conversations endpoints.

## How It Works

This application demonstrates Agent Framework with:
Expand Down Expand Up @@ -234,7 +236,7 @@ dotnet new aiagent-webapi --provider ollama --chat-model llama3.1
## Troubleshooting

<!--#if (IsGHModels) -->
**Problem**: Application fails with "Missing configuration: GitHubModels:Token"
**Problem**: Application fails with "Missing configuration: GITHUB_TOKEN"

**Solution**: Make sure you've configured your GitHub Models API token using one of the methods described above.

Expand All @@ -243,7 +245,7 @@ dotnet new aiagent-webapi --provider ollama --chat-model llama3.1
**Solution**: Verify your GitHub Models token is valid and hasn't expired. You may need to regenerate it from the GitHub Models website.

<!--#elif (IsOpenAI) -->
**Problem**: Application fails with "Missing configuration: OpenAI:Key"
**Problem**: Application fails with "Missing configuration: OPENAI_KEY"

**Solution**: Make sure you've configured your OpenAI API key using one of the methods described above.

Expand All @@ -252,33 +254,42 @@ dotnet new aiagent-webapi --provider ollama --chat-model llama3.1
**Solution**: Verify your OpenAI API key is valid. Check your usage limits and billing status on the OpenAI Platform.

<!--#elif (IsAzureOpenAI) -->
**Problem**: Application fails with "Missing configuration: AzureOpenAI:Endpoint"<!--#if (!IsManagedIdentity) --> or "Missing configuration: AzureOpenAI:Key"<!--#endif -->
<!--#if (!IsManagedIdentity) -->
**Problem**: Application fails with "Missing configuration: AzureOpenAI:Endpoint" or "Missing configuration: AzureOpenAI:Key"

**Solution**: Make sure you've configured your Azure OpenAI endpoint<!--#if (!IsManagedIdentity) --> and API key<!--#endif --> using one of the methods described above.
**Solution**: Make sure you've configured your Azure OpenAI endpoint and API key using one of the methods described above.

**Problem**: API requests fail with authentication errors

**Solution**: Verify your Azure OpenAI endpoint is correct and your API key is valid.

<!--#else -->
**Problem**: Application fails with "Missing configuration: AzureOpenAI:Endpoint"

**Solution**: Make sure you've configured your Azure OpenAI endpoint using one of the methods described above.

<!--#if (IsManagedIdentity) -->
**Problem**: Managed identity authentication fails

**Solution**:
**Solution**:
- Ensure your Azure resource has a system-assigned or user-assigned managed identity enabled
- Verify the managed identity has been granted the "Cognitive Services OpenAI User" role on your Azure OpenAI resource
- For local development, ensure you're signed in to Azure CLI: `az login`

<!--#endif -->
**Problem**: API requests fail with authentication errors

**Solution**: Verify your Azure OpenAI endpoint is correct and<!--#if (!IsManagedIdentity) --> your API key is valid<!--#endif --><!--#if (IsManagedIdentity) --> your managed identity has the correct permissions<!--#endif -->.
**Solution**: Verify your Azure OpenAI endpoint is correct and your managed identity has the correct permissions.

<!--#endif -->

<!--#elif (IsOllama) -->
**Problem**: Application fails to connect to Ollama

**Solution**:
**Solution**:
- Ensure Ollama is running. On macOS/Linux, check with `pgrep ollama`. On Windows, check Task Manager.
- Verify Ollama is accessible at `http://localhost:11434`
- Make sure you've downloaded the llama3.2 model: `ollama pull llama3.2`

**Problem**: Model responses are slow or time out

**Solution**: Ollama runs locally and performance depends on your hardware. Consider using a smaller model or ensuring your system has adequate resources (RAM, GPU if available).

<!--#endif -->
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@
</PropertyGroup>

<ItemGroup>
<!--#if (IsAzureOpenAI && IsManagedIdentity) -->
<PackageReference Include="Azure.Identity" Version="${TemplatePackageVersion_AzureIdentity}" />
<!--#endif -->
<PackageReference Include="Microsoft.Agents.AI" Version="${TemplatePackageVersion_MicrosoftAgentsAI}" />
<PackageReference Include="Microsoft.Agents.AI.DevUI" Version="${TemplatePackageVersion_MicrosoftAgentsAI}" />
<PackageReference Include="Microsoft.Agents.AI.Hosting" Version="${TemplatePackageVersion_MicrosoftAgentsAI}" />
<PackageReference Include="Microsoft.Agents.AI.Hosting.OpenAI" Version="${TemplatePackageVersion_MicrosoftAgentsAIHostingOpenAI}" />
<!--#if (IsOpenAI || IsAzureOpenAI || IsGHModels) -->
<PackageReference Include="Microsoft.Agents.AI.OpenAI" Version="${TemplatePackageVersion_MicrosoftAgentsAI}" />
<!--#endif -->
<PackageReference Include="Microsoft.Agents.AI.Workflows" Version="${TemplatePackageVersion_MicrosoftAgentsAI}" />
<!--#if (IsOllama) -->
<PackageReference Include="OllamaSharp" Version="${TemplatePackageVersion_OllamaSharp}" />
<!--#endif -->
<!--#if (IsAzureOpenAI && IsManagedIdentity) -->
<PackageReference Include="Azure.Identity" Version="${TemplatePackageVersion_AzureIdentity}" />
<!--#endif -->
<PackageReference Include="Microsoft.Agents.AI.Workflows" Version="${TemplatePackageVersion_MicrosoftAgentsAI}" />
</ItemGroup>

</Project>
Loading
Loading