Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e360297
Add some OpenAI specific extensions
markwallace-microsoft Jul 23, 2025
48ad3cf
Update samples and extension methods
markwallace-microsoft Jul 23, 2025
f798ca4
Apply suggestion from @Copilot
markwallace-microsoft Jul 24, 2025
c781aca
Apply suggestion from @Copilot
markwallace-microsoft Jul 24, 2025
ea4f59c
Merge branch 'main' into users/markwallace/openai_extensions
markwallace-microsoft Jul 24, 2025
4b7858a
Add extension methods for creating agents using the Assistant API
markwallace-microsoft Jul 28, 2025
c42226c
Add orchestration sample
markwallace-microsoft Jul 28, 2025
2269b1a
Add orchestration sample
markwallace-microsoft Jul 28, 2025
7a08b19
Merge branch 'main' into users/markwallace/openai_extensions
markwallace-microsoft Jul 28, 2025
4ff3894
Merge branch 'users/markwallace/openai_extensions' of https://github.…
markwallace-microsoft Jul 28, 2025
be94f1d
Sample for the Foundry alignment document
markwallace-microsoft Jul 28, 2025
d3906f5
Merge branch 'main' into users/markwallace/openai_extensions
markwallace-microsoft Jul 29, 2025
8aed6e5
Address code review feedback
markwallace-microsoft Jul 29, 2025
0013f75
Merge branch 'main' into users/markwallace/openai_extensions
markwallace-microsoft Jul 29, 2025
d221ef5
Rename provider samples
markwallace-microsoft Jul 29, 2025
e33a6b7
Sample showing how to get an AI agent for Foundry SDK
markwallace-microsoft Jul 29, 2025
43f303f
Add OpenAI chat completion based implementation of AIAgent
markwallace-microsoft Jul 29, 2025
3759963
Merge latest from main
markwallace-microsoft Jul 30, 2025
76a56cd
Merge branch 'main' into users/markwallace/openai_extensions
markwallace-microsoft Jul 31, 2025
6fbc11e
Split OpenAI client extension methods by client type
markwallace-microsoft Jul 31, 2025
8008699
Remove OpenAIClient extension methods
markwallace-microsoft Jul 31, 2025
786b5e3
Rename AsRunnableAgent
markwallace-microsoft Jul 31, 2025
b20f2a2
Merge branch 'main' into users/markwallace/openai_extensions
markwallace-microsoft Jul 31, 2025
4361c64
Fix XML comments
markwallace-microsoft Jul 31, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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 openAIClient = new OpenAIClient(TestConfiguration.OpenAI.ApiKey);
var model = TestConfiguration.OpenAI.ChatModelId;

var agent = new MyOpenAIChatClientAgent(openAIClient, model);

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(OpenAIClient client, string model, ILoggerFactory? loggerFactory = null) :
base(client, model, instructions: JokerInstructions, name: JokerName, loggerFactory: loggerFactory)
{
}
}
2 changes: 1 addition & 1 deletion dotnet/samples/GettingStarted/GettingStarted.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<RootNamespace>GettingStarted</RootNamespace>
<OutputType>Library</OutputType>
<UserSecretsId>5ee045b0-aea3-4f08-8d31-32d1a6f8fed0</UserSecretsId>
<NoWarn>$(NoWarn);CA1707;CA1716;IDE0009;IDE1006;OPENAI001;</NoWarn>
<NoWarn>$(NoWarn);CA1707;CA1716;IDE0009;IDE1006; OPENAI001;</NoWarn>
<ImplicitUsings>enable</ImplicitUsings>
<InjectSharedSamples>true</InjectSharedSamples>
<InjectSharedThrow>true</InjectSharedThrow>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (c) Microsoft. All rights reserved.

using Azure.AI.Agents.Persistent;
using Azure.Identity;
using Microsoft.Agents.Orchestration;
using Microsoft.Extensions.AI.Agents;
using Microsoft.Shared.Samples;

namespace Orchestration;

