Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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/**/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