Skip to content

Commit

Permalink
Merge sc-agent-workflow-and-tools-options into sc-basic-models-and-en…
Browse files Browse the repository at this point in the history
…dpoints-ui
  • Loading branch information
Sensational-Code committed Dec 12, 2024
2 parents 03ef4b2 + ce6eaee commit e3031bb
Show file tree
Hide file tree
Showing 64 changed files with 1,890 additions and 616 deletions.
7 changes: 6 additions & 1 deletion docs/release-notes/breaking-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,23 @@ The following new App Configuration settings are required:
|`FoundationaLLM:APIEndpoints:LangChainAPI:Configuration:ExternalModules:Storage:AuthenticationType` | `-` | `-` |
|`FoundationaLLM:APIEndpoints:LangChainAPI:Configuration:ExternalModules:RootStorageContainer` | `-` | `-` |
|`FoundationaLLM:APIEndpoints:LangChainAPI:Configuration:ExternalModules:Modules` | `-` | `-` |
|`FoundationaLLM:APIEndpoints:LangChainAPI:Configuration:PollingIntervalSeconds` | `10` | The interval in seconds at which the LangChain API will be polled for status. |
|`FoundationaLLM:UserPortal:Configuration:ShowMessageRating` | `true` | If `true`, rating options on agent messages will appear. |
|`FoundationaLLM:UserPortal:Configuration:ShowLastConversationOnStartup` | `false` | If `true`, the last conversation will be displayed when the user logs in. Otherwise, a new conversation placeholder appears on page load. |
|`FoundationaLLM:UserPortal:Configuration:ShowMessageTokens` | `true` | If `true`, the number of consumed tokens on agent and user messages will appear. |
|`FoundationaLLM:UserPortal:Configuration:ShowViewPrompt` | `true` | If `true`, the "View Prompt" button on agent messages will appear. |
|`FoundationaLLM:Instance:EnableResourceProvidersCache` | `false` | If `true`, the caching of resource providers will be enabled. |

#### Agent Tool configuration changes

Agent tools are now an array of AgentTool objects rather than a dictionary.

When defining tools for an agent, each tool now requires a `package_name` property. This property is used to identify the package that contains the tool's implementation. If the tool is internal, the `package_name` should be set to `FoundationaLLM`, if the tool is external, the `package_name` should be set to the name of the external package.

#### Security-related changes

The **Authorization API** now requires the ability to write to the Key Vault account contained within the auth resource group. Currently, the Authorization APIs managed identity is assigned to the `Key Vault Secrets User` role on the Key Vault account. This role assignment must be updated to include the `Key Vault Secrets Officer` role in addition to the user role.

#### Renamed classes

The following classes have been renamed:
Expand All @@ -54,7 +60,6 @@ The `/instances/{instanceId}/sessions/{sessionId}/message/{id}/rate` endpoint ha
> [!NOTE]
> Please note that both properties are nullable. Set them to null to clear out the rating and comments.

## Starting with 0.8.4

### Configuration changes
Expand Down
1 change: 0 additions & 1 deletion src/dotnet/Agent/Agent.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

<ItemGroup>
<PackageReference Include="Azure.Storage.Blobs" Version="12.19.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
5 changes: 4 additions & 1 deletion src/dotnet/AzureOpenAI/AzureOpenAI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0-beta.1" />
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
</ItemGroup>

