Skip to content

Commit

Permalink
Merge branch 'main' into @mramos/V8.1.3
Browse files Browse the repository at this point in the history
  • Loading branch information
MarioRamosEs committed Feb 13, 2024
2 parents f90a7d8 + 7c54496 commit 4fc92c3
Show file tree
Hide file tree
Showing 24 changed files with 343 additions and 41 deletions.
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,32 @@ Previous classification is not required if changes are simple or all belong to t
- Removed direct dependency on `IAsyncRepository<ChatMessageHistoryRecord>` in `ChatWithHistoryPlugin`, now relying on `IChatHistoryProvider` for chat history management.
- Added new calculation methods `LengthChatMessage` and `LengthChatMessageWithEncoding` in `ILengthFunctions` to determine the length of chat messages considering the author's role.

### Breaking Changes
- Removed `HistoryMaxMessages` property from `ChatWithHistoryPluginOptions` as part of a refactor to improve the configuration management of chat history. This property is now available within a new dedicated class `ChatHistoryProviderOptions`, which is designed to configure aspects of the `IChatHistoryProvider` implementation.
- The method `ImportChatWithHistoryPluginUsingCosmosDb` has been renamed to `ImportChatWithHistoryPlugin` to reflect its decoupling from the specific storage implementation and to align with the new `IChatHistoryProvider` abstraction. This change requires consumers to update their method calls to match the new signature, and to provide an instance of `IChatHistoryProvider` in the dependency container. You can use `AddCosmosChatHistoryProvider` to add an instance of `IChatHistoryProvider` that uses Azure Cosmos DB for storing chat histories.
- Modified the `ChatAsync` method signature in `ChatWithHistoryPlugin` by changing the order of parameters and making `userName` and `locale` optional. This change requires consumers to update their method calls to match the new signature.
- The `KernelExtensions.cs` and `ChatWithHistoryPluginOptions.cs` files in `Encamina.Enmarcha.SemanticKernel.Plugins.Chat` had been moved to a new location to better align with the project's structure.

