Integrating Logic App with Semantic Kernel: A Detailed Guide and Demo
Overview
Recently, my exploration of Semantic Kernel has also impressed me, particularly its robust integration with .NET applications and the flexibility to incorporate plugins, empowering agents to perform diverse tasks beyond simple Q&A interactions.
Value Proposition of this Article
The motivation behind this guide and accompanying demo application is to harness the combined potential of these two technologies. While building my own applications, I observed gaps in the currently available documented guidance —focusing more on the code aspect and offering less insights into Logic App integration. Successfully importing Logic App into your codebase requires careful consideration of additional factors, which this article aim to address here.
Furthermore, this article provides an end-to-end demo application can significantly expedite the adoption of Logic App + SK.
Sample application: LogicAppSK on GitHub
With this demo application, you can chat with your virtual agent, get the inventory information of the storage accounts and have the agent send that information as an email to the recipients.
Build your Logic App
In this demo application, I’ve built 2 sample workflows within the same LAS app. When we import Logic App into your code, we don’t have to import individual workflows; we only need to import the Logic App as a whole, and Semantic Kernel will help you decide which workflow it should call and what parameters it needs to pass along when calling the corresponding endpoints.
Sample workflow 1 – sending an email with a given recipient, title, and content.
Sample workflow 2 – list the current blob information in my storage account
Build the workflow
When constructing the workflow, follow a similar thought process as when using Logic App to build a REST endpoint. This involves creating an HTTP trigger with an appropriate payload schema, defining actions in the middle, and concluding the workflow with a proper response.
The final step is sometimes overlooked when constructing your Logic App, often for the sake of task completion (a mistake I initially made). Without a “response” action, SK can still trigger the workflow and execute the task. However, it will throw a “Function failed: no media type available” error after execution. This issue troubled me because it gave the impression that the workflow did not execute successfully. Ultimately, adding a proper response action at the end of the workflow resolves this error message.
Test the workflow
When testing the workflow within Azure portal, it is straightforward. When you trigger the workflow, it uses the default auto-generated endpoint. The generated endpoint already has SAS token in it as it’s the default authentication method in Logic App Http trigger workflow, with this format:
https://<request-endpoint-URI>sp=<permissions>sv=<SAS-version>sig=<signature>
As suggested by our Logic App documentation, to secure the connection between your application and Logic App, it is recommended to enable Easy Auth on your Logic App. Afterward, you would typically want to test the endpoint using tools like Postman to validate the authentication configuration.
However, when attempting to use the auto-generated URL mentioned above in Postman, it will fail. The reason is that “Inbound calls to a request endpoint can use only one authorization scheme, either SAS or OAuth with Microsoft Entra ID. Although using one scheme doesn’t disable the other scheme, using both schemes at the same time causes an error because the service doesn’t know which scheme to choose.” (Source: Microsoft Azure Logic Apps Documentation)
To enable Easy Auth on your Logic App, follow the configuration steps below. This setup is another common area where customers may encounter mistakes that impact authentication settings, prompting me to share it here.
To test the Logic App workflow with Easy Auth enabled, change the url from:
https://<request-endpoint-URI>sp=<permissions>sv=<SAS-version>sig=<signature>
To
and pass your generated access token, you will then be able to test the endpoint with Entra ID authentication in Postman
Build your simple console application with SK
A sample application has shared in the Github repository.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.Plugins.Web;
using Microsoft.SemanticKernel.Plugins.OpenApi;
using System.Net.Http.Headers;
using static System.Environment;
using Microsoft.Identity.Client;
var builder = Kernel.CreateBuilder();
// // Add logging
// builder.Services.AddLogging(b => b.AddConsole().SetMinimumLevel(LogLevel.Error));
//Add Permission Filter
#pragma warning disable SKEXP0001
builder.Services.AddSingleton<IFunctionInvocationFilter, PermissionFilter>();
string model = GetEnvironmentVariable(“model”);
string endpoint = GetEnvironmentVariable(“endpoint”);
string key = GetEnvironmentVariable(“key”);
builder.Services.AddAzureOpenAIChatCompletion(
model,
endpoint,
key
);
var kernel = builder.Build();
string ClientId = “[AAD_CLIENT_ID]”;
string TenantId = “[TENANT_ID]”;
string Authority = $”https://login.microsoftonline.com/{TenantId}”;
string[] Scopes = new string[] { “api://[AAD_CIENT_ID]/SKLogicApp” };
var app = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority(Authority)
.WithDefaultRedirectUri() // Uses http://localhost for a console app
.Build();
AuthenticationResult authResult = null;
try
{
authResult = await app.AcquireTokenInteractive(Scopes).ExecuteAsync();
}
catch (MsalException ex)
{
Console.WriteLine(“An error occurred acquiring the token: ” + ex.Message);
}
//import Logic App as a function
#pragma warning disable SKEXP0040
await kernel.ImportPluginFromOpenApiAsync(
pluginName: “openapi_plugin”,
uri: new Uri(“https://mylogicapp-ai.azurewebsites.net/swagger.json”),
executionParameters: new OpenApiFunctionExecutionParameters()
{
HttpClient = new HttpClient()
{
DefaultRequestHeaders =
{
Authorization = new AuthenticationHeaderValue(“Bearer”, authResult.AccessToken)
}
}
//ServerUrlOverride = new Uri(lightPluginEndpoint),
//EnablePayloadNamespacing = true
}
);
// Enable planning
//tell OpenAI it is ok to import the function
var settings = new OpenAIPromptExecutionSettings(){ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions};
//Get chat completion service
var chatService = kernel.GetRequiredService<IChatCompletionService>();
//Create chat history
ChatHistory chat = new();
ChatHistory chatMessages = new ChatHistory(“””
You are a friendly assistant who likes to follow the rules. You will complete required steps
and request approval before taking any consequential actions. If the user doesn’t provide
enough information for you to complete a task, you will keep asking questions until you have
enough information to complete the task.
“””);
while (true){
Console.Write(“Q:”);
chat.AddUserMessage(Console.ReadLine());
//add the kernel and settings to the chat service
var r = await chatService.GetChatMessageContentAsync(chat, settings, kernel);
Console.WriteLine(“A:” + r);
chat.Add(r); // add response to chat history
}
#pragma warning disable SKEXP0001
class PermissionFilter : IFunctionInvocationFilter
{
public async Task OnFunctionInvocationAsync(FunctionInvocationContext context, Func<FunctionInvocationContext, Task> next)
{
Console.WriteLine($”Allow {context.Function.Name} to be invoked? If so, answer with ‘y'”);
if (Console.ReadLine() == “y”)
{
// Perform some actions before function invocation
await next(context);
}
else{
throw new Exception(“Function invocation not allowed”);
}
}
}
In this sample application, we have developed a console chat application capable of answering questions, remembering chat history, and invoking external endpoints using Logic App as a plugin. It requests your permission before executing external functions.
Since the Logic App contains two workflows, you can instruct the chat application to complete tasks according to your instructions. It dynamically selects which workflow to execute based on your prompt and passes the necessary parameters. For instance, you can instruct it to first retrieve and list the latest blob content from your storage account, followed by sending that information to your inbox via email.
You can verify later that an email containing the necessary content has been delivered to your inbox.
Microsoft Tech Community – Latest Blogs –Read More