test
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
Python - Merge - Tests / paths-filter (push) Has been cancelled
Python - Merge - Tests / Python Tests - Core (integration, ubuntu-latest, 3.10) (push) Has been cancelled
Python - Merge - Tests / Python Tests - Azure AI (integration, ubuntu-latest, 3.10) (push) Has been cancelled
Python - Merge - Tests / python-integration-tests-check (push) Has been cancelled
Python - Lab Tests / paths-filter (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.10) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.11) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.12) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.13) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.14) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.10) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.11) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.12) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.13) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.14) (push) Has been cancelled
Check .md links / markdown-link-check (push) Has been cancelled
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
Python - Merge - Tests / paths-filter (push) Has been cancelled
Python - Merge - Tests / Python Tests - Core (integration, ubuntu-latest, 3.10) (push) Has been cancelled
Python - Merge - Tests / Python Tests - Azure AI (integration, ubuntu-latest, 3.10) (push) Has been cancelled
Python - Merge - Tests / python-integration-tests-check (push) Has been cancelled
Python - Lab Tests / paths-filter (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.10) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.11) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.12) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.13) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (ubuntu-latest, 3.14) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.10) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.11) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.12) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.13) (push) Has been cancelled
Python - Lab Tests / Python Lab Tests (windows-latest, 3.14) (push) Has been cancelled
Check .md links / markdown-link-check (push) Has been cancelled
This commit is contained in:
36
dotnet/samples/M365Agent/Agents/AdaptiveCardAIContent.cs
Normal file
36
dotnet/samples/M365Agent/Agents/AdaptiveCardAIContent.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using AdaptiveCards;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
namespace M365Agent.Agents;
|
||||
|
||||
/// <summary>
|
||||
/// An <see cref="AIContent"/> type allows an <see cref="AIAgent"/> to return adaptive cards as part of its response messages.
|
||||
/// </summary>
|
||||
internal sealed class AdaptiveCardAIContent : AIContent
|
||||
{
|
||||
public AdaptiveCardAIContent(AdaptiveCard adaptiveCard)
|
||||
{
|
||||
this.AdaptiveCard = adaptiveCard ?? throw new ArgumentNullException(nameof(adaptiveCard));
|
||||
}
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
[JsonConstructor]
|
||||
public AdaptiveCardAIContent(string adaptiveCardJson)
|
||||
{
|
||||
this.AdaptiveCardJson = adaptiveCardJson;
|
||||
}
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
|
||||
[JsonIgnore]
|
||||
public AdaptiveCard AdaptiveCard { get; private set; }
|
||||
|
||||
public string AdaptiveCardJson
|
||||
{
|
||||
get => this.AdaptiveCard.ToJson();
|
||||
set => this.AdaptiveCard = AdaptiveCard.FromJson(value).Card;
|
||||
}
|
||||
}
|
||||
115
dotnet/samples/M365Agent/Agents/WeatherForecastAgent.cs
Normal file
115
dotnet/samples/M365Agent/Agents/WeatherForecastAgent.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Text.Json;
|
||||
using AdaptiveCards;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
namespace M365Agent.Agents;
|
||||
|
||||
/// <summary>
|
||||
/// A weather forecasting agent. This agent wraps a <see cref="ChatClientAgent"/> and adds custom logic
|
||||
/// to generate adaptive cards for weather forecasts and add these to the agent's response.
|
||||
/// </summary>
|
||||
public class WeatherForecastAgent : DelegatingAIAgent
|
||||
{
|
||||
private const string AgentName = "WeatherForecastAgent";
|
||||
private const string AgentInstructions = """
|
||||
You are a friendly assistant that helps people find a weather forecast for a given location.
|
||||
You may ask follow up questions until you have enough information to answer the customers question.
|
||||
When answering with a weather forecast, fill out the weatherCard property with an adaptive card containing the weather information and
|
||||
add some emojis to indicate the type of weather.
|
||||
When answering with just text, fill out the context property with a friendly response.
|
||||
""";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WeatherForecastAgent"/> class.
|
||||
/// </summary>
|
||||
/// <param name="chatClient">An instance of <see cref="IChatClient"/> for interacting with an LLM.</param>
|
||||
public WeatherForecastAgent(IChatClient chatClient)
|
||||
: base(new ChatClientAgent(
|
||||
chatClient: chatClient,
|
||||
new ChatClientAgentOptions()
|
||||
{
|
||||
Name = AgentName,
|
||||
ChatOptions = new ChatOptions()
|
||||
{
|
||||
Instructions = AgentInstructions,
|
||||
Tools = [new ApprovalRequiredAIFunction(AIFunctionFactory.Create(GetWeather))],
|
||||
// We want the agent to return structured output in a known format
|
||||
// so that we can easily create adaptive cards from the response.
|
||||
ResponseFormat = ChatResponseFormat.ForJsonSchema(
|
||||
schema: AIJsonUtilities.CreateJsonSchema(typeof(WeatherForecastAgentResponse)),
|
||||
schemaName: "WeatherForecastAgentResponse",
|
||||
schemaDescription: "Response to a query about the weather in a specified location"),
|
||||
}
|
||||
}))
|
||||
{
|
||||
}
|
||||
|
||||
protected override async Task<AgentResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await base.RunCoreAsync(messages, thread, options, cancellationToken);
|
||||
|
||||
// If the agent returned a valid structured output response
|
||||
// we might be able to enhance the response with an adaptive card.
|
||||
if (response.TryDeserialize<WeatherForecastAgentResponse>(JsonSerializerOptions.Web, out var structuredOutput))
|
||||
{
|
||||
var textContentMessage = response.Messages.FirstOrDefault(x => x.Contents.OfType<TextContent>().Any());
|
||||
if (textContentMessage is not null)
|
||||
{
|
||||
// If the response contains weather information, create an adaptive card.
|
||||
if (structuredOutput.ContentType == WeatherForecastAgentResponseContentType.WeatherForecastAgentResponse)
|
||||
{
|
||||
var card = CreateWeatherCard(structuredOutput.Location, structuredOutput.MeteorologicalCondition, structuredOutput.TemperatureInCelsius);
|
||||
textContentMessage.Contents.Add(new AdaptiveCardAIContent(card));
|
||||
}
|
||||
|
||||
// If the response is just text, replace the structured output with the text response.
|
||||
if (structuredOutput.ContentType == WeatherForecastAgentResponseContentType.OtherAgentResponse)
|
||||
{
|
||||
var textContent = textContentMessage.Contents.OfType<TextContent>().First();
|
||||
textContent.Text = structuredOutput.OtherResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A mock weather tool, to get weather information for a given location.
|
||||
/// </summary>
|
||||
[Description("Get the weather for a given location.")]
|
||||
private 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.";
|
||||
|
||||
/// <summary>
|
||||
/// Create an adaptive card to display weather information.
|
||||
/// </summary>
|
||||
private static AdaptiveCard CreateWeatherCard(string? location, string? condition, string? temperature)
|
||||
{
|
||||
var card = new AdaptiveCard("1.5");
|
||||
card.Body.Add(new AdaptiveTextBlock
|
||||
{
|
||||
Text = "🌤️ Weather Forecast 🌤️",
|
||||
Size = AdaptiveTextSize.Large,
|
||||
Weight = AdaptiveTextWeight.Bolder,
|
||||
HorizontalAlignment = AdaptiveHorizontalAlignment.Center
|
||||
});
|
||||
card.Body.Add(new AdaptiveTextBlock
|
||||
{
|
||||
Text = "Location: " + location,
|
||||
});
|
||||
card.Body.Add(new AdaptiveTextBlock
|
||||
{
|
||||
Text = "Condition: " + condition,
|
||||
});
|
||||
card.Body.Add(new AdaptiveTextBlock
|
||||
{
|
||||
Text = "Temperature: " + temperature,
|
||||
});
|
||||
return card;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace M365Agent.Agents;
|
||||
|
||||
/// <summary>
|
||||
/// The structured output type for the <see cref="WeatherForecastAgent"/>.
|
||||
/// </summary>
|
||||
internal sealed class WeatherForecastAgentResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// A value indicating whether the response contains a weather forecast or some other type of response.
|
||||
/// </summary>
|
||||
[JsonPropertyName("contentType")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public WeatherForecastAgentResponseContentType ContentType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the agent could not provide a weather forecast this should contain a textual response.
|
||||
/// </summary>
|
||||
[Description("If the answer is other agent response, contains the textual agent response.")]
|
||||
[JsonPropertyName("otherResponse")]
|
||||
public string? OtherResponse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The location for which the weather forecast is given.
|
||||
/// </summary>
|
||||
[Description("If the answer is a weather forecast, contains the location for which the forecast is given.")]
|
||||
[JsonPropertyName("location")]
|
||||
public string? Location { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The temperature in Celsius for the given location.
|
||||
/// </summary>
|
||||
[Description("If the answer is a weather forecast, contains the temperature in Celsius.")]
|
||||
[JsonPropertyName("temperatureInCelsius")]
|
||||
public string? TemperatureInCelsius { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The meteorological condition for the given location.
|
||||
/// </summary>
|
||||
[Description("If the answer is a weather forecast, contains the meteorological condition (e.g., Sunny, Rainy).")]
|
||||
[JsonPropertyName("meteorologicalCondition")]
|
||||
public string? MeteorologicalCondition { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace M365Agent.Agents;
|
||||
|
||||
/// <summary>
|
||||
/// The type of content contained in a <see cref="WeatherForecastAgentResponse"/>.
|
||||
/// </summary>
|
||||
internal enum WeatherForecastAgentResponseContentType
|
||||
{
|
||||
[JsonPropertyName("otherAgentResponse")]
|
||||
OtherAgentResponse,
|
||||
|
||||
[JsonPropertyName("weatherForecastAgentResponse")]
|
||||
WeatherForecastAgentResponse
|
||||
}
|
||||
Reference in New Issue
Block a user