/// <summary>
/// Demonstrates how to use the <see cref="SequentialOrchestration"/> for
/// executing multiple Foundry agents in sequence.
/// </summary>
public class SequentialOrchestration_Foundry_Agents(ITestOutputHelper output) : OrchestrationSample(output)
{
[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task RunOrchestrationAsync(bool streamedResponse)
{
// Get a client to create server side agents with.
var persistentAgentsClient = new PersistentAgentsClient(TestConfiguration.AzureAI.Endpoint, new AzureCliCredential());
var model = TestConfiguration.OpenAI.ChatModelId;

// Define the agents
AIAgent analystAgent =
await persistentAgentsClient.CreateAIAgentAsync(
model,
name: "Analyst",
instructions:
"""
You are a marketing analyst. Given a product description, identify:
- Key features
- Target audience
- Unique selling points
""",
description: "A agent that extracts key concepts from a product description.");
AIAgent writerAgent =
await persistentAgentsClient.CreateAIAgentAsync(
model,
name: "copywriter",
instructions:
"""
You are a marketing copywriter. Given a block of text describing features, audience, and USPs,
compose a compelling marketing copy (like a newsletter section) that highlights these points.
Output should be short (around 150 words), output just the copy as a single text block.
""",
description: "An agent that writes a marketing copy based on the extracted concepts.");
AIAgent editorAgent =
await persistentAgentsClient.CreateAIAgentAsync(
model,
name: "editor",
instructions:
"""
You are an editor. Given the draft copy, correct grammar, improve clarity, ensure consistent tone,
give format and make it polished. Output the final improved copy as a single text block.
""",
description: "An agent that formats and proofreads the marketing copy.");

// Create a monitor to capturing agent responses (via ResponseCallback)
// to display at the end of this sample. (optional)
// NOTE: Create your own callback to capture responses in your application or service.
OrchestrationMonitor monitor = new();
// Define the orchestration
SequentialOrchestration orchestration =
new(analystAgent, writerAgent, editorAgent)
{
LoggerFactory = this.LoggerFactory,
ResponseCallback = monitor.ResponseCallback,
StreamingResponseCallback = streamedResponse ? monitor.StreamingResultCallback : null,
};

// Run the orchestration
string input = "An eco-friendly stainless steel water bottle that keeps drinks cold for 24 hours";
Console.WriteLine($"\n# INPUT: {input}\n");
AgentRunResponse result = await orchestration.RunAsync(input);
Console.WriteLine($"\n# RESULT: {result}");

this.DisplayHistory(monitor.History);

// Cleanup
await persistentAgentsClient.Administration.DeleteAgentAsync(editorAgent.Id);
await persistentAgentsClient.Administration.DeleteAgentAsync(writerAgent.Id);
await persistentAgentsClient.Administration.DeleteAgentAsync(analystAgent.Id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) Microsoft. All rights reserved.

using Microsoft.Agents.Orchestration;
using Microsoft.Extensions.AI.Agents;
using Microsoft.Shared.Samples;
using OpenAI;

namespace Orchestration;

/// <summary>
/// Demonstrates how to use the <see cref="SequentialOrchestration"/> for
/// executing multiple heterogeneous agents in sequence.
/// </summary>
public class SequentialOrchestration_Multi_Agent(ITestOutputHelper output) : OrchestrationSample(output)
{
[Theory]
[InlineData(false)]
[InlineData(true)]
public async Task RunOrchestrationAsync(bool streamedResponse)
{
var openAIClient = new OpenAIClient(TestConfiguration.OpenAI.ApiKey);
var model = TestConfiguration.OpenAI.ChatModelId;

// Define the agents
AIAgent analystAgent =
openAIClient.CreateChatClientAgent(
model,
name: "Analyst",
instructions:
"""
You are a marketing analyst. Given a product description, identify:
- Key features
- Target audience
- Unique selling points
""",
description: "A agent that extracts key concepts from a product description.");
AIAgent writerAgent =
openAIClient.CreateResponseClientAgent(
model,
name: "copywriter",
instructions:
"""
You are a marketing copywriter. Given a block of text describing features, audience, and USPs,
compose a compelling marketing copy (like a newsletter section) that highlights these points.
Output should be short (around 150 words), output just the copy as a single text block.
""",
description: "An agent that writes a marketing copy based on the extracted concepts.");
AIAgent editorAgent =
await openAIClient.CreateAssistantClientAgentAsync(
model,
name: "editor",
instructions:
"""
You are an editor. Given the draft copy, correct grammar, improve clarity, ensure consistent tone,
give format and make it polished. Output the final improved copy as a single text block.
""",
description: "An agent that formats and proofreads the marketing copy.");

// Create a monitor to capturing agent responses (via ResponseCallback)
// to display at the end of this sample. (optional)
// NOTE: Create your own callback to capture responses in your application or service.
OrchestrationMonitor monitor = new();
// Define the orchestration
SequentialOrchestration orchestration =
new(analystAgent, writerAgent, editorAgent)
{
LoggerFactory = this.LoggerFactory,
ResponseCallback = monitor.ResponseCallback,
StreamingResponseCallback = streamedResponse ? monitor.StreamingResultCallback : null,
};

// Run the orchestration
string input = "An eco-friendly stainless steel water bottle that keeps drinks cold for 24 hours";
Console.WriteLine($"\n# INPUT: {input}\n");
AgentRunResponse result = await orchestration.RunAsync(input);
Console.WriteLine($"\n# RESULT: {result}");

this.DisplayHistory(monitor.History);

// Cleanup
var assistantClient = openAIClient.GetAssistantClient();
await assistantClient.DeleteAssistantAsync(editorAgent.Id);
// Need to know how to get the assistant thread ID to delete the thread (issue #260)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) Microsoft. All rights reserved.

using Azure.AI.Agents.Persistent;
using Azure.Identity;
using Microsoft.Extensions.AI.Agents;
using Microsoft.Shared.Samples;

namespace Providers;

/// <summary>
/// Shows how to use <see cref="AIAgent"/> with Azure AI Persistent Agents.
/// </summary>
/// <remarks>
/// Running "az login" command in terminal is required for authentication with Azure AI service.
/// </remarks>
public sealed class AIAgent_With_AzureAIAgentsPersistent(ITestOutputHelper output) : AgentSample(output)
{
private const string JokerName = "Joker";
private const string JokerInstructions = "You are good at telling jokes.";

[Fact]
public async Task GetWithAzureAIAgentsPersistent()
{
// Get a client to create server side agents with.
var persistentAgentsClient = new PersistentAgentsClient(TestConfiguration.AzureAI.Endpoint, new AzureCliCredential());

// Create a service side persistent agent.
var persistentAgent = await persistentAgentsClient.Administration.CreateAgentAsync(
model: TestConfiguration.AzureAI.DeploymentName!,
name: JokerName,
instructions: JokerInstructions);

// Get a server side agent.
AIAgent agent = await persistentAgentsClient.GetAIAgentAsync(persistentAgent.Value.Id);

// 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 run agent and display the conversation messages for the thread.
async Task RunAgentAsync(string input)
{
Console.WriteLine(input);

var response = await agent.RunAsync(input, thread);

Console.WriteLine(response);
}

// Cleanup
await persistentAgentsClient.Threads.DeleteThreadAsync(thread.Id);
await persistentAgentsClient.Administration.DeleteAgentAsync(agent.Id);
}

[Fact]
public async Task CreateWithAzureAIAgentsPersistent()
{
// Get a client to create server side agents with.
var persistentAgentsClient = new PersistentAgentsClient(TestConfiguration.AzureAI.Endpoint, new AzureCliCredential());

// Create a server side persistent agent.
AIAgent agent = await persistentAgentsClient.CreateAIAgentAsync(
model: TestConfiguration.AzureAI.DeploymentName!,
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 run agent and display the conversation messages for the thread.
async Task RunAgentAsync(string input)
{
Console.WriteLine(input);

var response = await agent.RunAsync(input, thread);

Console.WriteLine(response);
}

// Cleanup
await persistentAgentsClient.Threads.DeleteThreadAsync(thread.Id);
await persistentAgentsClient.Administration.DeleteAgentAsync(agent.Id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,31 @@
using System.ClientModel;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using Microsoft.Shared.Samples;
using OpenAI;

namespace Providers;

/// <summary>
/// End-to-end sample showing how to use <see cref="ChatClientAgent"/> with Azure OpenAI Chat Completion.
/// </summary>
public sealed class ChatClientAgent_With_AzureOpenAIChatCompletion(ITestOutputHelper output) : AgentSample(output)
public sealed class AIAgent_With_AzureOpenAIChatCompletion(ITestOutputHelper output) : AgentSample(output)
{
private const string JokerName = "Joker";
private const string JokerInstructions = "You are good at telling jokes.";

[Fact]
public async Task RunWithChatCompletion()
{
// Get the chat client to use for the agent.
using var chatClient = ((TestConfiguration.AzureOpenAI.ApiKey is null)
// Get the OpenAI client to use for the agent.
var openAIClient = (TestConfiguration.AzureOpenAI.ApiKey is null)
// Use Azure CLI credentials if API key is not provided.
? new AzureOpenAIClient(TestConfiguration.AzureOpenAI.Endpoint, new AzureCliCredential())
: new AzureOpenAIClient(TestConfiguration.AzureOpenAI.Endpoint, new ApiKeyCredential(TestConfiguration.AzureOpenAI.ApiKey)))
.GetChatClient(TestConfiguration.AzureOpenAI.DeploymentName)
.AsIChatClient();
: new AzureOpenAIClient(TestConfiguration.AzureOpenAI.Endpoint, new ApiKeyCredential(TestConfiguration.AzureOpenAI.ApiKey));

// Define the agent
ChatClientAgent agent = new(chatClient, JokerInstructions, JokerName);
// Create the agent
AIAgent agent = openAIClient.CreateChatClientAgent(TestConfiguration.AzureOpenAI.DeploymentName, JokerInstructions, JokerName);

// Start a new thread for the agent conversation.
AgentThread thread = agent.GetNewThread();
Expand Down
Loading
Loading