<ItemGroup>
Expand Down
12 changes: 11 additions & 1 deletion src/dotnet/Common/Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,13 @@
<PackageReference Include="Microsoft.DeepDev.TokenizerLib" Version="1.3.3" />
<PackageReference Include="Microsoft.Extensions.Azure" Version="1.7.2" />
<PackageReference Include="Microsoft.Graph" Version="5.48.0" />
<PackageReference Include="Microsoft.Identity.Web" Version="2.17.4" />
<PackageReference Include="Microsoft.Identity.Web" Version="3.5.0" />
<PackageReference Include="Mime-Detective" Version="24.7.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Asp.Versioning.Http" Version="8.1.0" />
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.4" />
<PackageReference Include="OpenTelemetry" Version="1.9.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.4.0" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
Expand All @@ -78,6 +79,10 @@
<LastGenOutput>AuthorizableActionNames.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
</None>
<None Update="Templates\TelemetryActivityNames.tt">
<LastGenOutput>TelemetryActivityNames.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
</None>
<None Update="Templates\AuthorizationKeyVaultSecretNames.tt">
<LastGenOutput>AuthorizationKeyVaultSecretNames.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
Expand Down Expand Up @@ -165,6 +170,11 @@
<AutoGen>True</AutoGen>
<DependentUpon>AuthorizableActionNames.tt</DependentUpon>
</Compile>
<Compile Update="Templates\TelemetryActivityNames.cs">
<DependentUpon>TelemetryActivityNames.tt</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Templates\AuthorizationKeyVaultSecretNames.cs">
<DependentUpon>AuthorizationKeyVaultSecretNames.tt</DependentUpon>
<DesignTime>True</DesignTime>
Expand Down
8 changes: 8 additions & 0 deletions src/dotnet/Common/Constants/Data/AppConfiguration.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@
"value": "",
"content_type": "",
"first_version": "0.8.0"
},
{
"name": "EnableResourceProvidersCache",
"description": "Enable caching for resource providers.",
"secret": "",
"value": "false",
"content_type": "",
"first_version": "0.9.1"
}
]
},
Expand Down
13 changes: 13 additions & 0 deletions src/dotnet/Common/Constants/Data/TelemetryActivities.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"telemetry_activity_source": "CoreAPI",
"telemetry_activities": [
{
"name": "AsyncCompletions_StartCompletionOperation"
},
{
"name": "Completions_GetCompletion"
}
]
}
]
33 changes: 33 additions & 0 deletions src/dotnet/Common/Constants/Telemetry/TelemetryActivityTagNames.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace FoundationaLLM.Common.Constants.Telemetry
{
/// <summary>
/// Provides the names of the tags used in telemetry activities.
/// </summary>
public static class TelemetryActivityTagNames
{
/// <summary>
/// The FoundationaLLM instance identifier tag.
/// </summary>
public const string InstanceId = "FoundationaLLM-InstanceId";

/// <summary>
/// The FoundationaLLM conversation identifier tag.
/// </summary>
public const string ConversationId = "FoundationaLLM-ConversationId";

/// <summary>
/// The FoundationaLLM operation identifier tag.
/// </summary>
public const string OperationId = "FoundationaLLM-OperationId";

/// <summary>
/// The FoundationaLLM user principal name tag.
/// </summary>
public const string UPN = "FoundationaLLM-UPN";

/// <summary>
/// The FoundationaLLM user identifier tag.
/// </summary>
public const string UserId = "FoundationaLLM-UserId";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using FoundationaLLM.Common.Models.ResourceProviders;

namespace FoundationaLLM.Common.Interfaces
{
/// <summary>
/// Provides the resource caching services used by FoundationaLLM resource providers.
/// </summary>
public interface IResourceProviderResourceCacheService
{
/// <summary>
/// Tries to get a resource value identified by a resource reference from the cache.
/// </summary>
/// <typeparam name="T">The type of resource value to be retrieved.</typeparam>
/// <param name="resourceReference">The <see cref="ResourceReference"/> used as a key in the cache.</param>
/// <param name="resourceValue">The resource value to be retrieved.</param>
/// <returns><see langword="true"/> is the resource value was found in the cache, <see langword="false"/> otherwise.</returns>
bool TryGetValue<T>(ResourceReference resourceReference, out T? resourceValue) where T: ResourceBase;

/// <summary>
/// Sets a resource value identified by a resource reference in the cache.
/// </summary>
/// <typeparam name="T">The type of resource value to be set.</typeparam>
/// <param name="resourceReference">The <see cref="ResourceReference"/> used as a key in the cache.</param>
/// <param name="resourceValue">The resource value to be set.</param>
void SetValue<T>(ResourceReference resourceReference, T resourceValue) where T : ResourceBase;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,10 @@ public class InstanceSettings
/// The Regex pattern used to validate the values allowed as User Principal Name (UPN) substitutes in the X-USER-IDENTITY header.
/// </summary>
public string? IdentitySubstitutionUserPrincipalNamePattern { get; set; }

/// <summary>
/// Enabling caching for resource providers.
/// </summary>
public bool EnableResourceProvidersCache { get; set; } = false;
}
}
70 changes: 50 additions & 20 deletions src/dotnet/Common/Services/DependencyInjection.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Azure.Monitor.OpenTelemetry.AspNetCore;
using Azure.Monitor.OpenTelemetry.Exporter;
using FoundationaLLM.Common.Authentication;
using FoundationaLLM.Common.Constants;
using FoundationaLLM.Common.Constants.Authorization;
using FoundationaLLM.Common.Constants.Configuration;
using FoundationaLLM.Common.Interfaces;
using FoundationaLLM.Common.Models.Configuration.CosmosDB;
Expand All @@ -9,21 +11,18 @@
using FoundationaLLM.Common.Services.Azure;
using FoundationaLLM.Common.Services.Security;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Azure.Cosmos.Fluent;
using Microsoft.Azure.Cosmos;
using Microsoft.AspNetCore.Identity;
using Microsoft.Azure.Cosmos.Fluent;
using Microsoft.Extensions.Azure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Identity.Web;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Authentication;
using FoundationaLLM.Common.Constants.Authorization;
using Microsoft.Graph.Models;
using System.Diagnostics;

namespace FoundationaLLM
{
Expand Down Expand Up @@ -60,23 +59,54 @@ public static void AddOpenTelemetry(this IHostApplicationBuilder builder,
string connectionStringConfigurationKey,
string serviceName)
{
// Add the OpenTelemetry telemetry service and send telemetry data to Azure Monitor.
builder.Services.AddOpenTelemetry().UseAzureMonitor(options =>
var resourceBuilder = ResourceBuilder
.CreateDefault()
.AddAttributes(new Dictionary<string, object>
{
{ "service.name", serviceName },
{ "service.namespace", "FoundationaLLM" },
{ "service.version", builder.Configuration[EnvironmentVariables.FoundationaLLM_Version]! },
{ "service.instance.id", ValidatedEnvironment.MachineName }
});


// Add the OpenTelemetry logging provider and send logs to Azure Monitor.
builder.Logging.AddOpenTelemetry(openTelemetryLoggerOptions =>
{
options.ConnectionString = builder.Configuration[connectionStringConfigurationKey];
openTelemetryLoggerOptions.SetResourceBuilder(resourceBuilder);
openTelemetryLoggerOptions.IncludeFormattedMessage = true;
openTelemetryLoggerOptions.IncludeScopes = true;
openTelemetryLoggerOptions.AddAzureMonitorLogExporter(azureMonitorOptions =>
{
azureMonitorOptions.ConnectionString = builder.Configuration[connectionStringConfigurationKey];
});
});

// Create a dictionary of resource attributes.
var resourceAttributes = new Dictionary<string, object> {
{ "service.name", serviceName },
{ "service.namespace", "FoundationaLLM" },
{ "service.instance.id", ValidatedEnvironment.MachineName }
};

// Configure the OpenTelemetry tracer provider to add the resource attributes to all traces.
builder.Services.ConfigureOpenTelemetryTracerProvider((sp, builder) =>
builder.ConfigureResource(resourceBuilder =>
resourceBuilder.AddAttributes(resourceAttributes)));
// Add the OpenTelemetry telemetry service and send telemetry data to Azure Monitor.
builder.Services.AddOpenTelemetry()
.WithTracing(traceProviderBuilder => traceProviderBuilder
.SetResourceBuilder(resourceBuilder)
.AddSource("Azure.*")
.AddSource(serviceName)
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation(httpOptions => httpOptions.FilterHttpRequestMessage = (_) =>
{
// Azure SDKs create their own client span before calling the service using HttpClient
// In this case, we would see two spans corresponding to the same operation
// 1) created by Azure SDK 2) created by HttpClient
// To prevent this duplication we are filtering the span from HttpClient
// as span from Azure SDK contains all relevant information needed.
var parentActivity = Activity.Current?.Parent;
if (parentActivity != null && parentActivity.Source.Name.Equals("Azure.Core.Http"))
{
return false;
}
return true;
})
.AddAzureMonitorTraceExporter(azureMonitorOptions =>
{
azureMonitorOptions.ConnectionString = builder.Configuration[connectionStringConfigurationKey];
}));
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using FoundationaLLM.Common.Interfaces;
using FoundationaLLM.Common.Models.ResourceProviders;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;

namespace FoundationaLLM.Common.Services.ResourceProviders
{
/// <summary>
/// Provides the resource caching services used by FoundationaLLM resource providers.
/// </summary>
/// <param name="logger">The <see cref="ILogger"/> used to log information.</param>
public class ResourceProviderResourceCacheService(
ILogger logger) : IResourceProviderResourceCacheService
{
private readonly ILogger _logger = logger;

private readonly IMemoryCache _cache = new MemoryCache(new MemoryCacheOptions
{
SizeLimit = 10000, // Limit cache size to 5000 resources.
ExpirationScanFrequency = TimeSpan.FromMinutes(5) // Scan for expired items every five minutes.
});
private readonly MemoryCacheEntryOptions _cacheEntryOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(60)) // Cache entries are valid for 60 minutes.
.SetSlidingExpiration(TimeSpan.FromMinutes(30)) // Reset expiration time if accessed within 5 minutes.
.SetSize(1); // Each cache entry is a single resource.

/// <inheritdoc/>
public void SetValue<T>(ResourceReference resourceReference, T resourceValue) where T : ResourceBase
{
try
{
_cache.Set<T>(GetCacheKey(resourceReference), resourceValue, _cacheEntryOptions);
_logger.LogInformation("The resource {ResourceName} of type {ResourceType} has been set in the cache.",
resourceReference.Name,
resourceReference.Type);
}
catch (Exception ex)
{
_logger.LogError(ex, "There was an error setting the resource {ResourceName} of type {ResourceType} in the cache.",
resourceReference.Name,
resourceReference.Type);
}
}

/// <inheritdoc/>
public bool TryGetValue<T>(ResourceReference resourceReference, out T? resourceValue) where T : ResourceBase
{
resourceValue = default;

try
{
if (_cache.TryGetValue<T>(GetCacheKey(resourceReference), out T? cachedValue)
&& cachedValue != null)
{
resourceValue = cachedValue;
_logger.LogInformation("The resource {ResourceName} of type {ResourceType} has been retrieved from the cache.",
resourceReference.Name,
resourceReference.Type);
return true;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "There was an error getting the resource {ResourceName} of type {ResourceType} from the cache.",
resourceReference.Name,
resourceReference.Type);
}

return false;
}

private string GetCacheKey(ResourceReference resourceReference) =>
$"{resourceReference.Type}|{resourceReference.Name}";
}
}
Loading

0 comments on commit e3031bb

Please sign in to comment.