### Major Changes
- Introduced `IChatHistoryProvider` interface and its corresponding implementation `ChatHistoryProvider`. This new abstraction layer provides a more flexible and decoupled way to work with chat history.
- Added a new extension method `AddCosmosChatHistoryProvider` to the service collection extensions. This method streamlines the setup and registration of `IChatHistoryProvider` that uses Azure Cosmos DB for storing chat histories.
- Removed direct dependency on `IAsyncRepository<ChatMessageHistoryRecord>` in `ChatWithHistoryPlugin`, now relying on `IChatHistoryProvider` for chat history management.
- Added new calculation methods `LengthChatMessage` and `LengthChatMessageWithEncoding` in `ILengthFunctions` to determine the length of chat messages considering the author's role.
- Updated dependencies:
- Updated `Azure.AI.OpenAI` from `1.0.0-beta12` to `1.0.0-beta13` (which provides some fixes for Function Calling).
- Updated `Azure.Data.Tables` from `12.8.2` to `12.8.3`.
- Updated `Microsoft.Bot.Builder.Azure` from `4.22.0` to `4.22.1`.
- Updated `Microsoft.Bot.Builder.Azure.Blobs` from `4.22.0` to `4.22.1`.
- Updated `Microsoft.Bot.Builder.Dialogs` from `4.22.0` to `4.22.1`.
- Updated `Microsoft.Bot.Builder.Integration.ApplicationInsights.Core` from `4.22.0` to `4.22.1`.
- Updated `MMicrosoft.Bot.Builder.Integration.AspNet.Core` from `4.22.0` to `4.22.1`.
- Updated `Microsoft.Semantic Kernel` from `1.3.0` to `1.3.1`.
- Updated `Microsoft.SemanticKernel.Connectors.AzureAISearch` from `1.3.0-alpha` to `1.3.1-alpha`. **Important**: this does not fix the issue detected by ENMARCHA and reported in [Issue 72](https://github.com/Encamina/enmarcha/issues/72).
- Updated `Microsoft.SemanticKernel.Connectors.Qdrant` from `1.3.0-alpha` to `1.3.1-alpha`.
- Updated `Microsoft.SemanticKernel.Plugins.Document` from `1.3.0-alpha` to `1.3.1-alpha`.
- Updated `Microsoft.SemanticKernel.Plugins.Memory` from `1.3.0-alpha` to `1.3.1-alpha`.
- Updated `SharpToken` from `1.2.14` to `1.2.15`.

### Minor Changes
- Added `Description` property in `VersionSwaggerGenOptions`.
- New text prompt function for extract KeyPhrases with specified locale, `KeyPhrasesLocaled`.
Expand All @@ -39,6 +65,11 @@ Previous classification is not required if changes are simple or all belong to t
- Bug fix: Temporary workaround for handling Http NotFound exception in `MemoryStoreExtender`. [(#72)](https://github.com/Encamina/enmarcha/issues/72)
- Added new method `ExistsMemoryAsync` in `MemoryStoreExtender`.
- Added a new optional parameter `Locale` to the functions of `QuestionAnsweringPlugin`, to specify the language of the response.
- Improved memory store event types, when they are raised and the data inside the arguments.
- Added new package `Encamina.Enmarcha.AspNet.OpenApi` with some goodies for OpenAPI. Currently, it adds the following:
- `GroupNameKeyAuthorizationMiddleware` a middleware that provides key authorization for OpenAPI specifications based on the group name of an API.
- `GroupNameKeyAuthenticationOptions` an options class to configure the `GroupNameKeyAuthorizationMiddleware`.
- Extensions method on `IApplicationBuilder` to add the `GroupNameKeyAuthorizationMiddleware`. For more information, refer to the package `README.md`.
- Adjusted package references in `Encamina.Enmarcha.SemanticKernel.csproj` to include `Encamina.Enmarcha.Data.Abstractions`.

## [8.1.2]
Expand Down
8 changes: 7 additions & 1 deletion Enmarcha.sln
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Encamina.Enmarcha.AI.Tests"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Encamina.Enmarcha.SemanticKernel.Tests", "tst\Encamina.Enmarcha.SemanticKernel.Tests\Encamina.Enmarcha.SemanticKernel.Tests.csproj", "{7B6F4DC4-74E2-4013-8DBA-12B7AAAD5278}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Encamina.Enmarcha.Data.AzureAISearch", "src\Encamina.Enmarcha.Data.AzureAISearch\Encamina.Enmarcha.Data.AzureAISearch.csproj", "{120ABEF3-3E36-434D-8EC7-E3B3F1817EAA}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Encamina.Enmarcha.Data.AzureAISearch", "src\Encamina.Enmarcha.Data.AzureAISearch\Encamina.Enmarcha.Data.AzureAISearch.csproj", "{120ABEF3-3E36-434D-8EC7-E3B3F1817EAA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Encamina.Enmarcha.AspNet.OpenApi", "src\Encamina.Enmarcha.AspNet.OpenApi\Encamina.Enmarcha.AspNet.OpenApi.csproj", "{0EFAA5CF-7106-40E0-A427-1CFBFFAEA3EC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -364,6 +366,10 @@ Global
{120ABEF3-3E36-434D-8EC7-E3B3F1817EAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{120ABEF3-3E36-434D-8EC7-E3B3F1817EAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{120ABEF3-3E36-434D-8EC7-E3B3F1817EAA}.Release|Any CPU.Build.0 = Release|Any CPU
{0EFAA5CF-7106-40E0-A427-1CFBFFAEA3EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0EFAA5CF-7106-40E0-A427-1CFBFFAEA3EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0EFAA5CF-7106-40E0-A427-1CFBFFAEA3EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0EFAA5CF-7106-40E0-A427-1CFBFFAEA3EC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Memory" Version="1.3.0-alpha" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Memory" Version="1.3.1-alpha" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" Version="1.0.0-beta.12" />
<PackageReference Include="Azure.AI.OpenAI" Version="1.0.0-beta.13" />
<PackageReference Include="Microsoft.Extensions.Azure" Version="1.7.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.1" />
Expand All @@ -24,7 +24,7 @@
</ItemGroup>

<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\"/>
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<ItemGroup>
<PackageReference Include="Azure.AI.Language.QuestionAnswering" Version="1.1.0" />
<PackageReference Include="Azure.Data.Tables" Version="12.8.2" />
<PackageReference Include="Azure.Data.Tables" Version="12.8.3" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
Expand All @@ -25,7 +25,7 @@
</ItemGroup>

<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\"/>
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</ItemGroup>

<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\"/>
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion src/Encamina.Enmarcha.AspNet.OpenApi.Swashbuckle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Nuget package](https://img.shields.io/nuget/v/Encamina.Enmarcha.AspNet.OpenApi.Swashbuckle)](https://www.nuget.org/packages/Encamina.Enmarcha.AspNet.OpenApi.Swashbuckle)

The Data Qdrant project contains functionalities related to the [OpenApi Swashbuckle](https://learn.microsoft.com/es-es/aspnet/core/tutorials/web-api-help-pages-using-swagger?view=aspnetcore-7.0)
This package provides extensions and filters for OpenAPI (Swagger) with version support using [Swashbuckle](https://learn.microsoft.com/es-es/aspnet/core/tutorials/web-api-help-pages-using-swagger?view=aspnetcore-8.0).

## Setup

Expand Down
18 changes: 18 additions & 0 deletions src/Encamina.Enmarcha.AspNet.OpenApi/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Encamina.Enmarcha.AspNet.OpenApi;

/// <summary>
/// Constants used in the OpenAPI library.
/// </summary>
public static class Constants
{
/// <summary>
/// OpenAPI related constants.
/// </summary>
public static class OpenApi
{
/// <summary>
/// The OpenAPI key header.
/// </summary>
public static readonly string KeyHeader = @"x-openapi-key";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<OutputType>Library</OutputType>
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
<IsPackable>true</IsPackable>
</PropertyGroup>

<PropertyGroup>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>

<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Encamina.Enmarcha.AspNet.OpenApi.Middlewares;

using Microsoft.Extensions.Options;

namespace Encamina.Enmarcha.AspNet.OpenApi.Extensions;

/// <summary>
/// Extension methods for <see cref="IApplicationBuilder"/>.
/// </summary>
public static class IApplicationBuilderExtensions
{
/// <summary>
/// Use the OpenAPI group name key authorization middleware with a given configuration.
/// </summary>
/// <param name="app">A valid instance of <see cref="IApplicationBuilder"/> as the application's request pipeline builder.</param>
/// <param name="setupAction">An optional setup action for the <see cref="GroupNameKeyAuthenticationOptions"/>.</param>
/// <returns>The <see cref="IApplicationBuilder"/> so that additional calls can be chained.</returns>
public static IApplicationBuilder UseOpenApiGroupNameKeyAuthorization(this IApplicationBuilder app, Action<GroupNameKeyAuthenticationOptions> setupAction)
{
GroupNameKeyAuthenticationOptions options;

using (var scope = app.ApplicationServices.CreateScope())
{
options = scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<GroupNameKeyAuthenticationOptions>>().Value;

setupAction?.Invoke(options);
}

return app.UseOpenApiGroupNameKeyAuthorization(options);
}

/// <summary>
/// Use the OpenAPI group name key authorization middleware with options.
/// </summary>
/// <param name="app">A valid instance of <see cref="IApplicationBuilder"/> as the application's request pipeline builder.</param>
/// <param name="options">Option parameters for the group name key authorization middleware.</param>
/// <returns>The <see cref="IApplicationBuilder"/> so that additional calls can be chained.</returns>
public static IApplicationBuilder UseOpenApiGroupNameKeyAuthorization(this IApplicationBuilder app, GroupNameKeyAuthenticationOptions options)
{
return app.UseMiddleware<GroupNameKeyAuthorizationMiddleware>(Options.Create(options));
}

/// <summary>
/// Use the OpenAPI group name key authorization middleware.
/// </summary>
/// <param name="app">A valid instance of <see cref="IApplicationBuilder"/> as the application's request pipeline builder.</param>
/// <returns>The <see cref="IApplicationBuilder"/> so that additional calls can be chained.</returns>
public static IApplicationBuilder UseOpenApiGroupNameKeyAuthorization(this IApplicationBuilder app)
{
return app.UseMiddleware<GroupNameKeyAuthorizationMiddleware>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace Encamina.Enmarcha.AspNet.OpenApi.Middlewares;

/// <summary>
/// Option parameters for the group name key authorization middleware.
/// </summary>
public sealed class GroupNameKeyAuthenticationOptions
{
/// <summary>
/// Gets or sets a dictionary of keys indexed by group name.
/// </summary>
public IDictionary<string, string> GroupNameKeys { get; set; }

/// <summary>
/// Gets or sets the specification file name. By default, it is set to <c>swagger.json</c> because it is the most common OpenAPI implementation.
/// </summary>
public string SpecificationFileName { get; set; } = @"swagger.json";

/// <summary>
/// Gets or sets the specification path. By default, it is set to <c>/swagger</c> because it is the most common OpenAPI implementation.
/// </summary>
/// <remarks>It is very important that the value of this property starts with '<c>/</c>'.</remarks>
public string SpecificationPath { get; set; } = @"/swagger";

/// <summary>
/// Gets or sets a value indicating whether the middleware is enabled. By default, it is set to <c>true</c>.
/// </summary>
/// <remarks>This property would allow turning on/off the middleware for development or testing purposes.</remarks>
public bool IsEnabled { get; set; } = true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.Net;

using Microsoft.Extensions.Options;

namespace Encamina.Enmarcha.AspNet.OpenApi.Middlewares;

/// <summary>
/// A middleware that authorizes requests for specific OpenAPI specifications based on a key associated with a group name of an API.
/// </summary>
public class GroupNameKeyAuthorizationMiddleware
{
private readonly RequestDelegate next;
private readonly GroupNameKeyAuthenticationOptions options;
private readonly ILogger logger;

/// <summary>
/// Initializes a new instance of the <see cref="GroupNameKeyAuthorizationMiddleware"/> class.
/// </summary>
/// <param name="next">The delegate representing the remaining middleware in the request pipeline.</param>
/// <param name="options">Option parameters for the group name key authorization middleware.</param>
/// <param name="loggerFactory">A factory for <see cref="ILogger"/> instances.</param>
public GroupNameKeyAuthorizationMiddleware(RequestDelegate next, IOptions<GroupNameKeyAuthenticationOptions> options, ILoggerFactory loggerFactory)
{
this.next = next;
this.options = options.Value;

logger = loggerFactory.CreateLogger<GroupNameKeyAuthorizationMiddleware>();
}

/// <summary>
/// Executes the middleware.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> for the current request.</param>
/// <returns>A task that represents the execution of this middleware.</returns>
public async Task InvokeAsync(HttpContext context)
{
if (!options.IsEnabled)
{
logger.LogInformation(@"Swagger group name key authorization middleware is disabled!");
await next.Invoke(context).ConfigureAwait(false);
return;
}

var requestPathValue = context.Request.Path.Value;

if (requestPathValue == null || !requestPathValue.EndsWith(options.SpecificationFileName, StringComparison.OrdinalIgnoreCase))
{
await next.Invoke(context).ConfigureAwait(false);
return;
}

var groupNameKey = options.GroupNameKeys.FirstOrDefault(item => requestPathValue.StartsWith($@"{options.SpecificationPath}/{item.Key}", StringComparison.OrdinalIgnoreCase)).Value;

if (groupNameKey == null || (context.Request.Headers.TryGetValue(Constants.OpenApi.KeyHeader, out var apiKey) && apiKey.Equals(groupNameKey)))
{
await next.Invoke(context).ConfigureAwait(false);
return;
}

logger.LogInformation(@"Invalid or missing key for path {RequestPath}!", requestPathValue);

context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
}
}
66 changes: 66 additions & 0 deletions src/Encamina.Enmarcha.AspNet.OpenApi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# OpenApi

[![Nuget package](https://img.shields.io/nuget/v/Encamina.Enmarcha.AspNet.OpenApi)](https://www.nuget.org/packages/Encamina.Enmarcha.AspNet.OpenApi)

This package provides extensions and types to work with OpenAPI (a.k.a. Swagger).

## Setup

### Nuget package

First, [install NuGet](http://docs.nuget.org/docs/start-here/installing-nuget). Then, install [Encamina.Enmarcha.AspNet.OpenApi](https://www.nuget.org/packages/Encamina.Enmarcha.AspNet.OpenApi) from the package manager console:

PM> Install-Package Encamina.Enmarcha.AspNet.OpenApi

### .NET CLI:

First, [install .NET CLI](https://learn.microsoft.com/en-us/dotnet/core/tools/). Then, install [Encamina.Enmarcha.AspNet.OpenApi](https://www.nuget.org/packages/Encamina.Enmarcha.AspNet.OpenApi) from the .NET CLI:

dotnet add package Encamina.Enmarcha.AspNet.OpenApi

## How to use

### Middlewares

#### GroupNameKeyAuthorizationMiddleware

This middleware is used to block access to an OpenAPI document or specification by using a pre-shared key that must be provided in the request header per specification.

To configure, use the `GroupNameKeyAuthenticationOptions` class.

When requesting an OpenAPI specification, identified by its group name, the client must provide the pre-shared key in the request header. Otherwise, the request will fail with an `HTTP 401 UNAUTHORIZED` response.

### Extensions

#### IApplicationBuilderExtensions

The `IApplicationBuilderExtensions` is a static class that provides extension methods for `IApplicationBuilder`, usually to add and configure middlewares.

Using it is quite simple, just get an instance of an `IApplicationBuilder` and call any of the available extension methods.

```csharp

var builder = WebApplication.CreateBuilder(new WebApplicationOptions()
{
ContentRootPath = Directory.GetCurrentDirectory(),
});

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

app.UseSwaggerGroupNameKeyAuthorization(options =>
{
// Enable only if not in Development environment. Allow developers to test without keys...
options.IsEnabled = !builder.Environment.IsDevelopment();
});

// ...
```

Currently, available extension methods are:

- `UseSwaggerGroupNameKeyAuthorization(this IApplicationBuilder app, SwaggerGroupNameKeyAuthenticationOptions options)`: adds the `GroupNameKeyAuthorizationMiddleware` middleware using provided options.
- `UseSwaggerGroupNameKeyAuthorization(this IApplicationBuilder app, Action<SwaggerGroupNameKeyAuthenticationOptions>? setupAction = null)`: adds the `GroupNameKeyAuthorizationMiddleware` middleware configuring options inline.

**Important**: Make sure that `UseSwaggerGroupNameKeyAuthorization` is added before any `UseSwagger()`, `UseSwaggerUI()`, or any other OpenAPI implementation middleware call, so that authorization middleware is called before accessing the OpenAPI document.
Loading

0 comments on commit 4fc92c3

Please sign in to comment.