diff --git a/CopilotChat.sln b/CopilotChat.sln index 3e3514688..e79eb97a4 100644 --- a/CopilotChat.sln +++ b/CopilotChat.sln @@ -11,9 +11,10 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatCopilotIntegrationTests", "integration-tests\ChatCopilotIntegrationTests.csproj", "{0CD2CD95-536B-455F-B74A-772A455FA607}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CopilotChatShared", "shared\CopilotChatShared.csproj", "{94F12185-FAF9-43E3-B153-28A1708AC918}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSearcher", "plugins\web-searcher\WebSearcher.csproj", "{F83C857D-3080-4DEA-B3D1-978E2BC64BFB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginShared", "plugins\shared\PluginShared.csproj", "{9D03913A-21FF-4D0A-9883-95C4B3D6F65A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PluginShared", "plugins\shared\PluginShared.csproj", "{9D03913A-21FF-4D0A-9883-95C4B3D6F65A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/memorypipeline/CopilotChatMemoryPipeline.csproj b/memorypipeline/CopilotChatMemoryPipeline.csproj index 3b68a3db6..df32f4c2b 100644 --- a/memorypipeline/CopilotChatMemoryPipeline.csproj +++ b/memorypipeline/CopilotChatMemoryPipeline.csproj @@ -15,8 +15,8 @@ - - + + diff --git a/memorypipeline/Program.cs b/memorypipeline/Program.cs index d8733290b..93157e315 100644 --- a/memorypipeline/Program.cs +++ b/memorypipeline/Program.cs @@ -6,8 +6,8 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.SemanticMemory; -using Microsoft.SemanticMemory.Diagnostics; +using Microsoft.KernelMemory; +using Microsoft.KernelMemory.Diagnostics; // ******************************************************** // ************** SETUP *********************************** @@ -15,8 +15,8 @@ var builder = WebApplication.CreateBuilder(); -ISemanticMemoryClient memory = - new MemoryClientBuilder(builder.Services) +IKernelMemory memory = + new KernelMemoryBuilder(builder.Services) .FromAppSettings() .WithCustomOcr(builder.Configuration) .Build(); diff --git a/memorypipeline/appsettings.json b/memorypipeline/appsettings.json index f189cd479..56de5071d 100644 --- a/memorypipeline/appsettings.json +++ b/memorypipeline/appsettings.json @@ -1,6 +1,6 @@ { // - // Semantic Memory configuration - https://github.com/microsoft/semantic-memory + // Kernel Memory configuration - https://github.com/microsoft/kernel-memory // - ContentStorageType is the storage configuration for memory transfer: "AzureBlobs" or "SimpleFileStorage" // - TextGeneratorType is the AI completion service configuration: "AzureOpenAIText" or "OpenAI" // - ImageOcrType is the image OCR configuration: "None" or "AzureFormRecognizer" or "Tesseract" @@ -8,7 +8,7 @@ // - Retrieval is the configuration section for memory retrieval. // - Services is the configuration sections for various memory settings. // - "SemanticMemory": { + "KernelMemory": { "ContentStorageType": "SimpleFileStorage", "TextGeneratorType": "AzureOpenAIText", "ImageOcrType": "None", diff --git a/plugins/web-searcher/PluginEndpoint.cs b/plugins/web-searcher/PluginEndpoint.cs index 1c976e064..ba8b8253f 100644 --- a/plugins/web-searcher/PluginEndpoint.cs +++ b/plugins/web-searcher/PluginEndpoint.cs @@ -122,7 +122,11 @@ public async Task WebSearch([HttpTrigger(AuthorizationLevel.Fu return await this.CreateBadRequestResponseAsync(req, "Invalid number of results."); } - var offset = queries.ContainsKey("Offset") ? int.Parse(queries["Offset"]) : 0; + int offset = 0; + if (queries.TryGetValue("Offset", out var offsetValue)) + { + int.TryParse(offsetValue, out offset); + } var site = queries.ContainsKey("Site") ? queries["Site"].ToString() : string.Empty; if (string.IsNullOrWhiteSpace(site)) diff --git a/plugins/web-searcher/local.settings.json b/plugins/web-searcher/local.settings.json index 4df4ec6a5..39aa5e185 100644 --- a/plugins/web-searcher/local.settings.json +++ b/plugins/web-searcher/local.settings.json @@ -7,7 +7,7 @@ "Host": { "CORS": "*" }, - "PluginConfig": { - "BingApiKey": "" - } + "PluginConfig": { + "BingApiKey": "" + } } \ No newline at end of file diff --git a/scripts/Configure.ps1 b/scripts/Configure.ps1 index 32080a1e9..47b1afe4e 100644 --- a/scripts/Configure.ps1 +++ b/scripts/Configure.ps1 @@ -141,7 +141,7 @@ $webapiProjectPath = Join-Path "$PSScriptRoot" '../webapi' Write-Host "Setting 'APIKey' user secret for $AIService..." if ($AIService -eq $varOpenAI) { - dotnet user-secrets set --project $webapiProjectPath SemanticMemory:Services:OpenAI:APIKey $ApiKey + dotnet user-secrets set --project $webapiProjectPath KernelMemory:Services:OpenAI:APIKey $ApiKey if ($LASTEXITCODE -ne 0) { exit(1) } $AIServiceOverrides = @{ OpenAI = @{ @@ -151,9 +151,9 @@ if ($AIService -eq $varOpenAI) { }; } else { - dotnet user-secrets set --project $webapiProjectPath SemanticMemory:Services:AzureOpenAIText:APIKey $ApiKey + dotnet user-secrets set --project $webapiProjectPath KernelMemory:Services:AzureOpenAIText:APIKey $ApiKey if ($LASTEXITCODE -ne 0) { exit(1) } - dotnet user-secrets set --project $webapiProjectPath SemanticMemory:Services:AzureOpenAIEmbedding:APIKey $ApiKey + dotnet user-secrets set --project $webapiProjectPath KernelMemory:Services:AzureOpenAIEmbedding:APIKey $ApiKey if ($LASTEXITCODE -ne 0) { exit(1) } $AIServiceOverrides = @{ AzureOpenAIText = @{ @@ -180,7 +180,7 @@ $appsettingsOverrides = @{ Planner = @{ Model = $PlannerModel }; - SemanticMemory = @{ + KernelMemory = @{ TextGeneratorType = $AIService; DataIngestion = @{ EmbeddingGeneratorTypes = @($AIService) diff --git a/scripts/configure.sh b/scripts/configure.sh index 8713f02b2..f88c23328 100755 --- a/scripts/configure.sh +++ b/scripts/configure.sh @@ -158,7 +158,7 @@ WEBAPI_PROJECT_PATH="${SCRIPT_DIRECTORY}/../webapi" echo "Setting 'APIKey' user secret for $AI_SERVICE..." if [ "$AI_SERVICE" = "$ENV_OPEN_AI" ]; then - dotnet user-secrets set --project $WEBAPI_PROJECT_PATH SemanticMemory:Services:OpenAI:APIKey $API_KEY + dotnet user-secrets set --project $WEBAPI_PROJECT_PATH KernelMemory:Services:OpenAI:APIKey $API_KEY if [ $? -ne 0 ]; then exit 1; fi AISERVICE_OVERRIDES="{ \"OpenAI\": @@ -168,9 +168,9 @@ if [ "$AI_SERVICE" = "$ENV_OPEN_AI" ]; then } }" else - dotnet user-secrets set --project $WEBAPI_PROJECT_PATH SemanticMemory:Services:AzureOpenAIText:APIKey $API_KEY + dotnet user-secrets set --project $WEBAPI_PROJECT_PATH KernelMemory:Services:AzureOpenAIText:APIKey $API_KEY if [ $? -ne 0 ]; then exit 1; fi - dotnet user-secrets set --project $WEBAPI_PROJECT_PATH SemanticMemory:Services:AzureOpenAIEmbedding:APIKey $API_KEY + dotnet user-secrets set --project $WEBAPI_PROJECT_PATH KernelMemory:Services:AzureOpenAIEmbedding:APIKey $API_KEY if [ $? -ne 0 ]; then exit 1; fi AISERVICE_OVERRIDES="{ \"AzureOpenAIText\": { @@ -197,7 +197,7 @@ APPSETTINGS_OVERRIDES="{ \"Planner\": { \"Model\": \"${PLANNER_MODEL}\" }, - \"SemanticMemory\": { + \"KernelMemory\": { \"TextGeneratorType\": \"${AI_SERVICE}\", \"DataIngestion\": { \"EmbeddingGeneratorTypes\": [\"${AI_SERVICE}\"] diff --git a/scripts/deploy/main.bicep b/scripts/deploy/main.bicep index 805a1bf4e..67d749f00 100644 --- a/scripts/deploy/main.bicep +++ b/scripts/deploy/main.bicep @@ -288,115 +288,115 @@ resource appServiceWebConfig 'Microsoft.Web/sites/config@2022-09-01' = { value: '~2' } { - name: 'SemanticMemory:ContentStorageType' + name: 'KernelMemory:ContentStorageType' value: 'AzureBlobs' } { - name: 'SemanticMemory:TextGeneratorType' + name: 'KernelMemory:TextGeneratorType' value: aiService } { - name: 'SemanticMemory:DataIngestion:OrchestrationType' + name: 'KernelMemory:DataIngestion:OrchestrationType' value: 'Distributed' } { - name: 'SemanticMemory:DataIngestion:DistributedOrchestration:QueueType' + name: 'KernelMemory:DataIngestion:DistributedOrchestration:QueueType' value: 'AzureQueue' } { - name: 'SemanticMemory:DataIngestion:EmbeddingGeneratorTypes:0' + name: 'KernelMemory:DataIngestion:EmbeddingGeneratorTypes:0' value: aiService } { - name: 'SemanticMemory:DataIngestion:VectorDbTypes:0' + name: 'KernelMemory:DataIngestion:VectorDbTypes:0' value: memoryStore } { - name: 'SemanticMemory:Retrieval:VectorDbType' + name: 'KernelMemory:Retrieval:VectorDbType' value: memoryStore } { - name: 'SemanticMemory:Retrieval:EmbeddingGeneratorType' + name: 'KernelMemory:Retrieval:EmbeddingGeneratorType' value: aiService } { - name: 'SemanticMemory:Services:AzureBlobs:Auth' + name: 'KernelMemory:Services:AzureBlobs:Auth' value: 'ConnectionString' } { - name: 'SemanticMemory:Services:AzureBlobs:ConnectionString' + name: 'KernelMemory:Services:AzureBlobs:ConnectionString' value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${storage.listKeys().keys[1].value}' } { - name: 'SemanticMemory:Services:AzureBlobs:Container' + name: 'KernelMemory:Services:AzureBlobs:Container' value: 'chatmemory' } { - name: 'SemanticMemory:Services:AzureQueue:Auth' + name: 'KernelMemory:Services:AzureQueue:Auth' value: 'ConnectionString' } { - name: 'SemanticMemory:Services:AzureQueue:ConnectionString' + name: 'KernelMemory:Services:AzureQueue:ConnectionString' value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${storage.listKeys().keys[1].value}' } { - name: 'SemanticMemory:Services:AzureCognitiveSearch:Auth' + name: 'KernelMemory:Services:AzureCognitiveSearch:Auth' value: 'ApiKey' } { - name: 'SemanticMemory:Services:AzureCognitiveSearch:Endpoint' + name: 'KernelMemory:Services:AzureCognitiveSearch:Endpoint' value: memoryStore == 'AzureCognitiveSearch' ? 'https://${azureCognitiveSearch.name}.search.windows.net' : '' } { - name: 'SemanticMemory:Services:AzureCognitiveSearch:APIKey' + name: 'KernelMemory:Services:AzureCognitiveSearch:APIKey' value: memoryStore == 'AzureCognitiveSearch' ? azureCognitiveSearch.listAdminKeys().primaryKey : '' } { - name: 'SemanticMemory:Services:Qdrant:Endpoint' + name: 'KernelMemory:Services:Qdrant:Endpoint' value: memoryStore == 'Qdrant' ? 'https://${appServiceQdrant.properties.defaultHostName}' : '' } { - name: 'SemanticMemory:Services:AzureOpenAIText:Auth' + name: 'KernelMemory:Services:AzureOpenAIText:Auth' value: 'ApiKey' } { - name: 'SemanticMemory:Services:AzureOpenAIText:Endpoint' + name: 'KernelMemory:Services:AzureOpenAIText:Endpoint' value: deployNewAzureOpenAI ? openAI.properties.endpoint : aiEndpoint } { - name: 'SemanticMemory:Services:AzureOpenAIText:APIKey' + name: 'KernelMemory:Services:AzureOpenAIText:APIKey' value: deployNewAzureOpenAI ? openAI.listKeys().key1 : aiApiKey } { - name: 'SemanticMemory:Services:AzureOpenAIText:Deployment' + name: 'KernelMemory:Services:AzureOpenAIText:Deployment' value: completionModel } { - name: 'SemanticMemory:Services:AzureOpenAIEmbedding:Auth' + name: 'KernelMemory:Services:AzureOpenAIEmbedding:Auth' value: 'ApiKey' } { - name: 'SemanticMemory:Services:AzureOpenAIEmbedding:Endpoint' + name: 'KernelMemory:Services:AzureOpenAIEmbedding:Endpoint' value: deployNewAzureOpenAI ? openAI.properties.endpoint : aiEndpoint } { - name: 'SemanticMemory:Services:AzureOpenAIEmbedding:APIKey' + name: 'KernelMemory:Services:AzureOpenAIEmbedding:APIKey' value: deployNewAzureOpenAI ? openAI.listKeys().key1 : aiApiKey } { - name: 'SemanticMemory:Services:AzureOpenAIEmbedding:Deployment' + name: 'KernelMemory:Services:AzureOpenAIEmbedding:Deployment' value: embeddingModel } { - name: 'SemanticMemory:Services:OpenAI:TextModel' + name: 'KernelMemory:Services:OpenAI:TextModel' value: completionModel } { - name: 'SemanticMemory:Services:OpenAI:EmbeddingModel' + name: 'KernelMemory:Services:OpenAI:EmbeddingModel' value: embeddingModel } { - name: 'SemanticMemory:Services:OpenAI:APIKey' + name: 'KernelMemory:Services:OpenAI:APIKey' value: aiApiKey } { @@ -467,131 +467,131 @@ resource appServiceMemoryPipelineConfig 'Microsoft.Web/sites/config@2022-09-01' vnetRouteAllEnabled: true appSettings: [ { - name: 'SemanticMemory:ContentStorageType' + name: 'KernelMemory:ContentStorageType' value: 'AzureBlobs' } { - name: 'SemanticMemory:TextGeneratorType' + name: 'KernelMemory:TextGeneratorType' value: aiService } { - name: 'SemanticMemory:ImageOcrType' + name: 'KernelMemory:ImageOcrType' value: 'AzureFormRecognizer' } { - name: 'SemanticMemory:DataIngestion:OrchestrationType' + name: 'KernelMemory:DataIngestion:OrchestrationType' value: 'Distributed' } { - name: 'SemanticMemory:DataIngestion:DistributedOrchestration:QueueType' + name: 'KernelMemory:DataIngestion:DistributedOrchestration:QueueType' value: 'AzureQueue' } { - name: 'SemanticMemory:DataIngestion:EmbeddingGeneratorTypes:0' + name: 'KernelMemory:DataIngestion:EmbeddingGeneratorTypes:0' value: aiService } { - name: 'SemanticMemory:DataIngestion:VectorDbTypes:0' + name: 'KernelMemory:DataIngestion:VectorDbTypes:0' value: memoryStore } { - name: 'SemanticMemory:Retrieval:VectorDbType' + name: 'KernelMemory:Retrieval:VectorDbType' value: memoryStore } { - name: 'SemanticMemory:Retrieval:EmbeddingGeneratorType' + name: 'KernelMemory:Retrieval:EmbeddingGeneratorType' value: aiService } { - name: 'SemanticMemory:Services:AzureBlobs:Auth' + name: 'KernelMemory:Services:AzureBlobs:Auth' value: 'ConnectionString' } { - name: 'SemanticMemory:Services:AzureBlobs:ConnectionString' + name: 'KernelMemory:Services:AzureBlobs:ConnectionString' value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${storage.listKeys().keys[1].value}' } { - name: 'SemanticMemory:Services:AzureBlobs:Container' + name: 'KernelMemory:Services:AzureBlobs:Container' value: 'chatmemory' } { - name: 'SemanticMemory:Services:AzureQueue:Auth' + name: 'KernelMemory:Services:AzureQueue:Auth' value: 'ConnectionString' } { - name: 'SemanticMemory:Services:AzureQueue:ConnectionString' + name: 'KernelMemory:Services:AzureQueue:ConnectionString' value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${storage.listKeys().keys[1].value}' } { - name: 'SemanticMemory:Services:AzureCognitiveSearch:Auth' + name: 'KernelMemory:Services:AzureCognitiveSearch:Auth' value: 'ApiKey' } { - name: 'SemanticMemory:Services:AzureCognitiveSearch:Endpoint' + name: 'KernelMemory:Services:AzureCognitiveSearch:Endpoint' value: memoryStore == 'AzureCognitiveSearch' ? 'https://${azureCognitiveSearch.name}.search.windows.net' : '' } { - name: 'SemanticMemory:Services:AzureCognitiveSearch:APIKey' + name: 'KernelMemory:Services:AzureCognitiveSearch:APIKey' value: memoryStore == 'AzureCognitiveSearch' ? azureCognitiveSearch.listAdminKeys().primaryKey : '' } { - name: 'SemanticMemory:Services:Qdrant:Endpoint' + name: 'KernelMemory:Services:Qdrant:Endpoint' value: memoryStore == 'Qdrant' ? 'https://${appServiceQdrant.properties.defaultHostName}' : '' } { - name: 'SemanticMemory:Services:AzureOpenAIText:Auth' + name: 'KernelMemory:Services:AzureOpenAIText:Auth' value: 'ApiKey' } { - name: 'SemanticMemory:Services:AzureOpenAIText:Endpoint' + name: 'KernelMemory:Services:AzureOpenAIText:Endpoint' value: deployNewAzureOpenAI ? openAI.properties.endpoint : aiEndpoint } { - name: 'SemanticMemory:Services:AzureOpenAIText:APIKey' + name: 'KernelMemory:Services:AzureOpenAIText:APIKey' value: deployNewAzureOpenAI ? openAI.listKeys().key1 : aiApiKey } { - name: 'SemanticMemory:Services:AzureOpenAIText:Deployment' + name: 'KernelMemory:Services:AzureOpenAIText:Deployment' value: completionModel } { - name: 'SemanticMemory:Services:AzureOpenAIEmbedding:Auth' + name: 'KernelMemory:Services:AzureOpenAIEmbedding:Auth' value: 'ApiKey' } { - name: 'SemanticMemory:Services:AzureOpenAIEmbedding:Endpoint' + name: 'KernelMemory:Services:AzureOpenAIEmbedding:Endpoint' value: deployNewAzureOpenAI ? openAI.properties.endpoint : aiEndpoint } { - name: 'SemanticMemory:Services:AzureOpenAIEmbedding:APIKey' + name: 'KernelMemory:Services:AzureOpenAIEmbedding:APIKey' value: deployNewAzureOpenAI ? openAI.listKeys().key1 : aiApiKey } { - name: 'SemanticMemory:Services:AzureOpenAIEmbedding:Deployment' + name: 'KernelMemory:Services:AzureOpenAIEmbedding:Deployment' value: embeddingModel } { - name: 'SemanticMemory:Services:AzureFormRecognizer:Auth' + name: 'KernelMemory:Services:AzureFormRecognizer:Auth' value: 'ApiKey' } { - name: 'SemanticMemory:Services:AzureFormRecognizer:Endpoint' + name: 'KernelMemory:Services:AzureFormRecognizer:Endpoint' value: ocrAccount.properties.endpoint } { - name: 'SemanticMemory:Services:AzureFormRecognizer:APIKey' + name: 'KernelMemory:Services:AzureFormRecognizer:APIKey' value: ocrAccount.listKeys().key1 } { - name: 'SemanticMemory:Services:OpenAI:TextModel' + name: 'KernelMemory:Services:OpenAI:TextModel' value: completionModel } { - name: 'SemanticMemory:Services:OpenAI:EmbeddingModel' + name: 'KernelMemory:Services:OpenAI:EmbeddingModel' value: embeddingModel } { - name: 'SemanticMemory:Services:OpenAI:APIKey' + name: 'KernelMemory:Services:OpenAI:APIKey' value: aiApiKey } { diff --git a/scripts/deploy/main.json b/scripts/deploy/main.json index ce90ff583..cd6f00a08 100644 --- a/scripts/deploy/main.json +++ b/scripts/deploy/main.json @@ -310,7 +310,7 @@ "use32BitWorkerProcess": false, "vnetRouteAllEnabled": true, "webSocketsEnabled": true, - "appSettings": "[concat(createArray(createObject('name', 'Authentication:Type', 'value', 'AzureAd'), createObject('name', 'Authentication:AzureAd:Instance', 'value', parameters('azureAdInstance')), createObject('name', 'Authentication:AzureAd:TenantId', 'value', parameters('azureAdTenantId')), createObject('name', 'Authentication:AzureAd:ClientId', 'value', parameters('webApiClientId')), createObject('name', 'Authentication:AzureAd:Scopes', 'value', 'access_as_user'), createObject('name', 'Planner:Model', 'value', parameters('plannerModel')), createObject('name', 'ChatStore:Type', 'value', if(parameters('deployCosmosDB'), 'cosmos', 'volatile')), createObject('name', 'ChatStore:Cosmos:Database', 'value', 'CopilotChat'), createObject('name', 'ChatStore:Cosmos:ChatSessionsContainer', 'value', 'chatsessions'), createObject('name', 'ChatStore:Cosmos:ChatMessagesContainer', 'value', 'chatmessages'), createObject('name', 'ChatStore:Cosmos:ChatMemorySourcesContainer', 'value', 'chatmemorysources'), createObject('name', 'ChatStore:Cosmos:ChatParticipantsContainer', 'value', 'chatparticipants'), createObject('name', 'ChatStore:Cosmos:ConnectionString', 'value', if(parameters('deployCosmosDB'), listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(format('cosmos-{0}', variables('uniqueName')))), '2023-04-15').connectionStrings[0].connectionString, '')), createObject('name', 'AzureSpeech:Region', 'value', parameters('location')), createObject('name', 'AzureSpeech:Key', 'value', if(parameters('deploySpeechServices'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('cog-speech-{0}', variables('uniqueName'))), '2022-12-01').key1, '')), createObject('name', 'AllowedOrigins', 'value', '[*]'), createObject('name', 'Kestrel:Endpoints:Https:Url', 'value', 'https://localhost:443'), createObject('name', 'Frontend:AadClientId', 'value', parameters('frontendClientId')), createObject('name', 'Logging:LogLevel:Default', 'value', 'Warning'), createObject('name', 'Logging:LogLevel:CopilotChat.WebApi', 'value', 'Warning'), createObject('name', 'Logging:LogLevel:Microsoft.SemanticKernel', 'value', 'Warning'), createObject('name', 'Logging:LogLevel:Microsoft.AspNetCore.Hosting', 'value', 'Warning'), createObject('name', 'Logging:LogLevel:Microsoft.Hosting.Lifetimel', 'value', 'Warning'), createObject('name', 'Logging:ApplicationInsights:LogLevel:Default', 'value', 'Warning'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', reference(resourceId('Microsoft.Insights/components', format('appins-{0}', variables('uniqueName'))), '2020-02-02').ConnectionString), createObject('name', 'ApplicationInsightsAgent_EXTENSION_VERSION', 'value', '~2'), createObject('name', 'SemanticMemory:ContentStorageType', 'value', 'AzureBlobs'), createObject('name', 'SemanticMemory:TextGeneratorType', 'value', parameters('aiService')), createObject('name', 'SemanticMemory:DataIngestion:OrchestrationType', 'value', 'Distributed'), createObject('name', 'SemanticMemory:DataIngestion:DistributedOrchestration:QueueType', 'value', 'AzureQueue'), createObject('name', 'SemanticMemory:DataIngestion:EmbeddingGeneratorTypes:0', 'value', parameters('aiService')), createObject('name', 'SemanticMemory:DataIngestion:VectorDbTypes:0', 'value', parameters('memoryStore')), createObject('name', 'SemanticMemory:Retrieval:VectorDbType', 'value', parameters('memoryStore')), createObject('name', 'SemanticMemory:Retrieval:EmbeddingGeneratorType', 'value', parameters('aiService')), createObject('name', 'SemanticMemory:Services:AzureBlobs:Auth', 'value', 'ConnectionString'), createObject('name', 'SemanticMemory:Services:AzureBlobs:ConnectionString', 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', format('st{0}', variables('rgIdHash')), listKeys(resourceId('Microsoft.Storage/storageAccounts', format('st{0}', variables('rgIdHash'))), '2022-09-01').keys[1].value)), createObject('name', 'SemanticMemory:Services:AzureBlobs:Container', 'value', 'chatmemory'), createObject('name', 'SemanticMemory:Services:AzureQueue:Auth', 'value', 'ConnectionString'), createObject('name', 'SemanticMemory:Services:AzureQueue:ConnectionString', 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', format('st{0}', variables('rgIdHash')), listKeys(resourceId('Microsoft.Storage/storageAccounts', format('st{0}', variables('rgIdHash'))), '2022-09-01').keys[1].value)), createObject('name', 'SemanticMemory:Services:AzureCognitiveSearch:Auth', 'value', 'ApiKey'), createObject('name', 'SemanticMemory:Services:AzureCognitiveSearch:Endpoint', 'value', if(equals(parameters('memoryStore'), 'AzureCognitiveSearch'), format('https://{0}.search.windows.net', format('acs-{0}', variables('uniqueName'))), '')), createObject('name', 'SemanticMemory:Services:AzureCognitiveSearch:APIKey', 'value', if(equals(parameters('memoryStore'), 'AzureCognitiveSearch'), listAdminKeys(resourceId('Microsoft.Search/searchServices', format('acs-{0}', variables('uniqueName'))), '2022-09-01').primaryKey, '')), createObject('name', 'SemanticMemory:Services:Qdrant:Endpoint', 'value', if(equals(parameters('memoryStore'), 'Qdrant'), format('https://{0}', reference(resourceId('Microsoft.Web/sites', format('app-{0}-qdrant', variables('uniqueName'))), '2022-09-01').defaultHostName), '')), createObject('name', 'SemanticMemory:Services:AzureOpenAIText:Auth', 'value', 'ApiKey'), createObject('name', 'SemanticMemory:Services:AzureOpenAIText:Endpoint', 'value', if(parameters('deployNewAzureOpenAI'), reference(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2023-05-01').endpoint, parameters('aiEndpoint'))), createObject('name', 'SemanticMemory:Services:AzureOpenAIText:APIKey', 'value', if(parameters('deployNewAzureOpenAI'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2023-05-01').key1, parameters('aiApiKey'))), createObject('name', 'SemanticMemory:Services:AzureOpenAIText:Deployment', 'value', parameters('completionModel')), createObject('name', 'SemanticMemory:Services:AzureOpenAIEmbedding:Auth', 'value', 'ApiKey'), createObject('name', 'SemanticMemory:Services:AzureOpenAIEmbedding:Endpoint', 'value', if(parameters('deployNewAzureOpenAI'), reference(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2023-05-01').endpoint, parameters('aiEndpoint'))), createObject('name', 'SemanticMemory:Services:AzureOpenAIEmbedding:APIKey', 'value', if(parameters('deployNewAzureOpenAI'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2023-05-01').key1, parameters('aiApiKey'))), createObject('name', 'SemanticMemory:Services:AzureOpenAIEmbedding:Deployment', 'value', parameters('embeddingModel')), createObject('name', 'SemanticMemory:Services:OpenAI:TextModel', 'value', parameters('completionModel')), createObject('name', 'SemanticMemory:Services:OpenAI:EmbeddingModel', 'value', parameters('embeddingModel')), createObject('name', 'SemanticMemory:Services:OpenAI:APIKey', 'value', parameters('aiApiKey')), createObject('name', 'Plugins:0:Name', 'value', 'Klarna Shopping'), createObject('name', 'Plugins:0:ManifestDomain', 'value', 'https://www.klarna.com')), if(parameters('deployWebSearcherPlugin'), createArray(createObject('name', 'Plugins:1:Name', 'value', 'WebSearcher'), createObject('name', 'Plugins:1:ManifestDomain', 'value', format('https://{0}', reference(resourceId('Microsoft.Web/sites', format('function-{0}-websearcher-plugin', variables('uniqueName'))), '2022-09-01').defaultHostName)), createObject('name', 'Plugins:1:Key', 'value', listkeys(format('{0}/host/default/', resourceId('Microsoft.Web/sites', format('function-{0}-websearcher-plugin', variables('uniqueName')))), '2022-09-01').functionKeys.default)), createArray()))]" + "appSettings": "[concat(createArray(createObject('name', 'Authentication:Type', 'value', 'AzureAd'), createObject('name', 'Authentication:AzureAd:Instance', 'value', parameters('azureAdInstance')), createObject('name', 'Authentication:AzureAd:TenantId', 'value', parameters('azureAdTenantId')), createObject('name', 'Authentication:AzureAd:ClientId', 'value', parameters('webApiClientId')), createObject('name', 'Authentication:AzureAd:Scopes', 'value', 'access_as_user'), createObject('name', 'Planner:Model', 'value', parameters('plannerModel')), createObject('name', 'ChatStore:Type', 'value', if(parameters('deployCosmosDB'), 'cosmos', 'volatile')), createObject('name', 'ChatStore:Cosmos:Database', 'value', 'CopilotChat'), createObject('name', 'ChatStore:Cosmos:ChatSessionsContainer', 'value', 'chatsessions'), createObject('name', 'ChatStore:Cosmos:ChatMessagesContainer', 'value', 'chatmessages'), createObject('name', 'ChatStore:Cosmos:ChatMemorySourcesContainer', 'value', 'chatmemorysources'), createObject('name', 'ChatStore:Cosmos:ChatParticipantsContainer', 'value', 'chatparticipants'), createObject('name', 'ChatStore:Cosmos:ConnectionString', 'value', if(parameters('deployCosmosDB'), listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(format('cosmos-{0}', variables('uniqueName')))), '2023-04-15').connectionStrings[0].connectionString, '')), createObject('name', 'AzureSpeech:Region', 'value', parameters('location')), createObject('name', 'AzureSpeech:Key', 'value', if(parameters('deploySpeechServices'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('cog-speech-{0}', variables('uniqueName'))), '2022-12-01').key1, '')), createObject('name', 'AllowedOrigins', 'value', '[*]'), createObject('name', 'Kestrel:Endpoints:Https:Url', 'value', 'https://localhost:443'), createObject('name', 'Frontend:AadClientId', 'value', parameters('frontendClientId')), createObject('name', 'Logging:LogLevel:Default', 'value', 'Warning'), createObject('name', 'Logging:LogLevel:CopilotChat.WebApi', 'value', 'Warning'), createObject('name', 'Logging:LogLevel:Microsoft.SemanticKernel', 'value', 'Warning'), createObject('name', 'Logging:LogLevel:Microsoft.AspNetCore.Hosting', 'value', 'Warning'), createObject('name', 'Logging:LogLevel:Microsoft.Hosting.Lifetimel', 'value', 'Warning'), createObject('name', 'Logging:ApplicationInsights:LogLevel:Default', 'value', 'Warning'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', reference(resourceId('Microsoft.Insights/components', format('appins-{0}', variables('uniqueName'))), '2020-02-02').ConnectionString), createObject('name', 'ApplicationInsightsAgent_EXTENSION_VERSION', 'value', '~2'), createObject('name', 'KernelMemory:ContentStorageType', 'value', 'AzureBlobs'), createObject('name', 'KernelMemory:TextGeneratorType', 'value', parameters('aiService')), createObject('name', 'KernelMemory:DataIngestion:OrchestrationType', 'value', 'Distributed'), createObject('name', 'KernelMemory:DataIngestion:DistributedOrchestration:QueueType', 'value', 'AzureQueue'), createObject('name', 'KernelMemory:DataIngestion:EmbeddingGeneratorTypes:0', 'value', parameters('aiService')), createObject('name', 'KernelMemory:DataIngestion:VectorDbTypes:0', 'value', parameters('memoryStore')), createObject('name', 'KernelMemory:Retrieval:VectorDbType', 'value', parameters('memoryStore')), createObject('name', 'KernelMemory:Retrieval:EmbeddingGeneratorType', 'value', parameters('aiService')), createObject('name', 'KernelMemory:Services:AzureBlobs:Auth', 'value', 'ConnectionString'), createObject('name', 'KernelMemory:Services:AzureBlobs:ConnectionString', 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', format('st{0}', variables('rgIdHash')), listKeys(resourceId('Microsoft.Storage/storageAccounts', format('st{0}', variables('rgIdHash'))), '2022-09-01').keys[1].value)), createObject('name', 'KernelMemory:Services:AzureBlobs:Container', 'value', 'chatmemory'), createObject('name', 'KernelMemory:Services:AzureQueue:Auth', 'value', 'ConnectionString'), createObject('name', 'KernelMemory:Services:AzureQueue:ConnectionString', 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', format('st{0}', variables('rgIdHash')), listKeys(resourceId('Microsoft.Storage/storageAccounts', format('st{0}', variables('rgIdHash'))), '2022-09-01').keys[1].value)), createObject('name', 'KernelMemory:Services:AzureCognitiveSearch:Auth', 'value', 'ApiKey'), createObject('name', 'KernelMemory:Services:AzureCognitiveSearch:Endpoint', 'value', if(equals(parameters('memoryStore'), 'AzureCognitiveSearch'), format('https://{0}.search.windows.net', format('acs-{0}', variables('uniqueName'))), '')), createObject('name', 'KernelMemory:Services:AzureCognitiveSearch:APIKey', 'value', if(equals(parameters('memoryStore'), 'AzureCognitiveSearch'), listAdminKeys(resourceId('Microsoft.Search/searchServices', format('acs-{0}', variables('uniqueName'))), '2022-09-01').primaryKey, '')), createObject('name', 'KernelMemory:Services:Qdrant:Endpoint', 'value', if(equals(parameters('memoryStore'), 'Qdrant'), format('https://{0}', reference(resourceId('Microsoft.Web/sites', format('app-{0}-qdrant', variables('uniqueName'))), '2022-09-01').defaultHostName), '')), createObject('name', 'KernelMemory:Services:AzureOpenAIText:Auth', 'value', 'ApiKey'), createObject('name', 'KernelMemory:Services:AzureOpenAIText:Endpoint', 'value', if(parameters('deployNewAzureOpenAI'), reference(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2023-05-01').endpoint, parameters('aiEndpoint'))), createObject('name', 'KernelMemory:Services:AzureOpenAIText:APIKey', 'value', if(parameters('deployNewAzureOpenAI'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2023-05-01').key1, parameters('aiApiKey'))), createObject('name', 'KernelMemory:Services:AzureOpenAIText:Deployment', 'value', parameters('completionModel')), createObject('name', 'KernelMemory:Services:AzureOpenAIEmbedding:Auth', 'value', 'ApiKey'), createObject('name', 'KernelMemory:Services:AzureOpenAIEmbedding:Endpoint', 'value', if(parameters('deployNewAzureOpenAI'), reference(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2023-05-01').endpoint, parameters('aiEndpoint'))), createObject('name', 'KernelMemory:Services:AzureOpenAIEmbedding:APIKey', 'value', if(parameters('deployNewAzureOpenAI'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2023-05-01').key1, parameters('aiApiKey'))), createObject('name', 'KernelMemory:Services:AzureOpenAIEmbedding:Deployment', 'value', parameters('embeddingModel')), createObject('name', 'KernelMemory:Services:OpenAI:TextModel', 'value', parameters('completionModel')), createObject('name', 'KernelMemory:Services:OpenAI:EmbeddingModel', 'value', parameters('embeddingModel')), createObject('name', 'KernelMemory:Services:OpenAI:APIKey', 'value', parameters('aiApiKey')), createObject('name', 'Plugins:0:Name', 'value', 'Klarna Shopping'), createObject('name', 'Plugins:0:ManifestDomain', 'value', 'https://www.klarna.com')), if(parameters('deployWebSearcherPlugin'), createArray(createObject('name', 'Plugins:1:Name', 'value', 'WebSearcher'), createObject('name', 'Plugins:1:ManifestDomain', 'value', format('https://{0}', reference(resourceId('Microsoft.Web/sites', format('function-{0}-websearcher-plugin', variables('uniqueName'))), '2022-09-01').defaultHostName)), createObject('name', 'Plugins:1:Key', 'value', listkeys(format('{0}/host/default/', resourceId('Microsoft.Web/sites', format('function-{0}-websearcher-plugin', variables('uniqueName')))), '2022-09-01').functionKeys.default)), createArray()))]" }, "dependsOn": [ "[resourceId('Microsoft.Insights/components', format('appins-{0}', variables('uniqueName')))]", @@ -373,131 +373,131 @@ "vnetRouteAllEnabled": true, "appSettings": [ { - "name": "SemanticMemory:ContentStorageType", + "name": "KernelMemory:ContentStorageType", "value": "AzureBlobs" }, { - "name": "SemanticMemory:TextGeneratorType", + "name": "KernelMemory:TextGeneratorType", "value": "[parameters('aiService')]" }, { - "name": "SemanticMemory:ImageOcrType", + "name": "KernelMemory:ImageOcrType", "value": "AzureFormRecognizer" }, { - "name": "SemanticMemory:DataIngestion:OrchestrationType", + "name": "KernelMemory:DataIngestion:OrchestrationType", "value": "Distributed" }, { - "name": "SemanticMemory:DataIngestion:DistributedOrchestration:QueueType", + "name": "KernelMemory:DataIngestion:DistributedOrchestration:QueueType", "value": "AzureQueue" }, { - "name": "SemanticMemory:DataIngestion:EmbeddingGeneratorTypes:0", + "name": "KernelMemory:DataIngestion:EmbeddingGeneratorTypes:0", "value": "[parameters('aiService')]" }, { - "name": "SemanticMemory:DataIngestion:VectorDbTypes:0", + "name": "KernelMemory:DataIngestion:VectorDbTypes:0", "value": "[parameters('memoryStore')]" }, { - "name": "SemanticMemory:Retrieval:VectorDbType", + "name": "KernelMemory:Retrieval:VectorDbType", "value": "[parameters('memoryStore')]" }, { - "name": "SemanticMemory:Retrieval:EmbeddingGeneratorType", + "name": "KernelMemory:Retrieval:EmbeddingGeneratorType", "value": "[parameters('aiService')]" }, { - "name": "SemanticMemory:Services:AzureBlobs:Auth", + "name": "KernelMemory:Services:AzureBlobs:Auth", "value": "ConnectionString" }, { - "name": "SemanticMemory:Services:AzureBlobs:ConnectionString", + "name": "KernelMemory:Services:AzureBlobs:ConnectionString", "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', format('st{0}', variables('rgIdHash')), listKeys(resourceId('Microsoft.Storage/storageAccounts', format('st{0}', variables('rgIdHash'))), '2022-09-01').keys[1].value)]" }, { - "name": "SemanticMemory:Services:AzureBlobs:Container", + "name": "KernelMemory:Services:AzureBlobs:Container", "value": "chatmemory" }, { - "name": "SemanticMemory:Services:AzureQueue:Auth", + "name": "KernelMemory:Services:AzureQueue:Auth", "value": "ConnectionString" }, { - "name": "SemanticMemory:Services:AzureQueue:ConnectionString", + "name": "KernelMemory:Services:AzureQueue:ConnectionString", "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', format('st{0}', variables('rgIdHash')), listKeys(resourceId('Microsoft.Storage/storageAccounts', format('st{0}', variables('rgIdHash'))), '2022-09-01').keys[1].value)]" }, { - "name": "SemanticMemory:Services:AzureCognitiveSearch:Auth", + "name": "KernelMemory:Services:AzureCognitiveSearch:Auth", "value": "ApiKey" }, { - "name": "SemanticMemory:Services:AzureCognitiveSearch:Endpoint", + "name": "KernelMemory:Services:AzureCognitiveSearch:Endpoint", "value": "[if(equals(parameters('memoryStore'), 'AzureCognitiveSearch'), format('https://{0}.search.windows.net', format('acs-{0}', variables('uniqueName'))), '')]" }, { - "name": "SemanticMemory:Services:AzureCognitiveSearch:APIKey", + "name": "KernelMemory:Services:AzureCognitiveSearch:APIKey", "value": "[if(equals(parameters('memoryStore'), 'AzureCognitiveSearch'), listAdminKeys(resourceId('Microsoft.Search/searchServices', format('acs-{0}', variables('uniqueName'))), '2022-09-01').primaryKey, '')]" }, { - "name": "SemanticMemory:Services:Qdrant:Endpoint", + "name": "KernelMemory:Services:Qdrant:Endpoint", "value": "[if(equals(parameters('memoryStore'), 'Qdrant'), format('https://{0}', reference(resourceId('Microsoft.Web/sites', format('app-{0}-qdrant', variables('uniqueName'))), '2022-09-01').defaultHostName), '')]" }, { - "name": "SemanticMemory:Services:AzureOpenAIText:Auth", + "name": "KernelMemory:Services:AzureOpenAIText:Auth", "value": "ApiKey" }, { - "name": "SemanticMemory:Services:AzureOpenAIText:Endpoint", + "name": "KernelMemory:Services:AzureOpenAIText:Endpoint", "value": "[if(parameters('deployNewAzureOpenAI'), reference(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2023-05-01').endpoint, parameters('aiEndpoint'))]" }, { - "name": "SemanticMemory:Services:AzureOpenAIText:APIKey", + "name": "KernelMemory:Services:AzureOpenAIText:APIKey", "value": "[if(parameters('deployNewAzureOpenAI'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2023-05-01').key1, parameters('aiApiKey'))]" }, { - "name": "SemanticMemory:Services:AzureOpenAIText:Deployment", + "name": "KernelMemory:Services:AzureOpenAIText:Deployment", "value": "[parameters('completionModel')]" }, { - "name": "SemanticMemory:Services:AzureOpenAIEmbedding:Auth", + "name": "KernelMemory:Services:AzureOpenAIEmbedding:Auth", "value": "ApiKey" }, { - "name": "SemanticMemory:Services:AzureOpenAIEmbedding:Endpoint", + "name": "KernelMemory:Services:AzureOpenAIEmbedding:Endpoint", "value": "[if(parameters('deployNewAzureOpenAI'), reference(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2023-05-01').endpoint, parameters('aiEndpoint'))]" }, { - "name": "SemanticMemory:Services:AzureOpenAIEmbedding:APIKey", + "name": "KernelMemory:Services:AzureOpenAIEmbedding:APIKey", "value": "[if(parameters('deployNewAzureOpenAI'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2023-05-01').key1, parameters('aiApiKey'))]" }, { - "name": "SemanticMemory:Services:AzureOpenAIEmbedding:Deployment", + "name": "KernelMemory:Services:AzureOpenAIEmbedding:Deployment", "value": "[parameters('embeddingModel')]" }, { - "name": "SemanticMemory:Services:AzureFormRecognizer:Auth", + "name": "KernelMemory:Services:AzureFormRecognizer:Auth", "value": "ApiKey" }, { - "name": "SemanticMemory:Services:AzureFormRecognizer:Endpoint", + "name": "KernelMemory:Services:AzureFormRecognizer:Endpoint", "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', format('cog-ocr-{0}', variables('uniqueName'))), '2022-12-01').endpoint]" }, { - "name": "SemanticMemory:Services:AzureFormRecognizer:APIKey", + "name": "KernelMemory:Services:AzureFormRecognizer:APIKey", "value": "[listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('cog-ocr-{0}', variables('uniqueName'))), '2022-12-01').key1]" }, { - "name": "SemanticMemory:Services:OpenAI:TextModel", + "name": "KernelMemory:Services:OpenAI:TextModel", "value": "[parameters('completionModel')]" }, { - "name": "SemanticMemory:Services:OpenAI:EmbeddingModel", + "name": "KernelMemory:Services:OpenAI:EmbeddingModel", "value": "[parameters('embeddingModel')]" }, { - "name": "SemanticMemory:Services:OpenAI:APIKey", + "name": "KernelMemory:Services:OpenAI:APIKey", "value": "[parameters('aiApiKey')]" }, { diff --git a/shared/CopilotChatShared.csproj b/shared/CopilotChatShared.csproj index 55699e9c3..7aeef31fa 100644 --- a/shared/CopilotChatShared.csproj +++ b/shared/CopilotChatShared.csproj @@ -9,7 +9,7 @@ - + diff --git a/shared/MemoryClientBuilderExtensions.cs b/shared/MemoryClientBuilderExtensions.cs index c2a24e004..48e695187 100644 --- a/shared/MemoryClientBuilderExtensions.cs +++ b/shared/MemoryClientBuilderExtensions.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using CopilotChat.Shared.Ocr; using Microsoft.Extensions.Configuration; -using Microsoft.SemanticMemory; +using Microsoft.KernelMemory; namespace CopilotChat.Shared; @@ -10,7 +10,7 @@ namespace CopilotChat.Shared; /// public static class MemoryClientBuilderExtensions { - public static MemoryClientBuilder WithCustomOcr(this MemoryClientBuilder builder, IConfiguration configuration) + public static KernelMemoryBuilder WithCustomOcr(this KernelMemoryBuilder builder, IConfiguration configuration) { var ocrEngine = configuration.CreateCustomOcr(); diff --git a/shared/MemoryConfiguration.cs b/shared/MemoryConfiguration.cs index 7ae0ccbe3..ebf598f41 100644 --- a/shared/MemoryConfiguration.cs +++ b/shared/MemoryConfiguration.cs @@ -6,7 +6,7 @@ namespace CopilotChat.Shared; /// public static class MemoryConfiguration { - public const string SemanticMemorySection = "SemanticMemory"; + public const string KernelMemorySection = "KernelMemory"; public const string ServicesSection = "Services"; public const string OrchestrationTypeDistributed = "Distributed"; public const string NoneType = "None"; diff --git a/shared/Ocr/ConfigurationExtensions.cs b/shared/Ocr/ConfigurationExtensions.cs index d093e65e9..05ccba85b 100644 --- a/shared/Ocr/ConfigurationExtensions.cs +++ b/shared/Ocr/ConfigurationExtensions.cs @@ -3,8 +3,8 @@ using System; using CopilotChat.Shared.Ocr.Tesseract; using Microsoft.Extensions.Configuration; -using Microsoft.SemanticMemory.Configuration; -using Microsoft.SemanticMemory.DataFormats.Image; +using Microsoft.KernelMemory.Configuration; +using Microsoft.KernelMemory.DataFormats.Image; namespace CopilotChat.Shared.Ocr; @@ -17,13 +17,13 @@ public static class ConfigurationExtensions public static IOcrEngine? CreateCustomOcr(this IConfiguration configuration) { - var ocrType = configuration.GetSection($"{MemoryConfiguration.SemanticMemorySection}:{ConfigOcrType}").Value ?? string.Empty; + var ocrType = configuration.GetSection($"{MemoryConfiguration.KernelMemorySection}:{ConfigOcrType}").Value ?? string.Empty; switch (ocrType) { case string x when x.Equals(TesseractOptions.SectionName, StringComparison.OrdinalIgnoreCase): var tesseractOptions = configuration - .GetSection($"{MemoryConfiguration.SemanticMemorySection}:{MemoryConfiguration.ServicesSection}:{TesseractOptions.SectionName}") + .GetSection($"{MemoryConfiguration.KernelMemorySection}:{MemoryConfiguration.ServicesSection}:{TesseractOptions.SectionName}") .Get(); if (tesseractOptions == null) diff --git a/shared/Ocr/Tesseract/TesseractOcrEngine.cs b/shared/Ocr/Tesseract/TesseractOcrEngine.cs index df6cb3874..5d9722292 100644 --- a/shared/Ocr/Tesseract/TesseractOcrEngine.cs +++ b/shared/Ocr/Tesseract/TesseractOcrEngine.cs @@ -3,7 +3,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -using Microsoft.SemanticMemory.DataFormats.Image; +using Microsoft.KernelMemory.DataFormats.Image; using Tesseract; namespace CopilotChat.Shared.Ocr.Tesseract; diff --git a/webapi/Controllers/ChatArchiveController.cs b/webapi/Controllers/ChatArchiveController.cs index 70579c1b0..ee2a57525 100644 --- a/webapi/Controllers/ChatArchiveController.cs +++ b/webapi/Controllers/ChatArchiveController.cs @@ -16,7 +16,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.SemanticMemory; +using Microsoft.KernelMemory; namespace CopilotChat.WebApi.Controllers; @@ -24,7 +24,7 @@ namespace CopilotChat.WebApi.Controllers; public class ChatArchiveController : ControllerBase { private readonly ILogger _logger; - private readonly ISemanticMemoryClient _memoryClient; + private readonly IKernelMemory _memoryClient; private readonly ChatSessionRepository _chatRepository; private readonly ChatMessageRepository _chatMessageRepository; private readonly ChatParticipantRepository _chatParticipantRepository; @@ -41,7 +41,7 @@ public class ChatArchiveController : ControllerBase /// The document memory options. /// The logger. public ChatArchiveController( - ISemanticMemoryClient memoryClient, + IKernelMemory memoryClient, ChatSessionRepository chatRepository, ChatMessageRepository chatMessageRepository, ChatParticipantRepository chatParticipantRepository, diff --git a/webapi/Controllers/ChatController.cs b/webapi/Controllers/ChatController.cs index 58851bec8..46ecdf0f2 100644 --- a/webapi/Controllers/ChatController.cs +++ b/webapi/Controllers/ChatController.cs @@ -28,13 +28,12 @@ using Microsoft.Graph; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Diagnostics; +using Microsoft.SemanticKernel.Functions.OpenAPI.Authentication; +using Microsoft.SemanticKernel.Functions.OpenAPI.Extensions; using Microsoft.SemanticKernel.Orchestration; -using Microsoft.SemanticKernel.SkillDefinition; -using Microsoft.SemanticKernel.Skills.MsGraph; -using Microsoft.SemanticKernel.Skills.MsGraph.Connectors; -using Microsoft.SemanticKernel.Skills.MsGraph.Connectors.Client; -using Microsoft.SemanticKernel.Skills.OpenAPI.Authentication; -using Microsoft.SemanticKernel.Skills.OpenAPI.Extensions; +using Microsoft.SemanticKernel.Plugins.MsGraph; +using Microsoft.SemanticKernel.Plugins.MsGraph.Connectors; +using Microsoft.SemanticKernel.Plugins.MsGraph.Connectors.Client; namespace CopilotChat.WebApi.Controllers; @@ -146,8 +145,6 @@ public async Task ProcessPlanAsync( return await this.HandleRequest(ProcessPlanFunctionName, kernel, messageRelayHubContext, planner, askConverter, chatSessionRepository, chatParticipantRepository, authInfo, ask, chatId.ToString()); } - #region Private Methods - /// /// Invokes given function of ChatSkill. /// @@ -179,8 +176,7 @@ private async Task HandleRequest( // Verify that the chat exists and that the user has access to it. ChatSession? chat = null; -#pragma warning disable CA1508 // Avoid dead conditional code. It's giving out false positives on chat == null. - if (!(await chatSessionRepository.TryFindByIdAsync(chatId, callback: c => chat = c)) || chat == null) + if (!(await chatSessionRepository.TryFindByIdAsync(chatId, callback: c => chat = c))) { return this.NotFound("Failed to find chat session for the chatId specified in variables."); } @@ -195,13 +191,13 @@ private async Task HandleRequest( await this.RegisterPlannerSkillsAsync(planner, openApiSkillsAuthHeaders, contextVariables); // Register hosted plugins that have been enabled - await this.RegisterPlannerHostedSkillsAsync(planner, chat.EnabledPlugins); + await this.RegisterPlannerHostedSkillsAsync(planner, chat!.EnabledPlugins); // Get the function to invoke ISKFunction? function = null; try { - function = kernel.Skills.GetFunction(ChatSkillName, functionName); + function = kernel.Functions.GetFunction(ChatSkillName, functionName); } catch (SKException ex) { @@ -210,7 +206,7 @@ private async Task HandleRequest( } // Run the function. - SKContext? result = null; + KernelResult? result = null; try { using CancellationTokenSource? cts = this._serviceOptions.TimeoutLimitInS is not null @@ -236,8 +232,8 @@ private async Task HandleRequest( AskResult chatSkillAskResult = new() { - Value = result.Result, - Variables = result.Variables.Select(v => new KeyValuePair(v.Key, v.Value)) + Value = result.GetValue() ?? string.Empty, + Variables = contextVariables.Select(v => new KeyValuePair(v.Key, v.Value)) }; // Broadcast AskResult to all users @@ -283,10 +279,10 @@ private async Task RegisterPlannerSkillsAsync(CopilotChatPlanner planner, Dictio { this._logger.LogInformation("Enabling GitHub plugin."); BearerAuthenticationProvider authenticationProvider = new(() => Task.FromResult(GithubAuthHeader)); - await planner.Kernel.ImportAIPluginAsync( - skillName: "GitHubPlugin", + await planner.Kernel.ImportPluginFunctionsAsync( + pluginName: "GitHubPlugin", filePath: Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "Skills", "OpenApiPlugins/GitHubPlugin/openapi.json"), - new OpenApiSkillExecutionParameters + new OpenApiFunctionExecutionParameters { AuthCallback = authenticationProvider.AuthenticateRequestAsync, }); @@ -299,10 +295,10 @@ await planner.Kernel.ImportAIPluginAsync( var authenticationProvider = new BasicAuthenticationProvider(() => { return Task.FromResult(JiraAuthHeader); }); var hasServerUrlOverride = variables.TryGetValue("jira-server-url", out string? serverUrlOverride); - await planner.Kernel.ImportAIPluginAsync( - skillName: "JiraPlugin", + await planner.Kernel.ImportPluginFunctionsAsync( + pluginName: "JiraPlugin", filePath: Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "Skills", "OpenApiPlugins/JiraPlugin/openapi.json"), - new OpenApiSkillExecutionParameters + new OpenApiFunctionExecutionParameters { AuthCallback = authenticationProvider.AuthenticateRequestAsync, ServerUrlOverride = hasServerUrlOverride ? new Uri(serverUrlOverride!) : null, @@ -316,9 +312,9 @@ await planner.Kernel.ImportAIPluginAsync( BearerAuthenticationProvider authenticationProvider = new(() => Task.FromResult(GraphAuthHeader)); GraphServiceClient graphServiceClient = this.CreateGraphServiceClient(authenticationProvider.AuthenticateRequestAsync); - planner.Kernel.ImportSkill(new TaskListSkill(new MicrosoftToDoConnector(graphServiceClient)), "todo"); - planner.Kernel.ImportSkill(new CalendarSkill(new OutlookCalendarConnector(graphServiceClient)), "calendar"); - planner.Kernel.ImportSkill(new EmailSkill(new OutlookMailConnector(graphServiceClient)), "email"); + planner.Kernel.ImportFunctions(new TaskListPlugin(new MicrosoftToDoConnector(graphServiceClient)), "todo"); + planner.Kernel.ImportFunctions(new CalendarPlugin(new OutlookCalendarConnector(graphServiceClient)), "calendar"); + planner.Kernel.ImportFunctions(new EmailPlugin(new OutlookMailConnector(graphServiceClient)), "email"); } if (variables.TryGetValue("customPlugins", out string? customPluginsString)) @@ -338,10 +334,10 @@ await planner.Kernel.ImportAIPluginAsync( var requiresAuth = !plugin.AuthType.Equals("none", StringComparison.OrdinalIgnoreCase); BearerAuthenticationProvider authenticationProvider = new(() => Task.FromResult(PluginAuthValue)); - await planner.Kernel.ImportAIPluginAsync( + await planner.Kernel.ImportPluginFunctionsAsync( $"{plugin.NameForModel}Plugin", PluginUtils.GetPluginManifestUri(plugin.ManifestDomain), - new OpenApiSkillExecutionParameters + new OpenApiFunctionExecutionParameters { HttpClient = this._httpClientFactory.CreateClient("Plugin"), IgnoreNonCompliantErrors = true, @@ -390,10 +386,10 @@ private async Task RegisterPlannerHostedSkillsAsync(CopilotChatPlanner planner, () => Task.FromResult(plugin.Key)); // Register the ChatGPT plugin with the planner's kernel. - await planner.Kernel.ImportAIPluginAsync( + await planner.Kernel.ImportPluginFunctionsAsync( PluginUtils.SanitizePluginName(plugin.Name), PluginUtils.GetPluginManifestUri(plugin.ManifestDomain), - new OpenApiSkillExecutionParameters + new OpenApiFunctionExecutionParameters { HttpClient = this._httpClientFactory.CreateClient("Plugin"), IgnoreNonCompliantErrors = true, @@ -408,8 +404,6 @@ await planner.Kernel.ImportAIPluginAsync( return; } - #endregion - /// /// Dispose of the object. /// diff --git a/webapi/Controllers/ChatHistoryController.cs b/webapi/Controllers/ChatHistoryController.cs index a506bb753..769db4321 100644 --- a/webapi/Controllers/ChatHistoryController.cs +++ b/webapi/Controllers/ChatHistoryController.cs @@ -20,7 +20,7 @@ using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.SemanticMemory; +using Microsoft.KernelMemory; namespace CopilotChat.WebApi.Controllers; @@ -37,7 +37,7 @@ public class ChatHistoryController : ControllerBase private const string GetChatRoute = "GetChatRoute"; private readonly ILogger _logger; - private readonly ISemanticMemoryClient _memoryClient; + private readonly IKernelMemory _memoryClient; private readonly ChatSessionRepository _sessionRepository; private readonly ChatMessageRepository _messageRepository; private readonly ChatParticipantRepository _participantRepository; @@ -58,7 +58,7 @@ public class ChatHistoryController : ControllerBase /// The auth info for the current request. public ChatHistoryController( ILogger logger, - ISemanticMemoryClient memoryClient, + IKernelMemory memoryClient, ChatSessionRepository sessionRepository, ChatMessageRepository messageRepository, ChatParticipantRepository participantRepository, diff --git a/webapi/Controllers/ChatMemoryController.cs b/webapi/Controllers/ChatMemoryController.cs index ce33d920d..84cb8064f 100644 --- a/webapi/Controllers/ChatMemoryController.cs +++ b/webapi/Controllers/ChatMemoryController.cs @@ -14,7 +14,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.SemanticMemory; +using Microsoft.KernelMemory; namespace CopilotChat.WebApi.Controllers; @@ -58,7 +58,7 @@ public ChatMemoryController( [ProducesResponseType(StatusCodes.Status400BadRequest)] [Authorize(Policy = AuthPolicyName.RequireChatParticipant)] public async Task GetSemanticMemoriesAsync( - [FromServices] ISemanticMemoryClient memoryClient, + [FromServices] IKernelMemory memoryClient, [FromRoute] string chatId, [FromQuery] string type) { diff --git a/webapi/Controllers/DocumentController.cs b/webapi/Controllers/DocumentController.cs index 884d2ac06..2382ffc23 100644 --- a/webapi/Controllers/DocumentController.cs +++ b/webapi/Controllers/DocumentController.cs @@ -20,7 +20,7 @@ using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.SemanticMemory; +using Microsoft.KernelMemory; namespace CopilotChat.WebApi.Controllers; @@ -86,7 +86,7 @@ public DocumentController( [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public Task DocumentImportAsync( - [FromServices] ISemanticMemoryClient memoryClient, + [FromServices] IKernelMemory memoryClient, [FromServices] IHubContext messageRelayHubContext, [FromForm] DocumentImportForm documentImportForm) { @@ -107,7 +107,7 @@ public Task DocumentImportAsync( [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public Task DocumentImportAsync( - [FromServices] ISemanticMemoryClient memoryClient, + [FromServices] IKernelMemory memoryClient, [FromServices] IHubContext messageRelayHubContext, [FromRoute] Guid chatId, [FromForm] DocumentImportForm documentImportForm) @@ -116,7 +116,7 @@ public Task DocumentImportAsync( } private async Task DocumentImportAsync( - ISemanticMemoryClient memoryClient, + IKernelMemory memoryClient, IHubContext messageRelayHubContext, DocumentScopes documentScope, Guid chatId, diff --git a/webapi/Controllers/ServiceInfoController.cs b/webapi/Controllers/ServiceInfoController.cs index 22cb72ec4..0f2ee8f5c 100644 --- a/webapi/Controllers/ServiceInfoController.cs +++ b/webapi/Controllers/ServiceInfoController.cs @@ -13,7 +13,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.SemanticMemory; +using Microsoft.KernelMemory; namespace CopilotChat.WebApi.Controllers; @@ -27,7 +27,7 @@ public class ServiceInfoController : ControllerBase private readonly IConfiguration Configuration; - private readonly SemanticMemoryConfig memoryOptions; + private readonly KernelMemoryConfig memoryOptions; private readonly ChatAuthenticationOptions _chatAuthenticationOptions; private readonly FrontendOptions _frontendOptions; private readonly IEnumerable availablePlugins; @@ -36,7 +36,7 @@ public class ServiceInfoController : ControllerBase public ServiceInfoController( ILogger logger, IConfiguration configuration, - IOptions memoryOptions, + IOptions memoryOptions, IOptions chatAuthenticationOptions, IOptions frontendOptions, IDictionary availablePlugins, diff --git a/webapi/CopilotChatWebApi.csproj b/webapi/CopilotChatWebApi.csproj index 02ea24a88..72c79a53b 100644 --- a/webapi/CopilotChatWebApi.csproj +++ b/webapi/CopilotChatWebApi.csproj @@ -1,4 +1,4 @@ - + CopilotChat.WebApi net6.0 @@ -21,15 +21,18 @@ - - - - - - - - - + + + + + + + + + + + + diff --git a/webapi/Extensions/ISemanticMemoryClientExtensions.cs b/webapi/Extensions/ISemanticMemoryClientExtensions.cs index 1b7e008d2..57e48302b 100644 --- a/webapi/Extensions/ISemanticMemoryClientExtensions.cs +++ b/webapi/Extensions/ISemanticMemoryClientExtensions.cs @@ -11,25 +11,25 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Microsoft.SemanticMemory; +using Microsoft.KernelMemory; namespace CopilotChat.WebApi.Extensions; /// -/// Extension methods for and service registration. +/// Extension methods for and service registration. /// internal static class ISemanticMemoryClientExtensions { private static readonly List pipelineSteps = new() { "extract", "partition", "gen_embeddings", "save_embeddings" }; /// - /// Inject . + /// Inject . /// public static void AddSemanticMemoryServices(this WebApplicationBuilder appBuilder) { var serviceProvider = appBuilder.Services.BuildServiceProvider(); - var memoryConfig = serviceProvider.GetRequiredService>().Value; + var memoryConfig = serviceProvider.GetRequiredService>().Value; var ocrType = memoryConfig.ImageOcrType; var hasOcr = !string.IsNullOrWhiteSpace(ocrType) && !ocrType.Equals(MemoryConfiguration.NoneType, StringComparison.OrdinalIgnoreCase); @@ -39,7 +39,7 @@ public static void AddSemanticMemoryServices(this WebApplicationBuilder appBuild appBuilder.Services.AddSingleton(sp => new DocumentTypeProvider(hasOcr)); - var memoryBuilder = new MemoryClientBuilder(appBuilder.Services); + var memoryBuilder = new KernelMemoryBuilder(appBuilder.Services); if (isDistributed) { @@ -53,13 +53,13 @@ public static void AddSemanticMemoryServices(this WebApplicationBuilder appBuild } } - ISemanticMemoryClient memory = memoryBuilder.FromAppSettings().Build(); + IKernelMemory memory = memoryBuilder.FromAppSettings().Build(); appBuilder.Services.AddSingleton(memory); } public static Task SearchMemoryAsync( - this ISemanticMemoryClient memoryClient, + this IKernelMemory memoryClient, string indexName, string query, float relevanceThreshold, @@ -71,7 +71,7 @@ public static Task SearchMemoryAsync( } public static async Task SearchMemoryAsync( - this ISemanticMemoryClient memoryClient, + this IKernelMemory memoryClient, string indexName, string query, float relevanceThreshold, @@ -106,7 +106,7 @@ await memoryClient.SearchAsync( } public static async Task StoreDocumentAsync( - this ISemanticMemoryClient memoryClient, + this IKernelMemory memoryClient, string indexName, string documentId, string chatId, @@ -131,7 +131,7 @@ public static async Task StoreDocumentAsync( } public static Task StoreMemoryAsync( - this ISemanticMemoryClient memoryClient, + this IKernelMemory memoryClient, string indexName, string chatId, string memoryName, @@ -142,7 +142,7 @@ public static Task StoreMemoryAsync( } public static async Task StoreMemoryAsync( - this ISemanticMemoryClient memoryClient, + this IKernelMemory memoryClient, string indexName, string chatId, string memoryName, @@ -176,7 +176,7 @@ public static async Task StoreMemoryAsync( } public static async Task RemoveChatMemoriesAsync( - this ISemanticMemoryClient memoryClient, + this IKernelMemory memoryClient, string indexName, string chatId, CancellationToken cancellationToken = default) diff --git a/webapi/Extensions/SemanticKernelExtensions.cs b/webapi/Extensions/SemanticKernelExtensions.cs index 4bcc61f8c..7a61faf1c 100644 --- a/webapi/Extensions/SemanticKernelExtensions.cs +++ b/webapi/Extensions/SemanticKernelExtensions.cs @@ -18,10 +18,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.KernelMemory; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Diagnostics; -using Microsoft.SemanticKernel.Skills.Core; -using Microsoft.SemanticMemory; +using Microsoft.SemanticKernel.Plugins.Core; namespace CopilotChat.WebApi.Extensions; @@ -151,10 +151,10 @@ public static IServiceCollection AddPlannerSetupHook(this IServiceCollection ser public static IKernel RegisterChatSkill(this IKernel kernel, IServiceProvider sp) { // Chat skill - kernel.ImportSkill( + kernel.ImportFunctions( new ChatSkill( kernel, - memoryClient: sp.GetRequiredService(), + memoryClient: sp.GetRequiredService(), chatMessageRepository: sp.GetRequiredService(), chatSessionRepository: sp.GetRequiredService(), messageRelayHubContext: sp.GetRequiredService>(), @@ -182,7 +182,7 @@ private static Task RegisterChatCopilotSkillsAsync(IServiceProvider sp, IKernel kernel.RegisterChatSkill(sp); // Time skill - kernel.ImportSkill(new TimeSkill(), nameof(TimeSkill)); + kernel.ImportFunctions(new TimePlugin(), nameof(TimePlugin)); return Task.CompletedTask; } @@ -202,7 +202,7 @@ private static Task RegisterPluginsAsync(IServiceProvider sp, IKernel kernel) { try { - kernel.ImportSemanticSkillFromDirectory(options.SemanticPluginsDirectory, Path.GetFileName(subDir)!); + kernel.ImportSemanticFunctionsFromDirectory(options.SemanticPluginsDirectory, Path.GetFileName(subDir)!); } catch (SKException ex) { @@ -231,7 +231,7 @@ private static Task RegisterPluginsAsync(IServiceProvider sp, IKernel kernel) try { var plugin = Activator.CreateInstance(classType); - kernel.ImportSkill(plugin!, classType.Name!); + kernel.ImportFunctions(plugin!, classType.Name!); } catch (SKException ex) { @@ -263,7 +263,7 @@ internal static void AddContentSafety(this IServiceCollection services) /// private static ChatArchiveEmbeddingConfig WithBotConfig(this IServiceProvider provider, IConfiguration configuration) { - var memoryOptions = provider.GetRequiredService>().Value; + var memoryOptions = provider.GetRequiredService>().Value; switch (memoryOptions.Retrieval.EmbeddingGeneratorType) { diff --git a/webapi/Extensions/ServiceExtensions.cs b/webapi/Extensions/ServiceExtensions.cs index f679fe384..3eceb9e66 100644 --- a/webapi/Extensions/ServiceExtensions.cs +++ b/webapi/Extensions/ServiceExtensions.cs @@ -5,6 +5,7 @@ using System.IO; using System.Net.Http; using System.Reflection; +using CopilotChat.Shared; using CopilotChat.WebApi.Auth; using CopilotChat.WebApi.Models.Storage; using CopilotChat.WebApi.Options; @@ -20,8 +21,8 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Identity.Web; +using Microsoft.KernelMemory; using Microsoft.SemanticKernel.Diagnostics; -using Microsoft.SemanticMemory; namespace CopilotChat.WebApi.Extensions; @@ -31,8 +32,6 @@ namespace CopilotChat.WebApi.Extensions; /// public static class CopilotChatServiceExtensions { - private const string SemanticMemoryOptionsName = "SemanticMemory"; - /// /// Parse configuration into options. /// @@ -59,7 +58,7 @@ public static IServiceCollection AddOptions(this IServiceCollection services, Co AddOptions(ContentSafetyOptions.PropertyName); - AddOptions(SemanticMemoryOptionsName); + AddOptions(MemoryConfiguration.KernelMemorySection); AddOptions(FrontendOptions.PropertyName); diff --git a/webapi/Models/Response/ChatArchive.cs b/webapi/Models/Response/ChatArchive.cs index b7705c9fc..6ffefc7a0 100644 --- a/webapi/Models/Response/ChatArchive.cs +++ b/webapi/Models/Response/ChatArchive.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using CopilotChat.WebApi.Models.Storage; using CopilotChat.WebApi.Options; -using Microsoft.SemanticMemory; +using Microsoft.KernelMemory; namespace CopilotChat.WebApi.Models.Response; diff --git a/webapi/Models/Storage/CitationSource.cs b/webapi/Models/Storage/CitationSource.cs index cb2a35ede..497791888 100644 --- a/webapi/Models/Storage/CitationSource.cs +++ b/webapi/Models/Storage/CitationSource.cs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -using Microsoft.SemanticMemory; +using Microsoft.KernelMemory; namespace CopilotChat.WebApi.Models.Storage; diff --git a/webapi/Options/MemoryStoreType.cs b/webapi/Options/MemoryStoreType.cs index a94aca68c..6d92b3f85 100644 --- a/webapi/Options/MemoryStoreType.cs +++ b/webapi/Options/MemoryStoreType.cs @@ -2,8 +2,8 @@ using System; using Microsoft.Extensions.Configuration; -using Microsoft.SemanticMemory; -using Microsoft.SemanticMemory.MemoryStorage.DevTools; +using Microsoft.KernelMemory; +using Microsoft.KernelMemory.MemoryStorage.DevTools; namespace CopilotChat.WebApi.Options; @@ -42,7 +42,7 @@ public static class MemoryStoreTypeExtensions /// /// The configuration. /// The memory store type. - public static MemoryStoreType GetMemoryStoreType(this SemanticMemoryConfig memoryOptions, IConfiguration configuration) + public static MemoryStoreType GetMemoryStoreType(this KernelMemoryConfig memoryOptions, IConfiguration configuration) { var type = memoryOptions.Retrieval.VectorDbType; if (type.Equals("AzureCognitiveSearch", StringComparison.OrdinalIgnoreCase)) diff --git a/webapi/Options/PlannerOptions.cs b/webapi/Options/PlannerOptions.cs index 86c79e249..672771049 100644 --- a/webapi/Options/PlannerOptions.cs +++ b/webapi/Options/PlannerOptions.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using System.ComponentModel.DataAnnotations; using CopilotChat.WebApi.Models.Response; -using Microsoft.SemanticKernel.Planning.Stepwise; +using Microsoft.SemanticKernel.Planners; namespace CopilotChat.WebApi.Options; diff --git a/webapi/Services/DocumentTypeProvider.cs b/webapi/Services/DocumentTypeProvider.cs index 198fac941..28dcf1882 100644 --- a/webapi/Services/DocumentTypeProvider.cs +++ b/webapi/Services/DocumentTypeProvider.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; -using Microsoft.SemanticMemory.Pipeline; +using Microsoft.KernelMemory.Pipeline; namespace CopilotChat.WebApi.Services; diff --git a/webapi/Services/MemoryMigration/ChatMemoryMigrationService.cs b/webapi/Services/MemoryMigration/ChatMemoryMigrationService.cs index bce9677d6..a3f606569 100644 --- a/webapi/Services/MemoryMigration/ChatMemoryMigrationService.cs +++ b/webapi/Services/MemoryMigration/ChatMemoryMigrationService.cs @@ -10,8 +10,8 @@ using CopilotChat.WebApi.Storage; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.KernelMemory; using Microsoft.SemanticKernel.Memory; -using Microsoft.SemanticMemory; namespace CopilotChat.WebApi.Services.MemoryMigration; @@ -22,7 +22,7 @@ public class ChatMemoryMigrationService : IChatMemoryMigrationService { private readonly ILogger _logger; private readonly ISemanticTextMemory _memory; - private readonly ISemanticMemoryClient _memoryClient; + private readonly IKernelMemory _memoryClient; private readonly ChatSessionRepository _chatSessionRepository; private readonly ChatMemorySourceRepository _memorySourceRepository; private readonly string _globalIndex; @@ -35,7 +35,7 @@ public ChatMemoryMigrationService( ILogger logger, IOptions documentMemoryOptions, IOptions promptOptions, - ISemanticMemoryClient memoryClient, + IKernelMemory memoryClient, ChatSessionRepository chatSessionRepository, ChatMemorySourceRepository memorySourceRepository, SemanticKernelProvider provider) @@ -46,8 +46,7 @@ public ChatMemoryMigrationService( this._chatSessionRepository = chatSessionRepository; this._memorySourceRepository = memorySourceRepository; this._globalIndex = documentMemoryOptions.Value.GlobalDocumentCollectionName; - var kernel = provider.GetMigrationKernel(); - this._memory = kernel.Memory; + this._memory = provider.GetMigrationMemory(); } /// diff --git a/webapi/Services/MemoryMigration/ChatMigrationMonitor.cs b/webapi/Services/MemoryMigration/ChatMigrationMonitor.cs index 8d5e3f119..c281a036a 100644 --- a/webapi/Services/MemoryMigration/ChatMigrationMonitor.cs +++ b/webapi/Services/MemoryMigration/ChatMigrationMonitor.cs @@ -47,8 +47,7 @@ public ChatMigrationMonitor( this._logger = logger; this._indexNameGlobalDocs = docOptions.Value.GlobalDocumentCollectionName; this._indexNameAllMemory = promptOptions.Value.MemoryIndexName; - var kernel = provider.GetMigrationKernel(); - this._memory = kernel.Memory; + this._memory = provider.GetMigrationMemory(); } /// diff --git a/webapi/Services/MemoryMigration/ChatMigrationStatus.cs b/webapi/Services/MemoryMigration/ChatMigrationStatus.cs index 190505768..d51dcd701 100644 --- a/webapi/Services/MemoryMigration/ChatMigrationStatus.cs +++ b/webapi/Services/MemoryMigration/ChatMigrationStatus.cs @@ -1,5 +1,4 @@ // Copyright (c) Microsoft. All rights reserved. - namespace CopilotChat.WebApi.Services.MemoryMigration; /// diff --git a/webapi/Services/SemanticKernelProvider.cs b/webapi/Services/SemanticKernelProvider.cs index aafaa9e3b..44dcd0888 100644 --- a/webapi/Services/SemanticKernelProvider.cs +++ b/webapi/Services/SemanticKernelProvider.cs @@ -8,13 +8,14 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.KernelMemory; +using Microsoft.KernelMemory.MemoryStorage.Qdrant; using Microsoft.SemanticKernel; -using Microsoft.SemanticKernel.AI.Embeddings; +using Microsoft.SemanticKernel.Connectors.AI.OpenAI; using Microsoft.SemanticKernel.Connectors.Memory.AzureCognitiveSearch; using Microsoft.SemanticKernel.Connectors.Memory.Qdrant; using Microsoft.SemanticKernel.Memory; -using Microsoft.SemanticMemory; -using Microsoft.SemanticMemory.MemoryStorage.Qdrant; +using Microsoft.SemanticKernel.Plugins.Memory; namespace CopilotChat.WebApi.Services; @@ -25,149 +26,157 @@ public sealed class SemanticKernelProvider { private static IMemoryStore? _volatileMemoryStore; - private readonly IServiceProvider _serviceProvider; - private readonly IConfiguration _configuration; - private readonly IHttpClientFactory _httpClientFactory; + private readonly KernelBuilder _builderChat; + private readonly KernelBuilder _builderPlanner; + private readonly MemoryBuilder _builderMemory; public SemanticKernelProvider(IServiceProvider serviceProvider, IConfiguration configuration, IHttpClientFactory httpClientFactory) { - this._serviceProvider = serviceProvider; - this._configuration = configuration; - this._httpClientFactory = httpClientFactory; + this._builderChat = InitializeCompletionKernel(serviceProvider, configuration, httpClientFactory); + this._builderPlanner = InitializePlannerKernel(serviceProvider, configuration, httpClientFactory); + this._builderMemory = InitializeMigrationMemory(serviceProvider, configuration, httpClientFactory); } /// /// Produce semantic-kernel with only completion services for chat. /// - public IKernel GetCompletionKernel() - { - var builder = Kernel.Builder.WithLoggerFactory(this._serviceProvider.GetRequiredService()); - - this.WithCompletionBackend(builder); - - return builder.Build(); - } + public IKernel GetCompletionKernel() => this._builderChat.Build(); /// /// Produce semantic-kernel with only completion services for planner. /// - public IKernel GetPlannerKernel() - { - var builder = Kernel.Builder.WithLoggerFactory(this._serviceProvider.GetRequiredService()); - - this.WithPlannerBackend(builder); - - return builder.Build(); - } + public IKernel GetPlannerKernel() => this._builderPlanner.Build(); /// /// Produce semantic-kernel with semantic-memory. /// - public IKernel GetMigrationKernel() - { - var builder = Kernel.Builder.WithLoggerFactory(this._serviceProvider.GetRequiredService()); + public ISemanticTextMemory GetMigrationMemory() => this._builderMemory.Build(); - this.WithEmbeddingBackend(builder); - this.WithSemanticTextMemory(builder); + private static KernelBuilder InitializeCompletionKernel( + IServiceProvider serviceProvider, + IConfiguration configuration, + IHttpClientFactory httpClientFactory) + { + var builder = new KernelBuilder(); - return builder.Build(); - } + builder.WithLoggerFactory(serviceProvider.GetRequiredService()); - /// - /// Add the completion backend to the kernel config - /// - private KernelBuilder WithCompletionBackend(KernelBuilder kernelBuilder) - { - var memoryOptions = this._serviceProvider.GetRequiredService>().Value; + var memoryOptions = serviceProvider.GetRequiredService>().Value; switch (memoryOptions.TextGeneratorType) { case string x when x.Equals("AzureOpenAI", StringComparison.OrdinalIgnoreCase): case string y when y.Equals("AzureOpenAIText", StringComparison.OrdinalIgnoreCase): - var azureAIOptions = memoryOptions.GetServiceConfig(this._configuration, "AzureOpenAIText"); -#pragma warning disable CA2000 // Dispose objects before losing scope - No need to dispose of HttpClient instances from IHttpClientFactory - return kernelBuilder.WithAzureChatCompletionService(azureAIOptions.Deployment, azureAIOptions.Endpoint, azureAIOptions.APIKey, - httpClient: this._httpClientFactory.CreateClient()); + var azureAIOptions = memoryOptions.GetServiceConfig(configuration, "AzureOpenAIText"); +#pragma warning disable CA2000 // No need to dispose of HttpClient instances from IHttpClientFactory + builder.WithAzureChatCompletionService( + azureAIOptions.Deployment, + azureAIOptions.Endpoint, + azureAIOptions.APIKey, + httpClient: httpClientFactory.CreateClient()); +#pragma warning restore CA2000 + break; case string x when x.Equals("OpenAI", StringComparison.OrdinalIgnoreCase): - var openAIOptions = memoryOptions.GetServiceConfig(this._configuration, "OpenAI"); - return kernelBuilder.WithOpenAIChatCompletionService(openAIOptions.TextModel, openAIOptions.APIKey, - httpClient: this._httpClientFactory.CreateClient()); -#pragma warning restore CA2000 // Dispose objects before losing scope + var openAIOptions = memoryOptions.GetServiceConfig(configuration, "OpenAI"); +#pragma warning disable CA2000 // No need to dispose of HttpClient instances from IHttpClientFactory + builder.WithOpenAIChatCompletionService( + openAIOptions.TextModel, + openAIOptions.APIKey, + httpClient: httpClientFactory.CreateClient()); +#pragma warning restore CA2000 + break; default: - throw new ArgumentException($"Invalid {nameof(memoryOptions.TextGeneratorType)} value in 'SemanticMemory' settings."); + throw new ArgumentException($"Invalid {nameof(memoryOptions.TextGeneratorType)} value in 'KernelMemory' settings."); } + + return builder; } - /// - /// Add the completion backend to the kernel config for the planner. - /// - private KernelBuilder WithPlannerBackend(KernelBuilder kernelBuilder) + private static KernelBuilder InitializePlannerKernel( + IServiceProvider serviceProvider, + IConfiguration configuration, + IHttpClientFactory httpClientFactory) { - var memoryOptions = this._serviceProvider.GetRequiredService>().Value; - var plannerOptions = this._serviceProvider.GetRequiredService>().Value; + var builder = new KernelBuilder(); + + builder.WithLoggerFactory(serviceProvider.GetRequiredService()); + + var memoryOptions = serviceProvider.GetRequiredService>().Value; + var plannerOptions = serviceProvider.GetRequiredService>().Value; switch (memoryOptions.TextGeneratorType) { case string x when x.Equals("AzureOpenAI", StringComparison.OrdinalIgnoreCase): case string y when y.Equals("AzureOpenAIText", StringComparison.OrdinalIgnoreCase): - var azureAIOptions = memoryOptions.GetServiceConfig(this._configuration, "AzureOpenAIText"); -#pragma warning disable CA2000 // Dispose objects before losing scope - No need to dispose of HttpClient instances from IHttpClientFactory - return kernelBuilder.WithAzureChatCompletionService(plannerOptions.Model, azureAIOptions.Endpoint, azureAIOptions.APIKey, - httpClient: this._httpClientFactory.CreateClient()); + var azureAIOptions = memoryOptions.GetServiceConfig(configuration, "AzureOpenAIText"); +#pragma warning disable CA2000 // No need to dispose of HttpClient instances from IHttpClientFactory + builder.WithAzureChatCompletionService( + plannerOptions.Model, + azureAIOptions.Endpoint, + azureAIOptions.APIKey, + httpClient: httpClientFactory.CreateClient()); +#pragma warning restore CA2000 + break; case string x when x.Equals("OpenAI", StringComparison.OrdinalIgnoreCase): - var openAIOptions = memoryOptions.GetServiceConfig(this._configuration, "OpenAI"); - return kernelBuilder.WithOpenAIChatCompletionService(plannerOptions.Model, openAIOptions.APIKey, - httpClient: this._httpClientFactory.CreateClient()); -#pragma warning restore CA2000 // Dispose objects before losing scope + var openAIOptions = memoryOptions.GetServiceConfig(configuration, "OpenAI"); +#pragma warning disable CA2000 // No need to dispose of HttpClient instances from IHttpClientFactory + builder.WithOpenAIChatCompletionService( + plannerOptions.Model, + openAIOptions.APIKey, + httpClient: httpClientFactory.CreateClient()); +#pragma warning restore CA2000 + break; + default: - throw new ArgumentException($"Invalid {nameof(memoryOptions.TextGeneratorType)} value in 'SemanticMemory' settings."); + throw new ArgumentException($"Invalid {nameof(memoryOptions.TextGeneratorType)} value in 'KernelMemory' settings."); } + + return builder; } - /// - /// Add the embedding backend to the kernel config - /// - private KernelBuilder WithEmbeddingBackend(KernelBuilder kernelBuilder) + private static MemoryBuilder InitializeMigrationMemory( + IServiceProvider serviceProvider, + IConfiguration configuration, + IHttpClientFactory httpClientFactory) { - var memoryOptions = this._serviceProvider.GetRequiredService>().Value; + var memoryOptions = serviceProvider.GetRequiredService>().Value; + + var builder = new MemoryBuilder(); + + builder.WithLoggerFactory(serviceProvider.GetRequiredService()); + builder.WithMemoryStore(CreateMemoryStore()); switch (memoryOptions.Retrieval.EmbeddingGeneratorType) { case string x when x.Equals("AzureOpenAI", StringComparison.OrdinalIgnoreCase): case string y when y.Equals("AzureOpenAIEmbedding", StringComparison.OrdinalIgnoreCase): - var azureAIOptions = memoryOptions.GetServiceConfig(this._configuration, "AzureOpenAIEmbedding"); -#pragma warning disable CA2000 // Dispose objects before losing scope - No need to dispose of HttpClient instances from IHttpClientFactory - return kernelBuilder.WithAzureTextEmbeddingGenerationService(azureAIOptions.Deployment, azureAIOptions.Endpoint, azureAIOptions.APIKey, - httpClient: this._httpClientFactory.CreateClient()); + var azureAIOptions = memoryOptions.GetServiceConfig(configuration, "AzureOpenAIEmbedding"); +#pragma warning disable CA2000 // No need to dispose of HttpClient instances from IHttpClientFactory + builder.WithAzureTextEmbeddingGenerationService( + azureAIOptions.Deployment, + azureAIOptions.Endpoint, + azureAIOptions.APIKey, + httpClient: httpClientFactory.CreateClient()); +#pragma warning restore CA2000 + break; case string x when x.Equals("OpenAI", StringComparison.OrdinalIgnoreCase): - var openAIOptions = memoryOptions.GetServiceConfig(this._configuration, "OpenAI"); - return kernelBuilder.WithOpenAITextEmbeddingGenerationService(openAIOptions.EmbeddingModel, openAIOptions.APIKey, - httpClient: this._httpClientFactory.CreateClient()); -#pragma warning restore CA2000 // Dispose objects before losing scope + var openAIOptions = memoryOptions.GetServiceConfig(configuration, "OpenAI"); +#pragma warning disable CA2000 // No need to dispose of HttpClient instances from IHttpClientFactory + builder.WithOpenAITextEmbeddingGenerationService( + openAIOptions.EmbeddingModel, + openAIOptions.APIKey, + httpClient: httpClientFactory.CreateClient()); +#pragma warning restore CA2000 + break; + default: - throw new ArgumentException($"Invalid {nameof(memoryOptions.Retrieval.EmbeddingGeneratorType)} value in 'SemanticMemory' settings."); + throw new ArgumentException($"Invalid {nameof(memoryOptions.Retrieval.EmbeddingGeneratorType)} value in 'KernelMemory' settings."); } - } - - /// - /// Add the semantic text memory. - /// - private void WithSemanticTextMemory(KernelBuilder builder) - { - var memoryOptions = this._serviceProvider.GetRequiredService>().Value; - - IMemoryStore memoryStore = CreateMemoryStore(); - -#pragma warning disable CA2000 // Ownership passed to kernel - builder.WithMemory( - new SemanticTextMemory( - memoryStore, - this._serviceProvider.GetRequiredService())); -#pragma warning restore CA2000 // Ownership passed to kernel + return builder; IMemoryStore CreateMemoryStore() { @@ -179,7 +188,7 @@ IMemoryStore CreateMemoryStore() return _volatileMemoryStore; case string x when x.Equals("Qdrant", StringComparison.OrdinalIgnoreCase): - var qdrantConfig = memoryOptions.GetServiceConfig(this._configuration, "Qdrant"); + var qdrantConfig = memoryOptions.GetServiceConfig(configuration, "Qdrant"); #pragma warning disable CA2000 // Ownership passed to QdrantMemoryStore HttpClient httpClient = new(new HttpClientHandler { CheckCertificateRevocationList = true }); @@ -194,10 +203,10 @@ IMemoryStore CreateMemoryStore() httpClient: httpClient, 1536, qdrantConfig.Endpoint, - loggerFactory: this._serviceProvider.GetRequiredService()); + loggerFactory: serviceProvider.GetRequiredService()); case string x when x.Equals("AzureCognitiveSearch", StringComparison.OrdinalIgnoreCase): - var acsConfig = memoryOptions.GetServiceConfig(this._configuration, "AzureCognitiveSearch"); + var acsConfig = memoryOptions.GetServiceConfig(configuration, "AzureCognitiveSearch"); return new AzureCognitiveSearchMemoryStore(acsConfig.Endpoint, acsConfig.APIKey); default: diff --git a/webapi/Skills/ChatSkills/ChatSkill.cs b/webapi/Skills/ChatSkills/ChatSkill.cs index 914751d54..54aefd76b 100644 --- a/webapi/Skills/ChatSkills/ChatSkill.cs +++ b/webapi/Skills/ChatSkills/ChatSkill.cs @@ -21,15 +21,14 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; +using Microsoft.KernelMemory; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.AI.ChatCompletion; -using Microsoft.SemanticKernel.AI.TextCompletion; +using Microsoft.SemanticKernel.Connectors.AI.OpenAI; using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Orchestration; using Microsoft.SemanticKernel.Planning; -using Microsoft.SemanticKernel.SkillDefinition; -using Microsoft.SemanticKernel.TemplateEngine.Prompt; -using Microsoft.SemanticMemory; +using Microsoft.SemanticKernel.TemplateEngine.Basic; using ChatCompletionContextMessages = Microsoft.SemanticKernel.AI.ChatCompletion.ChatHistory; namespace CopilotChat.WebApi.Skills.ChatSkills; @@ -49,7 +48,7 @@ public class ChatSkill /// /// Client for the semantic-memory service. /// - private readonly ISemanticMemoryClient _memoryClient; + private readonly IKernelMemory _memoryClient; /// /// A logger instance to log events. @@ -96,7 +95,7 @@ public class ChatSkill /// public ChatSkill( IKernel kernel, - ISemanticMemoryClient memoryClient, + IKernelMemory memoryClient, ChatMessageRepository chatMessageRepository, ChatSessionRepository chatSessionRepository, IHubContext messageRelayHubContext, @@ -133,10 +132,7 @@ public ChatSkill( /// /// The SKContext. /// The cancellation token. - [SKFunction, Description("Extract user intent")] - [SKParameter("chatId", "Chat ID to extract history from")] - [SKParameter("audience", "The audience the chat bot is interacting with.")] - public async Task ExtractUserIntentAsync(SKContext context, CancellationToken cancellationToken = default) + private async Task ExtractUserIntentAsync(SKContext context, CancellationToken cancellationToken = default) { var tokenLimit = this._promptOptions.CompletionTokenLimit; var historyTokenBudget = @@ -157,12 +153,12 @@ public async Task ExtractUserIntentAsync(SKContext context, Cancellation var completionFunction = this._kernel.CreateSemanticFunction( this._promptOptions.SystemIntentExtraction, - skillName: nameof(ChatSkill), + pluginName: nameof(ChatSkill), description: "Complete the prompt."); var result = await completionFunction.InvokeAsync( intentExtractionContext, - settings: this.CreateIntentCompletionSettings(), + this.CreateIntentCompletionSettings(), cancellationToken ); @@ -178,9 +174,7 @@ public async Task ExtractUserIntentAsync(SKContext context, Cancellation /// /// The SKContext. /// The cancellation token. - [SKFunction, Description("Extract audience list")] - [SKParameter("chatId", "Chat ID to extract history from")] - public async Task ExtractAudienceAsync(SKContext context, CancellationToken cancellationToken = default) + private async Task ExtractAudienceAsync(SKContext context, CancellationToken cancellationToken = default) { var tokenLimit = this._promptOptions.CompletionTokenLimit; var historyTokenBudget = @@ -199,12 +193,12 @@ public async Task ExtractAudienceAsync(SKContext context, CancellationTo var completionFunction = this._kernel.CreateSemanticFunction( this._promptOptions.SystemAudienceExtraction, - skillName: nameof(ChatSkill), + pluginName: nameof(ChatSkill), description: "Complete the prompt."); var result = await completionFunction.InvokeAsync( audienceExtractionContext, - settings: this.CreateIntentCompletionSettings(), + this.CreateIntentCompletionSettings(), cancellationToken ); @@ -442,7 +436,7 @@ await this.SaveNewResponseAsync( // Add bot message proposal as prompt context message chatContext.Variables.Set("planFunctions", this._externalInformationSkill.FormattedFunctionsString(deserializedPlan.Plan)); - var promptRenderer = new PromptTemplateEngine(); + var promptRenderer = new BasicPromptTemplateEngine(); var proposedPlanBotMessage = await promptRenderer.RenderAsync( this._promptOptions.ProposedPlanBotMessage, chatContext, @@ -518,8 +512,6 @@ await this.SaveNewResponseAsync( return context; } - #region Private - /// /// Generate the necessary chat context to create a prompt then invoke the model to get a response. /// @@ -635,7 +627,7 @@ private async Task RenderSystemInstructions(string chatId, SKContext con { // Render system instruction components await this.UpdateBotResponseStatusOnClientAsync(chatId, "Initializing prompt", cancellationToken); - var promptRenderer = new PromptTemplateEngine(); + var promptRenderer = new BasicPromptTemplateEngine(); return await promptRenderer.RenderAsync( this._promptOptions.SystemPersona, context, @@ -859,11 +851,11 @@ private async Task UpdateChatMessageContentAsync(string updatedResponse, string } /// - /// Create `ChatRequestSettings` for chat response. Parameters are read from the PromptSettings class. + /// Create `OpenAIRequestSettings` for chat response. Parameters are read from the PromptSettings class. /// - private ChatRequestSettings CreateChatRequestSettings() + private OpenAIRequestSettings CreateChatRequestSettings() { - return new ChatRequestSettings + return new OpenAIRequestSettings { MaxTokens = this._promptOptions.ResponseTokenLimit, Temperature = this._promptOptions.ResponseTemperature, @@ -874,11 +866,11 @@ private ChatRequestSettings CreateChatRequestSettings() } /// - /// Create `CompleteRequestSettings` for intent response. Parameters are read from the PromptSettings class. + /// Create `OpenAIRequestSettings` for intent response. Parameters are read from the PromptSettings class. /// - private CompleteRequestSettings CreateIntentCompletionSettings() + private OpenAIRequestSettings CreateIntentCompletionSettings() { - return new CompleteRequestSettings + return new OpenAIRequestSettings { MaxTokens = this._promptOptions.ResponseTokenLimit, Temperature = this._promptOptions.IntentTemperature, @@ -949,7 +941,11 @@ private async Task StreamResponseToClientAsync( { // Create the stream var chatCompletion = this._kernel.GetService(); - var stream = chatCompletion.GenerateMessageStreamAsync(prompt.MetaPromptTemplate, this.CreateChatRequestSettings(), cancellationToken); + var stream = + chatCompletion.GenerateMessageStreamAsync( + prompt.MetaPromptTemplate, + this.CreateChatRequestSettings(), + cancellationToken); // Create message on client var chatMessage = await this.CreateBotMessageOnClient( @@ -1033,6 +1029,4 @@ private async Task SetSystemDescriptionAsync(string chatId, CancellationToken ca this._promptOptions.SystemDescription = chatSession!.SystemDescription; } - - # endregion } diff --git a/webapi/Skills/ChatSkills/CopilotChatPlanner.cs b/webapi/Skills/ChatSkills/CopilotChatPlanner.cs index bf754d73a..9a6893798 100644 --- a/webapi/Skills/ChatSkills/CopilotChatPlanner.cs +++ b/webapi/Skills/ChatSkills/CopilotChatPlanner.cs @@ -10,12 +10,12 @@ using CopilotChat.WebApi.Models.Response; using CopilotChat.WebApi.Options; using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Tokens; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Orchestration; +using Microsoft.SemanticKernel.Planners; using Microsoft.SemanticKernel.Planning; -using Microsoft.SemanticKernel.Planning.Sequential; -using Microsoft.SemanticKernel.SkillDefinition; namespace CopilotChat.WebApi.Skills.ChatSkills; @@ -84,8 +84,8 @@ public CopilotChatPlanner(IKernel plannerKernel, PlannerOptions? plannerOptions, /// The plan. public async Task CreatePlanAsync(string goal, ILogger logger, CancellationToken cancellationToken = default) { - FunctionsView plannerFunctionsView = this.Kernel.Skills.GetFunctionsView(true, true); - if (plannerFunctionsView.NativeFunctions.IsEmpty && plannerFunctionsView.SemanticFunctions.IsEmpty) + var plannerFunctionsView = this.Kernel.Functions.GetFunctionViews(); + if (plannerFunctionsView.IsNullOrEmpty()) { // No functions are available - return an empty plan. return new Plan(goal); @@ -102,7 +102,10 @@ public async Task CreatePlanAsync(string goal, ILogger logger, Cancellatio this.Kernel, new SequentialPlannerConfig { - RelevancyThreshold = this._plannerOptions?.RelevancyThreshold, + SemanticMemoryConfig = + { + RelevancyThreshold = this._plannerOptions?.RelevancyThreshold, + }, // Allow plan to be created with missing functions AllowMissingFunctions = this._plannerOptions?.ErrorHandling.AllowMissingFunctions ?? false } @@ -128,17 +131,16 @@ public async Task CreatePlanAsync(string goal, ILogger logger, Cancellatio /// The goal containing user intent and ask context. /// The context to run the plan in. /// The cancellation token. - public async Task RunStepwisePlannerAsync(string goal, SKContext context, CancellationToken cancellationToken = default) + public async Task RunStepwisePlannerAsync(string goal, SKContext context, CancellationToken cancellationToken = default) { - var config = new Microsoft.SemanticKernel.Planning.Stepwise.StepwisePlannerConfig() + var config = new StepwisePlannerConfig() { MaxTokens = this._plannerOptions?.StepwisePlannerConfig.MaxTokens ?? 2048, MaxIterations = this._plannerOptions?.StepwisePlannerConfig.MaxIterations ?? 15, MinIterationTimeMs = this._plannerOptions?.StepwisePlannerConfig.MinIterationTimeMs ?? 1500 }; - Stopwatch sw = new(); - sw.Start(); + var sw = Stopwatch.StartNew(); try { @@ -149,7 +151,7 @@ public async Task RunStepwisePlannerAsync(string goal, SKContext cont var result = await plan.InvokeAsync(context, cancellationToken: cancellationToken); sw.Stop(); - result.Variables.Set("timeTaken", sw.Elapsed.ToString()); + context.Variables.Set("timeTaken", sw.Elapsed.ToString()); return result; } catch (Exception e) @@ -159,8 +161,6 @@ public async Task RunStepwisePlannerAsync(string goal, SKContext cont } } - #region Private - /// /// Scrubs plan of functions not available in planner's kernel /// and flags any effected input dependencies with '$???' to prompt for user input. @@ -168,7 +168,7 @@ public async Task RunStepwisePlannerAsync(string goal, SKContext cont /// The functions available in the planner's kernel. /// Logger from context. /// - private Plan SanitizePlan(Plan plan, FunctionsView availableFunctions, ILogger logger) + private Plan SanitizePlan(Plan plan, IEnumerable availableFunctions, ILogger logger) { // TODO: [Issue #2256] Re-evaluate this logic once we have a better understanding of how to handle missing functions List sanitizedSteps = new(); List availableOutputs = new(); @@ -177,7 +177,7 @@ private Plan SanitizePlan(Plan plan, FunctionsView availableFunctions, ILogger l foreach (var step in plan.Steps) { // Check if function exists in planner's kernel - if (this.Kernel.Skills.TryGetFunction(step.SkillName, step.Name, out var function)) + if (this.Kernel.Functions.TryGetFunction(step.PluginName, step.Name, out var function)) { availableOutputs.AddRange(step.Outputs); @@ -221,10 +221,11 @@ private Plan SanitizePlan(Plan plan, FunctionsView availableFunctions, ILogger l Plan sanitizedPlan = new(plan.Description, sanitizedSteps.ToArray()); // Merge any parameters back into new plan object - sanitizedPlan.Parameters.Update(plan.Parameters); + foreach (var parameter in plan.Parameters) + { + sanitizedPlan.Parameters[parameter.Key] = parameter.Value; + } return sanitizedPlan; } - - #endregion } diff --git a/webapi/Skills/ChatSkills/ExternalInformationSkill.cs b/webapi/Skills/ChatSkills/ExternalInformationSkill.cs index e834a9f40..7726c4965 100644 --- a/webapi/Skills/ChatSkills/ExternalInformationSkill.cs +++ b/webapi/Skills/ChatSkills/ExternalInformationSkill.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Globalization; using System.Linq; using System.Text.Json; @@ -19,10 +18,9 @@ using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Microsoft.SemanticKernel.Orchestration; +using Microsoft.SemanticKernel.Planners; using Microsoft.SemanticKernel.Planning; -using Microsoft.SemanticKernel.Planning.Stepwise; -using Microsoft.SemanticKernel.SkillDefinition; -using Microsoft.SemanticKernel.TemplateEngine.Prompt; +using Microsoft.SemanticKernel.TemplateEngine.Basic; namespace CopilotChat.WebApi.Skills.ChatSkills; @@ -49,14 +47,7 @@ public class ExternalInformationSkill /// /// Options for the planner. /// - private readonly PlannerOptions? _plannerOptions; - public PlannerOptions? PlannerOptions - { - get - { - return this._plannerOptions; - } - } + public PlannerOptions? PlannerOptions { get; } /// /// Proposed plan to return for approval. @@ -83,7 +74,7 @@ public ExternalInformationSkill( { this._promptOptions = promptOptions.Value; this._planner = planner; - this._plannerOptions = planner.PlannerOptions; + this.PlannerOptions = planner.PlannerOptions; this._logger = logger; } @@ -92,18 +83,14 @@ public ExternalInformationSkill( /// /// Invoke planner to generate a new plan or extract relevant additional knowledge. /// - /// The cancellation token. - [SKFunction, Description("Acquire external information")] - [SKParameter("tokenLimit", "Maximum number of tokens")] - [SKParameter("proposedPlan", "Previously proposed plan that is approved")] public async Task InvokePlannerAsync( - [Description("The intent to whether external information is needed")] string userIntent, + string userIntent, SKContext context, CancellationToken cancellationToken = default) { // TODO: [Issue #2106] Calculate planner and plan token usage - FunctionsView functions = this._planner.Kernel.Skills.GetFunctionsView(true, true); - if (functions.NativeFunctions.IsEmpty && functions.SemanticFunctions.IsEmpty) + var functions = this._planner.Kernel.Functions.GetFunctionViews(); + if (functions.IsNullOrEmpty()) { return string.Empty; } @@ -169,12 +156,12 @@ public async Task ExecutePlanAsync( CancellationToken cancellationToken = default) { // Reload the plan with the planner's kernel so it has full context to be executed - var newPlanContext = new SKContext(null, this._planner.Kernel.Skills, this._planner.Kernel.LoggerFactory); + var newPlanContext = this._planner.Kernel.CreateNewContext(context.Variables, this._planner.Kernel.Functions, this._planner.Kernel.LoggerFactory); string planJson = JsonSerializer.Serialize(plan); - plan = Plan.FromJson(planJson, newPlanContext); + plan = Plan.FromJson(planJson, this._planner.Kernel.Functions); // Invoke plan - newPlanContext = await plan.InvokeAsync(newPlanContext, cancellationToken: cancellationToken); + var functionResult = await plan.InvokeAsync(newPlanContext, null, cancellationToken); var functionsUsed = $"FUNCTIONS USED: {this.FormattedFunctionsString(plan)}"; // TODO: #2581 Account for planner system instructions @@ -216,13 +203,11 @@ public async Task ExecutePlanAsync( public bool UseStepwiseResultAsBotResponse(string planResult) { return !string.IsNullOrWhiteSpace(planResult) - && this._plannerOptions?.Type == PlanType.Stepwise - && this._plannerOptions.UseStepwiseResultAsBotResponse + && this.PlannerOptions?.Type == PlanType.Stepwise + && this.PlannerOptions.UseStepwiseResultAsBotResponse && this.StepwiseThoughtProcess != null; } - #region Private - /// /// Executes the stepwise planner with a given goal and context, and returns the result along with descriptive text. /// Also sets any metadata associated with stepwise planner execution. @@ -236,10 +221,10 @@ public bool UseStepwiseResultAsBotResponse(string planResult) private async Task RunStepwisePlannerAsync(string goal, SKContext context, CancellationToken cancellationToken) { var plannerContext = context.Clone(); - plannerContext = await this._planner.RunStepwisePlannerAsync(goal, context, cancellationToken); + var functionResult = await this._planner.RunStepwisePlannerAsync(goal, context, cancellationToken); // Populate the execution metadata. - var plannerResult = plannerContext.Variables.Input.Trim(); + var plannerResult = functionResult.GetValue()?.Trim() ?? string.Empty; this.StepwiseThoughtProcess = new PlanExecutionMetadata( plannerContext.Variables["stepsTaken"], plannerContext.Variables["timeTaken"], @@ -267,7 +252,7 @@ private async Task RunStepwisePlannerAsync(string goal, SKContext contex } // Render the supplement to guide the model in using the result. - var promptRenderer = new PromptTemplateEngine(); + var promptRenderer = new BasicPromptTemplateEngine(); var resultSupplement = await promptRenderer.RenderAsync( this._promptOptions.StepwisePlannerSupplement, plannerContext, @@ -324,6 +309,7 @@ private bool TryExtractJsonFromOpenApiPlanResult(SKContext context, string openA } json = string.Empty; + return false; } @@ -336,7 +322,7 @@ private string OptimizeOpenApiSkillJson(string jsonContent, int tokenLimit, Plan // Remove all new line characters + leading and trailing white space jsonContent = Regex.Replace(jsonContent.Trim(), @"[\n\r]", string.Empty); var document = JsonDocument.Parse(jsonContent); - string lastSkillInvoked = plan.Steps[^1].SkillName; + string lastSkillInvoked = plan.Steps[^1].PluginName; string lastSkillFunctionInvoked = plan.Steps[^1].Name; bool trimSkillResponse = false; @@ -479,7 +465,7 @@ private List GetPlanSteps(Plan plan) List steps = new(); foreach (var step in plan.Steps) { - steps.Add($"{step.SkillName}.{step.Name}"); + steps.Add($"{step.PluginName}.{step.Name}"); } return steps; @@ -499,6 +485,4 @@ private string GetChatContextString(SKContext context) || v.Key.Contains("chatId", StringComparison.CurrentCultureIgnoreCase))) .Select(v => $"{v.Key}: {v.Value}")); } - - #endregion } diff --git a/webapi/Skills/ChatSkills/SemanticChatMemoryExtractor.cs b/webapi/Skills/ChatSkills/SemanticChatMemoryExtractor.cs index 06cf4b743..bc8a7fb9e 100644 --- a/webapi/Skills/ChatSkills/SemanticChatMemoryExtractor.cs +++ b/webapi/Skills/ChatSkills/SemanticChatMemoryExtractor.cs @@ -9,10 +9,10 @@ using CopilotChat.WebApi.Options; using CopilotChat.WebApi.Skills.Utils; using Microsoft.Extensions.Logging; +using Microsoft.KernelMemory; using Microsoft.SemanticKernel; -using Microsoft.SemanticKernel.AI.TextCompletion; +using Microsoft.SemanticKernel.Connectors.AI.OpenAI; using Microsoft.SemanticKernel.Orchestration; -using Microsoft.SemanticMemory; namespace CopilotChat.WebApi.Skills.ChatSkills; @@ -32,7 +32,7 @@ internal static class SemanticChatMemoryExtractor /// The cancellation token. public static async Task ExtractSemanticChatMemoryAsync( string chatId, - ISemanticMemoryClient memoryClient, + IKernelMemory memoryClient, IKernel kernel, SKContext context, PromptsOptions options, @@ -135,9 +135,9 @@ await memoryClient.SearchMemoryAsync( /// /// Create a completion settings object for chat response. Parameters are read from the PromptSettings class. /// - private static CompleteRequestSettings ToCompletionSettings(this PromptsOptions options) + private static OpenAIRequestSettings ToCompletionSettings(this PromptsOptions options) { - var completionSettings = new CompleteRequestSettings + var completionSettings = new OpenAIRequestSettings { MaxTokens = options.ResponseTokenLimit, Temperature = options.ResponseTemperature, diff --git a/webapi/Skills/ChatSkills/SemanticMemoryRetriever.cs b/webapi/Skills/ChatSkills/SemanticMemoryRetriever.cs index 12329b321..13b8dfc57 100644 --- a/webapi/Skills/ChatSkills/SemanticMemoryRetriever.cs +++ b/webapi/Skills/ChatSkills/SemanticMemoryRetriever.cs @@ -13,7 +13,7 @@ using CopilotChat.WebApi.Storage; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Microsoft.SemanticMemory; +using Microsoft.KernelMemory; namespace CopilotChat.WebApi.Skills.ChatSkills; @@ -26,7 +26,7 @@ public class SemanticMemoryRetriever private readonly ChatSessionRepository _chatSessionRepository; - private readonly ISemanticMemoryClient _memoryClient; + private readonly IKernelMemory _memoryClient; private readonly List _memoryNames; @@ -41,7 +41,7 @@ public class SemanticMemoryRetriever public SemanticMemoryRetriever( IOptions promptOptions, ChatSessionRepository chatSessionRepository, - ISemanticMemoryClient memoryClient, + IKernelMemory memoryClient, ILogger logger) { this._promptOptions = promptOptions.Value; diff --git a/webapi/Skills/Utils/TokenUtils.cs b/webapi/Skills/Utils/TokenUtils.cs index dbf890253..f3c091ab1 100644 --- a/webapi/Skills/Utils/TokenUtils.cs +++ b/webapi/Skills/Utils/TokenUtils.cs @@ -5,6 +5,8 @@ using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Tokens; +using Microsoft.SemanticKernel.AI; using Microsoft.SemanticKernel.AI.ChatCompletion; using Microsoft.SemanticKernel.Connectors.AI.OpenAI.AzureSdk; using Microsoft.SemanticKernel.Orchestration; @@ -68,7 +70,7 @@ internal static Dictionary EmptyTokenUsages() /// The logger instance to use for logging errors. /// Name of the function that invoked the chat completion. /// true if token usage is found in result context; otherwise, false. - internal static void GetFunctionTokenUsage(SKContext result, SKContext chatContext, ILogger logger, string? functionName = null) + internal static void GetFunctionTokenUsage(FunctionResult result, SKContext chatContext, ILogger logger, string? functionName = null) { try { @@ -78,13 +80,14 @@ internal static void GetFunctionTokenUsage(SKContext result, SKContext chatConte return; } - if (result.ModelResults == null || result.ModelResults.Count == 0) + var modelResults = result.GetModelResults(); + if (modelResults.IsNullOrEmpty()) { logger.LogError("Unable to determine token usage for {0}", functionKey); return; } - var tokenUsage = result.ModelResults.First().GetResult().Usage.TotalTokens; + var tokenUsage = modelResults!.First().GetResult().Usage.TotalTokens; chatContext.Variables.Set(functionKey!, tokenUsage.ToString(CultureInfo.InvariantCulture)); } catch (Exception e)