diff --git a/.gitignore b/.gitignore
index 34fc91e88..5eebed827 100644
--- a/.gitignore
+++ b/.gitignore
@@ -429,8 +429,6 @@ FodyWeavers.xsd
certs/
# to make sure we don't commit local settings which might contain credentials
-launchSettings.json
-*launchSettings.json*
config.development.yaml
*.development.config
*.development.json
diff --git a/KernelMemory.sln b/KernelMemory.sln
index 16bbd4aee..b073a777d 100644
--- a/KernelMemory.sln
+++ b/KernelMemory.sln
@@ -108,7 +108,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "extensions", "extensions",
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{CA49F1A1-C3FA-4E99-ACB3-D7FF33D47976}"
ProjectSection(SolutionItems) = preProject
- tools\ask.sh = tools\ask.sh
tools\README.md = tools\README.md
tools\run-elasticsearch.sh = tools\run-elasticsearch.sh
tools\run-mongodb-atlas.sh = tools\run-mongodb-atlas.sh
@@ -117,10 +116,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{CA49F1A1
tools\run-rabbitmq.sh = tools\run-rabbitmq.sh
tools\run-redis.sh = tools\run-redis.sh
tools\run-s3ninja.sh = tools\run-s3ninja.sh
- tools\search.sh = tools\search.sh
- tools\upload-file.sh = tools\upload-file.sh
- tools\dockerize-amd64.sh = tools\dockerize-amd64.sh
- tools\dockerize-arm64.sh = tools\dockerize-arm64.sh
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Abstractions", "service\Abstractions\Abstractions.csproj", "{8A9FA587-7EBA-4D43-BE47-38D798B1C74C}"
@@ -339,6 +334,32 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tiktoken", "extensions\Tikt
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "303-dotnet-aspire", "examples\303-dotnet-aspire\303-dotnet-aspire.csproj", "{DD643765-8D45-4574-92C3-CBEF0C330242}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "aspire", "aspire", "{07A91D09-CA4D-425F-83AD-F955336AACD7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "all-azure", "tools\aspire\all-azure\all-azure.csproj", "{6E5EB6F3-17E2-4C71-B35A-5F8F0B7E407F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "volatile-openai", "tools\aspire\volatile-openai\volatile-openai.csproj", "{D81B99FF-E13D-4127-AC01-4BF0C8B02C71}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.Extensions", "tools\aspire\Aspire.Extensions\Aspire.Extensions.csproj", "{4E5BAA7B-7DB6-4F24-8D91-E9C3AC9773E7}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dev", "dev", "{3C1C483D-2C09-4B0D-9394-82B2AF1D61F1}"
+ ProjectSection(SolutionItems) = preProject
+ tools\dev\build.sh = tools\dev\build.sh
+ tools\dev\changes-since-last-release.sh = tools\dev\changes-since-last-release.sh
+ tools\dev\create-azure-webapp-publish-artifacts.sh = tools\dev\create-azure-webapp-publish-artifacts.sh
+ tools\dev\dockerize-amd64.sh = tools\dev\dockerize-amd64.sh
+ tools\dev\dockerize-arm64.sh = tools\dev\dockerize-arm64.sh
+ tools\dev\get-azure-token.py = tools\dev\get-azure-token.py
+ tools\dev\run-unit-tests.sh = tools\dev\run-unit-tests.sh
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "km-cli", "km-cli", "{239F5FE9-EAEE-4FA7-A3D5-09608FBA6EED}"
+ ProjectSection(SolutionItems) = preProject
+ tools\km-cli\ask.sh = tools\km-cli\ask.sh
+ tools\km-cli\search.sh = tools\km-cli\search.sh
+ tools\km-cli\upload-file.sh = tools\km-cli\upload-file.sh
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -634,6 +655,16 @@ Global
{DD643765-8D45-4574-92C3-CBEF0C330242}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DD643765-8D45-4574-92C3-CBEF0C330242}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DD643765-8D45-4574-92C3-CBEF0C330242}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6E5EB6F3-17E2-4C71-B35A-5F8F0B7E407F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6E5EB6F3-17E2-4C71-B35A-5F8F0B7E407F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6E5EB6F3-17E2-4C71-B35A-5F8F0B7E407F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D81B99FF-E13D-4127-AC01-4BF0C8B02C71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D81B99FF-E13D-4127-AC01-4BF0C8B02C71}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D81B99FF-E13D-4127-AC01-4BF0C8B02C71}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4E5BAA7B-7DB6-4F24-8D91-E9C3AC9773E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4E5BAA7B-7DB6-4F24-8D91-E9C3AC9773E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4E5BAA7B-7DB6-4F24-8D91-E9C3AC9773E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4E5BAA7B-7DB6-4F24-8D91-E9C3AC9773E7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -736,6 +767,14 @@ Global
{AF1E12A9-D8A1-4815-995E-C6F7B2022016} = {0A43C65C-6007-4BB4-B3FE-8D439FC91841}
{830C91B5-6F8D-4DAD-B1BD-3C2F9DEEC8F6} = {155DA079-E267-49AF-973A-D1D44681970F}
{DD643765-8D45-4574-92C3-CBEF0C330242} = {0A43C65C-6007-4BB4-B3FE-8D439FC91841}
+ {07A91D09-CA4D-425F-83AD-F955336AACD7} = {CA49F1A1-C3FA-4E99-ACB3-D7FF33D47976}
+ {6E5EB6F3-17E2-4C71-B35A-5F8F0B7E407F} = {07A91D09-CA4D-425F-83AD-F955336AACD7}
+ {D81B99FF-E13D-4127-AC01-4BF0C8B02C71} = {07A91D09-CA4D-425F-83AD-F955336AACD7}
+ {4E5BAA7B-7DB6-4F24-8D91-E9C3AC9773E7} = {07A91D09-CA4D-425F-83AD-F955336AACD7}
+ {3C1C483D-2C09-4B0D-9394-82B2AF1D61F1} = {CA49F1A1-C3FA-4E99-ACB3-D7FF33D47976}
+ {239F5FE9-EAEE-4FA7-A3D5-09608FBA6EED} = {CA49F1A1-C3FA-4E99-ACB3-D7FF33D47976}
+ {CA49F1A1-C3FA-4E99-ACB3-D7FF33D47976} = {6EF76FD8-4C35-4370-8539-5DDF45357A50}
+ {7BA7F1B2-19E2-46EB-B000-513EE2F65769} = {6EF76FD8-4C35-4370-8539-5DDF45357A50}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CC136C62-115C-41D1-B414-F9473EFF6EA8}
diff --git a/KernelMemory.sln.DotSettings b/KernelMemory.sln.DotSettings
index 56b15a2c0..afe4c4bcd 100644
--- a/KernelMemory.sln.DotSettings
+++ b/KernelMemory.sln.DotSettings
@@ -107,6 +107,7 @@
IOS
JSON
JWT
+ KM
MQ
MQTT
MS
diff --git a/README.md b/README.md
index cf6eb197b..ca9bce30a 100644
--- a/README.md
+++ b/README.md
@@ -235,7 +235,7 @@ which documents ground the response.
> ```
The OpenAPI schema ("swagger") is available at http://127.0.0.1:9001/swagger/index.html when
-running the service locally with OpenAPI enabled.
+running the service locally with OpenAPI enabled.
[Here's a copy](https://editor.swagger.io/?url=https://raw.githubusercontent.com/microsoft/kernel-memory/refs/heads/main/swagger.json).
@@ -471,9 +471,9 @@ Examples and Tools
## Tools
1. [.NET appsettings.json generator](tools/InteractiveSetup)
-2. [Curl script to upload files](tools/upload-file.sh)
-3. [Curl script to ask questions](tools/ask.sh)
-4. [Curl script to search documents](tools/search.sh)
+2. [Curl script to upload files](tools/km-cli/upload-file.sh)
+3. [Curl script to ask questions](tools/km-cli/ask.sh)
+4. [Curl script to search documents](tools/km-cli/search.sh)
5. [Script to start Qdrant for development tasks](tools/run-qdrant.sh)
6. [Script to start Elasticsearch for development tasks](tools/run-elasticsearch.sh)
7. [Script to start MS SQL Server for development tasks](tools/run-mssql.sh)
@@ -539,30 +539,30 @@ githubcontrib --repo kernel-memory --owner microsoft --showlogin true --sortBy l
:---: |:---: |:---: |:---: |:---: |:---: |
[aaronpowell](https://github.com/aaronpowell) |[afederici75](https://github.com/afederici75) |[akordowski](https://github.com/akordowski) |[alexibraimov](https://github.com/alexibraimov) |[alexmg](https://github.com/alexmg) |[alkampfergit](https://github.com/alkampfergit) |
-[
](https://github.com/amomra) |[
](https://github.com/anthonypuppo) |[
](https://github.com/chaelli) |[
](https://github.com/cherchyk) |[
](https://github.com/coryisakson) |[
](https://github.com/crickman) |
+[
](https://github.com/amomra) |[
](https://github.com/anthonypuppo) |[
](https://github.com/carlodek) |[
](https://github.com/chaelli) |[
](https://github.com/cherchyk) |[
](https://github.com/coryisakson) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[amomra](https://github.com/amomra) |[anthonypuppo](https://github.com/anthonypuppo) |[chaelli](https://github.com/chaelli) |[cherchyk](https://github.com/cherchyk) |[coryisakson](https://github.com/coryisakson) |[crickman](https://github.com/crickman) |
+[amomra](https://github.com/amomra) |[anthonypuppo](https://github.com/anthonypuppo) |[carlodek](https://github.com/carlodek) |[chaelli](https://github.com/chaelli) |[cherchyk](https://github.com/cherchyk) |[coryisakson](https://github.com/coryisakson) |
-[
](https://github.com/apps/dependabot) |[
](https://github.com/dluc) |[
](https://github.com/DM-98) |[
](https://github.com/EelcoKoster) |[
](https://github.com/Foorcee) |[
](https://github.com/GraemeJones104) |
+[
](https://github.com/crickman) |[
](https://github.com/apps/dependabot) |[
](https://github.com/dluc) |[
](https://github.com/DM-98) |[
](https://github.com/EelcoKoster) |[
](https://github.com/Foorcee) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[dependabot[bot]](https://github.com/apps/dependabot) |[dluc](https://github.com/dluc) |[DM-98](https://github.com/DM-98) |[EelcoKoster](https://github.com/EelcoKoster) |[Foorcee](https://github.com/Foorcee) |[GraemeJones104](https://github.com/GraemeJones104) |
+[crickman](https://github.com/crickman) |[dependabot[bot]](https://github.com/apps/dependabot) |[dluc](https://github.com/dluc) |[DM-98](https://github.com/DM-98) |[EelcoKoster](https://github.com/EelcoKoster) |[Foorcee](https://github.com/Foorcee) |
-[
](https://github.com/imranshams) |[
](https://github.com/jurepurgar) |[
](https://github.com/JustinRidings) |[
](https://github.com/kbeaugrand) |[
](https://github.com/koteus) |[
](https://github.com/KSemenenko) |
+[
](https://github.com/GraemeJones104) |[
](https://github.com/imranshams) |[
](https://github.com/jurepurgar) |[
](https://github.com/JustinRidings) |[
](https://github.com/kbeaugrand) |[
](https://github.com/koteus) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[imranshams](https://github.com/imranshams) |[jurepurgar](https://github.com/jurepurgar) |[JustinRidings](https://github.com/JustinRidings) |[kbeaugrand](https://github.com/kbeaugrand) |[koteus](https://github.com/koteus) |[KSemenenko](https://github.com/KSemenenko) |
+[GraemeJones104](https://github.com/GraemeJones104) |[imranshams](https://github.com/imranshams) |[jurepurgar](https://github.com/jurepurgar) |[JustinRidings](https://github.com/JustinRidings) |[kbeaugrand](https://github.com/kbeaugrand) |[koteus](https://github.com/koteus) |
-[
](https://github.com/lecramr) |[
](https://github.com/luismanez) |[
](https://github.com/marcominerva) |[
](https://github.com/neel015) |[
](https://github.com/pascalberger) |[
](https://github.com/pawarsum12) |
+[
](https://github.com/KSemenenko) |[
](https://github.com/lecramr) |[
](https://github.com/luismanez) |[
](https://github.com/marcominerva) |[
](https://github.com/neel015) |[
](https://github.com/pascalberger) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[lecramr](https://github.com/lecramr) |[luismanez](https://github.com/luismanez) |[marcominerva](https://github.com/marcominerva) |[neel015](https://github.com/neel015) |[pascalberger](https://github.com/pascalberger) |[pawarsum12](https://github.com/pawarsum12) |
+[KSemenenko](https://github.com/KSemenenko) |[lecramr](https://github.com/lecramr) |[luismanez](https://github.com/luismanez) |[marcominerva](https://github.com/marcominerva) |[neel015](https://github.com/neel015) |[pascalberger](https://github.com/pascalberger) |
-[
](https://github.com/pradeepr-roboticist) |[
](https://github.com/qihangnet) |[
](https://github.com/roldengarm) |[
](https://github.com/setuc) |[
](https://github.com/slapointe) |[
](https://github.com/slorello89) |
+[
](https://github.com/pawarsum12) |[
](https://github.com/pradeepr-roboticist) |[
](https://github.com/qihangnet) |[
](https://github.com/roldengarm) |[
](https://github.com/setuc) |[
](https://github.com/slapointe) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[pradeepr-roboticist](https://github.com/pradeepr-roboticist) |[qihangnet](https://github.com/qihangnet) |[roldengarm](https://github.com/roldengarm) |[setuc](https://github.com/setuc) |[slapointe](https://github.com/slapointe) |[slorello89](https://github.com/slorello89) |
+[pawarsum12](https://github.com/pawarsum12) |[pradeepr-roboticist](https://github.com/pradeepr-roboticist) |[qihangnet](https://github.com/qihangnet) |[roldengarm](https://github.com/roldengarm) |[setuc](https://github.com/setuc) |[slapointe](https://github.com/slapointe) |
-[
](https://github.com/snakex64) |[
](https://github.com/spenavajr) |[
](https://github.com/TaoChenOSU) |[
](https://github.com/teresaqhoang) |[
](https://github.com/tomasz-skarzynski) |[
](https://github.com/v-msamovendyuk) |
+[
](https://github.com/slorello89) |[
](https://github.com/snakex64) |[
](https://github.com/spenavajr) |[
](https://github.com/TaoChenOSU) |[
](https://github.com/teresaqhoang) |[
](https://github.com/tomasz-skarzynski) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[snakex64](https://github.com/snakex64) |[spenavajr](https://github.com/spenavajr) |[TaoChenOSU](https://github.com/TaoChenOSU) |[teresaqhoang](https://github.com/teresaqhoang) |[tomasz-skarzynski](https://github.com/tomasz-skarzynski) |[v-msamovendyuk](https://github.com/v-msamovendyuk) |
+[slorello89](https://github.com/slorello89) |[snakex64](https://github.com/snakex64) |[spenavajr](https://github.com/spenavajr) |[TaoChenOSU](https://github.com/TaoChenOSU) |[teresaqhoang](https://github.com/teresaqhoang) |[tomasz-skarzynski](https://github.com/tomasz-skarzynski) |
-[
](https://github.com/Valkozaur) |[
](https://github.com/vicperdana) |[
](https://github.com/walexee) |[
](https://github.com/westdavidr) |[
](https://github.com/xbotter) |
-:---: |:---: |:---: |:---: |:---: |
-[Valkozaur](https://github.com/Valkozaur) |[vicperdana](https://github.com/vicperdana) |[walexee](https://github.com/walexee) |[westdavidr](https://github.com/westdavidr) |[xbotter](https://github.com/xbotter) |
+[
](https://github.com/v-msamovendyuk) |[
](https://github.com/Valkozaur) |[
](https://github.com/vicperdana) |[
](https://github.com/walexee) |[
](https://github.com/westdavidr) |[
](https://github.com/xbotter) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[v-msamovendyuk](https://github.com/v-msamovendyuk) |[Valkozaur](https://github.com/Valkozaur) |[vicperdana](https://github.com/vicperdana) |[walexee](https://github.com/walexee) |[westdavidr](https://github.com/westdavidr) |[xbotter](https://github.com/xbotter) |
diff --git a/examples/302-dotnet-sk-km-chat/Properties/launchSettings.json.example b/examples/003-dotnet-SemanticKernel-plugin/Properties/launchSettings.json
similarity index 57%
rename from examples/302-dotnet-sk-km-chat/Properties/launchSettings.json.example
rename to examples/003-dotnet-SemanticKernel-plugin/Properties/launchSettings.json
index 423ee0064..dea57200c 100644
--- a/examples/302-dotnet-sk-km-chat/Properties/launchSettings.json.example
+++ b/examples/003-dotnet-SemanticKernel-plugin/Properties/launchSettings.json
@@ -1,11 +1,10 @@
{
"profiles": {
- "example302": {
+ "console": {
"commandName": "Project",
"launchBrowser": false,
"environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development",
- "OPENAI_APIKEY": ""
+ "ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
diff --git a/examples/004-dotnet-serverless-custom-pipeline/Properties/launchSettings.json b/examples/004-dotnet-serverless-custom-pipeline/Properties/launchSettings.json
new file mode 100644
index 000000000..dea57200c
--- /dev/null
+++ b/examples/004-dotnet-serverless-custom-pipeline/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/005-dotnet-async-memory-custom-pipeline/Properties/launchSettings.json b/examples/005-dotnet-async-memory-custom-pipeline/Properties/launchSettings.json
new file mode 100644
index 000000000..dea57200c
--- /dev/null
+++ b/examples/005-dotnet-async-memory-custom-pipeline/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/106-dotnet-retrieve-synthetics/Properties/launchSettings.json b/examples/106-dotnet-retrieve-synthetics/Properties/launchSettings.json
new file mode 100644
index 000000000..dea57200c
--- /dev/null
+++ b/examples/106-dotnet-retrieve-synthetics/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/107-dotnet-SemanticKernel-TextCompletion/Properties/launchSettings.json b/examples/107-dotnet-SemanticKernel-TextCompletion/Properties/launchSettings.json
new file mode 100644
index 000000000..dea57200c
--- /dev/null
+++ b/examples/107-dotnet-SemanticKernel-TextCompletion/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/109-dotnet-custom-webscraper/Properties/launchSettings.json b/examples/109-dotnet-custom-webscraper/Properties/launchSettings.json
new file mode 100644
index 000000000..8ea3fceb9
--- /dev/null
+++ b/examples/109-dotnet-custom-webscraper/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/examples/110-dotnet-anthropic/Properties/launchSettings.json b/examples/110-dotnet-anthropic/Properties/launchSettings.json
new file mode 100644
index 000000000..8ea3fceb9
--- /dev/null
+++ b/examples/110-dotnet-anthropic/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/examples/201-dotnet-serverless-custom-handler/Properties/launchSettings.json b/examples/201-dotnet-serverless-custom-handler/Properties/launchSettings.json
new file mode 100644
index 000000000..dea57200c
--- /dev/null
+++ b/examples/201-dotnet-serverless-custom-handler/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/202-dotnet-custom-handler-as-a-service/Properties/launchSettings.json b/examples/202-dotnet-custom-handler-as-a-service/Properties/launchSettings.json
new file mode 100644
index 000000000..dea57200c
--- /dev/null
+++ b/examples/202-dotnet-custom-handler-as-a-service/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/203-dotnet-using-KM-nuget/Properties/launchSettings.json b/examples/203-dotnet-using-KM-nuget/Properties/launchSettings.json
new file mode 100644
index 000000000..dea57200c
--- /dev/null
+++ b/examples/203-dotnet-using-KM-nuget/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/204-dotnet-ASP.NET-MVC-integration/Properties/launchSettings.json b/examples/204-dotnet-ASP.NET-MVC-integration/Properties/launchSettings.json
new file mode 100644
index 000000000..dea57200c
--- /dev/null
+++ b/examples/204-dotnet-ASP.NET-MVC-integration/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/208-dotnet-lmstudio/Properties/launchSettings.json b/examples/208-dotnet-lmstudio/Properties/launchSettings.json
new file mode 100644
index 000000000..dea57200c
--- /dev/null
+++ b/examples/208-dotnet-lmstudio/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/212-dotnet-ollama/Properties/launchSettings.json b/examples/212-dotnet-ollama/Properties/launchSettings.json
new file mode 100644
index 000000000..dea57200c
--- /dev/null
+++ b/examples/212-dotnet-ollama/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/302-dotnet-sk-km-chat/Properties/.gitignore b/examples/302-dotnet-sk-km-chat/Properties/.gitignore
deleted file mode 100644
index 417feb72a..000000000
--- a/examples/302-dotnet-sk-km-chat/Properties/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-launchSettings.json
-!launchSettings.json.example
diff --git a/examples/302-dotnet-sk-km-chat/Properties/launchSettings.json b/examples/302-dotnet-sk-km-chat/Properties/launchSettings.json
new file mode 100644
index 000000000..dea57200c
--- /dev/null
+++ b/examples/302-dotnet-sk-km-chat/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "console": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/303-dotnet-aspire/Properties/launchSettings.json b/examples/303-dotnet-aspire/Properties/launchSettings.json
new file mode 100644
index 000000000..78acf10fd
--- /dev/null
+++ b/examples/303-dotnet-aspire/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "https": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "applicationUrl": "https://localhost:30000;http://localhost:30001",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:30002",
+ "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:30003"
+ }
+ },
+ "http": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:30001",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:30002",
+ "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:30003"
+ }
+ }
+ }
+}
diff --git a/service/Abstractions/HTTP/SSE.cs b/service/Abstractions/HTTP/SSE.cs
index e6d9254fd..f9786d96b 100644
--- a/service/Abstractions/HTTP/SSE.cs
+++ b/service/Abstractions/HTTP/SSE.cs
@@ -34,8 +34,8 @@ public async static IAsyncEnumerable ParseStreamAsync(
buffer.Clear();
if (message.Trim() == DoneMessage) { yield break; }
- var memoryAnswer = ParseMessage(message);
- if (memoryAnswer != null) { yield return memoryAnswer; }
+ var value = ParseMessage(message);
+ if (value != null) { yield return value; }
}
else
{
@@ -49,8 +49,8 @@ public async static IAsyncEnumerable ParseStreamAsync(
string message = buffer.ToString();
if (message.Trim() == DoneMessage) { yield break; }
- var memoryAnswer = ParseMessage(message);
- if (memoryAnswer != null) { yield return memoryAnswer; }
+ var value = ParseMessage(message);
+ if (value != null) { yield return value; }
}
}
diff --git a/service/Core/Configuration/ConfigEnvVars.cs b/service/Core/Configuration/ConfigEnvVars.cs
new file mode 100644
index 000000000..eb4a6d2c2
--- /dev/null
+++ b/service/Core/Configuration/ConfigEnvVars.cs
@@ -0,0 +1,107 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Microsoft.KernelMemory.Configuration;
+
+public static class ConfigEnvVars
+{
+ ///
+ /// Generate env vars to override settings in appsettings.json
+ ///
+ /// Configuration settings
+ /// Namespace within the appsettings.json file
+ /// Environment variables
+ public static Dictionary GenerateEnvVarsFromObject(
+ object? source, params string[] parents)
+ {
+ if (source == null) { return new Dictionary(StringComparer.OrdinalIgnoreCase); }
+
+ var prefix = GetPrefix(parents);
+ return GenerateEnvVars(source, prefix);
+ }
+
+ ///
+ /// Generate env vars to override settings in appsettings.json,
+ /// ignoring defaults found in the type.
+ /// Note: defaults in appsettings.json might differ.
+ ///
+ /// Configuration settings
+ /// Namespace within the appsettings.json file
+ /// Environment variables
+ public static Dictionary GenerateEnvVarsFromObjectNoDefaults(
+ object? source, params string[] parents)
+ {
+ if (source == null) { return new Dictionary(StringComparer.OrdinalIgnoreCase); }
+
+ var variables = GenerateEnvVarsFromObject(source, parents);
+ var prefix = GetPrefix(parents);
+
+ var defaults = GenerateEnvVars(CreateInstanceOfSameType(source), prefix);
+ foreach (var pair in defaults)
+ {
+ if (variables.TryGetValue(pair.Key, out string? value) && value == pair.Value)
+ {
+ variables.Remove(pair.Key);
+ }
+ }
+
+ return variables;
+ }
+
+ private static string GetPrefix(params string[] parents)
+ {
+ return parents.Length > 0 ? string.Join("__", parents) + "__" : string.Empty;
+ }
+
+ private static Dictionary GenerateEnvVars(object source, string prefix)
+ {
+ var result = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ var objProperties = source.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
+
+ foreach (var property in objProperties)
+ {
+ var fullKey = $"{prefix}{property.Name}";
+ var value = property.GetValue(source);
+
+ if (value is IDictionary dictionary)
+ {
+ foreach (var key in dictionary.Keys)
+ {
+ if (dictionary[key] != null)
+ {
+ var dictKey = $"{fullKey}_{key}";
+ result[dictKey] = dictionary[key]?.ToString() ?? string.Empty;
+ }
+ }
+ }
+ else if (value is IEnumerable enumerable and not string)
+ {
+ int index = 0;
+ foreach (var item in enumerable)
+ {
+ var arrayKey = $"{fullKey}__{index}";
+ result[arrayKey] = item?.ToString() ?? string.Empty;
+ index++;
+ }
+ }
+ else if (value != null)
+ {
+ result[fullKey] = value.ToString() ?? string.Empty;
+ }
+ }
+
+ return result;
+ }
+
+ private static object CreateInstanceOfSameType(object source)
+ {
+ var type = source.GetType();
+ var result = Activator.CreateInstance(type);
+
+ return result ?? throw new InvalidOperationException($"Unable to create instance of type {type.FullName}");
+ }
+}
diff --git a/service/Service/.gitignore b/service/Service/.gitignore
new file mode 100644
index 000000000..5730a1951
--- /dev/null
+++ b/service/Service/.gitignore
@@ -0,0 +1,2 @@
+launchSettings.json
+*launchSettings.json*
diff --git a/service/Service/appsettings.json b/service/Service/appsettings.json
index db88ad35c..0a661d6c9 100644
--- a/service/Service/appsettings.json
+++ b/service/Service/appsettings.json
@@ -1,15 +1,5 @@
{
"AllowedHosts": "*",
- "Kestrel": {
- "Endpoints": {
- "Http": {
- "Url": "http://*:9001"
- }
- // "Https": {
- // "Url": "https://*:9002"
- // }
- }
- },
"Logging": {
"LogLevel": {
"Default": "Information",
@@ -276,6 +266,15 @@
"GlobalSafetyThreshold": 0.0,
"IgnoredWords": []
},
+ "AzureAIDocIntel": {
+ // "APIKey" or "AzureIdentity".
+ // AzureIdentity: use automatic AAD authentication mechanism. You can test locally
+ // using the env vars AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET.
+ "Auth": "AzureIdentity",
+ // Required when Auth == APIKey
+ "APIKey": "",
+ "Endpoint": ""
+ },
"AzureAISearch": {
// "ApiKey" or "AzureIdentity". For other options see .
// AzureIdentity: use automatic AAD authentication mechanism. You can test locally
@@ -298,15 +297,6 @@
// See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body
"UseStickySessions": false
},
- "AzureAIDocIntel": {
- // "APIKey" or "AzureIdentity".
- // AzureIdentity: use automatic AAD authentication mechanism. You can test locally
- // using the env vars AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET.
- "Auth": "AzureIdentity",
- // Required when Auth == APIKey
- "APIKey": "",
- "Endpoint": ""
- },
"AzureBlobs": {
// "ConnectionString" or "AzureIdentity". For other options see .
// AzureIdentity: use automatic AAD authentication mechanism. You can test locally
diff --git a/service/tests/Core.UnitTests/Configuration/ConfigEnvVarsTest.cs b/service/tests/Core.UnitTests/Configuration/ConfigEnvVarsTest.cs
new file mode 100644
index 000000000..cb6b84c60
--- /dev/null
+++ b/service/tests/Core.UnitTests/Configuration/ConfigEnvVarsTest.cs
@@ -0,0 +1,336 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Microsoft.KernelMemory;
+using Microsoft.KernelMemory.Configuration;
+using Microsoft.KernelMemory.DocumentStorage.DevTools;
+using Microsoft.KernelMemory.FileSystem.DevTools;
+using Microsoft.KernelMemory.MemoryStorage.DevTools;
+using Microsoft.KernelMemory.Pipeline.Queue.DevTools;
+using Microsoft.KernelMemory.Safety.AzureAIContentSafety;
+using Microsoft.KM.TestHelpers;
+using Xunit.Abstractions;
+
+namespace Microsoft.KM.Core.UnitTests.Configuration;
+
+public class ConfigEnvVarsTest : BaseUnitTestCase
+{
+ public ConfigEnvVarsTest(ITestOutputHelper output) : base(output)
+ {
+ }
+
+ [Fact]
+ public void ItIgnoresDefaultValues()
+ {
+ // Arrange
+ var target = new AzureAIContentSafetyConfig();
+
+ // Act
+ Dictionary result = ConfigEnvVars.GenerateEnvVarsFromObjectNoDefaults(
+ target, "KernelMemory", "Services", "AzureAIContentSafety");
+ foreach (var v in result) { Console.WriteLine($"{v.Key}: {v.Value}"); }
+
+ // Assert
+ Assert.Empty(result);
+ }
+
+ [Fact]
+ public void ItWorksForAzureAIContentSafetyConfig()
+ {
+ // Arrange
+ var target = new AzureAIContentSafetyConfig
+ {
+ Auth = AzureAIContentSafetyConfig.AuthTypes.APIKey,
+ Endpoint = "http://endpoint",
+ APIKey = "xyz",
+ GlobalSafetyThreshold = 0.35,
+ IgnoredWords = ["foo", "bar"]
+ };
+
+ // Act
+ Dictionary result = ConfigEnvVars.GenerateEnvVarsFromObject(
+ target, "KernelMemory", "Services", "AzureAIContentSafety");
+ foreach (var v in result) { Console.WriteLine($"{v.Key}: {v.Value}"); }
+
+ // Assert
+ Assert.Equal(6, result.Count);
+ Assert.Equal("APIKey", result["KernelMemory__Services__AzureAIContentSafety__Auth"]);
+ Assert.Equal("http://endpoint", result["KernelMemory__Services__AzureAIContentSafety__Endpoint"]);
+ Assert.Equal("xyz", result["KernelMemory__Services__AzureAIContentSafety__APIKey"]);
+ Assert.Equal("0.35", result["KernelMemory__Services__AzureAIContentSafety__GlobalSafetyThreshold"]);
+ Assert.Equal("foo", result["KernelMemory__Services__AzureAIContentSafety__IgnoredWords__0"]);
+ Assert.Equal("bar", result["KernelMemory__Services__AzureAIContentSafety__IgnoredWords__1"]);
+ }
+
+ [Fact]
+ public void ItWorksForAzureAIDocIntelConfig()
+ {
+ // Arrange
+ var target = new AzureAIDocIntelConfig
+ {
+ Auth = AzureAIDocIntelConfig.AuthTypes.APIKey,
+ Endpoint = "http://endpoint",
+ APIKey = "xyz",
+ };
+
+ // Act
+ Dictionary result = ConfigEnvVars.GenerateEnvVarsFromObject(
+ target, "KernelMemory", "Services", "AzureAIDocIntel");
+ foreach (var v in result) { Console.WriteLine($"{v.Key}: {v.Value}"); }
+
+ // Assert
+ Assert.Equal(3, result.Count);
+ Assert.Equal("APIKey", result["KernelMemory__Services__AzureAIDocIntel__Auth"]);
+ Assert.Equal("http://endpoint", result["KernelMemory__Services__AzureAIDocIntel__Endpoint"]);
+ Assert.Equal("xyz", result["KernelMemory__Services__AzureAIDocIntel__APIKey"]);
+ }
+
+ [Fact]
+ public void ItWorksForAzureAISearchConfig()
+ {
+ // Arrange
+ var target = new AzureAISearchConfig
+ {
+ Auth = AzureAISearchConfig.AuthTypes.APIKey,
+ Endpoint = "http://endpoint",
+ APIKey = "xyz",
+ UseHybridSearch = true,
+ UseStickySessions = true,
+ };
+
+ // Act
+ Dictionary result = ConfigEnvVars.GenerateEnvVarsFromObject(
+ target, "KernelMemory", "Services", "AzureAISearch");
+ foreach (var v in result) { Console.WriteLine($"{v.Key}: {v.Value}"); }
+
+ // Assert
+ Assert.Equal(5, result.Count);
+ Assert.Equal("APIKey", result["KernelMemory__Services__AzureAISearch__Auth"]);
+ Assert.Equal("http://endpoint", result["KernelMemory__Services__AzureAISearch__Endpoint"]);
+ Assert.Equal("xyz", result["KernelMemory__Services__AzureAISearch__APIKey"]);
+ Assert.Equal("True", result["KernelMemory__Services__AzureAISearch__UseHybridSearch"]);
+ Assert.Equal("True", result["KernelMemory__Services__AzureAISearch__UseStickySessions"]);
+ }
+
+ [Fact]
+ public void ItWorksForAzureBlobsConfig()
+ {
+ // Arrange
+ var target = new AzureBlobsConfig
+ {
+ Auth = AzureBlobsConfig.AuthTypes.ConnectionString,
+ ConnectionString = "http://endpoint",
+ Account = "acct",
+ AccountKey = "acctKey",
+ Container = "container name",
+ EndpointSuffix = "sfx",
+ };
+
+ // Act
+ Dictionary result = ConfigEnvVars.GenerateEnvVarsFromObject(
+ target, "KernelMemory", "Services", "AzureBlobs");
+ foreach (var v in result) { Console.WriteLine($"{v.Key}: {v.Value}"); }
+
+ // Assert
+ Assert.Equal(6, result.Count);
+ Assert.Equal("ConnectionString", result["KernelMemory__Services__AzureBlobs__Auth"]);
+ Assert.Equal("http://endpoint", result["KernelMemory__Services__AzureBlobs__ConnectionString"]);
+ Assert.Equal("acct", result["KernelMemory__Services__AzureBlobs__Account"]);
+ Assert.Equal("acctKey", result["KernelMemory__Services__AzureBlobs__AccountKey"]);
+ Assert.Equal("container name", result["KernelMemory__Services__AzureBlobs__Container"]);
+ Assert.Equal("sfx", result["KernelMemory__Services__AzureBlobs__EndpointSuffix"]);
+ }
+
+ [Fact]
+ public void ItWorksForAzureOpenAIConfig()
+ {
+ // Arrange
+ var target = new AzureOpenAIConfig
+ {
+ APIType = AzureOpenAIConfig.APITypes.ChatCompletion,
+ Auth = AzureOpenAIConfig.AuthTypes.APIKey,
+ APIKey = "x y z",
+ Endpoint = "http://endpoint",
+ Deployment = "gpt",
+ MaxTokenTotal = 9000,
+ Tokenizer = "o200k",
+ EmbeddingDimensions = 1000,
+ MaxEmbeddingBatchSize = 10,
+ MaxRetries = 5,
+ TrustedCertificateThumbprints = ["abc", "bb"],
+ };
+
+ // Act
+ Dictionary result = ConfigEnvVars.GenerateEnvVarsFromObject(
+ target, "KernelMemory", "Services", "AzureOpenAIxyz");
+ foreach (var v in result) { Console.WriteLine($"{v.Key}: {v.Value}"); }
+
+ // Assert
+ Assert.Equal(12, result.Count);
+ Assert.Equal("ChatCompletion", result["KernelMemory__Services__AzureOpenAIxyz__APIType"]);
+ Assert.Equal("APIKey", result["KernelMemory__Services__AzureOpenAIxyz__Auth"]);
+ Assert.Equal("http://endpoint", result["KernelMemory__Services__AzureOpenAIxyz__Endpoint"]);
+ Assert.Equal("gpt", result["KernelMemory__Services__AzureOpenAIxyz__Deployment"]);
+ Assert.Equal("9000", result["KernelMemory__Services__AzureOpenAIxyz__MaxTokenTotal"]);
+ Assert.Equal("o200k", result["KernelMemory__Services__AzureOpenAIxyz__Tokenizer"]);
+ Assert.Equal("1000", result["KernelMemory__Services__AzureOpenAIxyz__EmbeddingDimensions"]);
+ Assert.Equal("10", result["KernelMemory__Services__AzureOpenAIxyz__MaxEmbeddingBatchSize"]);
+ Assert.Equal("5", result["KernelMemory__Services__AzureOpenAIxyz__MaxRetries"]);
+ Assert.Equal("abc", result["KernelMemory__Services__AzureOpenAIxyz__TrustedCertificateThumbprints__0"]);
+ Assert.Equal("bb", result["KernelMemory__Services__AzureOpenAIxyz__TrustedCertificateThumbprints__1"]);
+ }
+
+ [Fact]
+ public void ItWorksForAzureQueuesConfig()
+ {
+ // Arrange
+ var target = new AzureQueuesConfig
+ {
+ Auth = AzureQueuesConfig.AuthTypes.ConnectionString,
+ ConnectionString = "http://endpoint",
+ Account = "acct",
+ AccountKey = "acctKey",
+ EndpointSuffix = "sfx",
+ PollDelayMsecs = 5,
+ FetchBatchSize = 6,
+ FetchLockSeconds = 7,
+ MaxRetriesBeforePoisonQueue = 8,
+ PoisonQueueSuffix = "dl",
+ };
+
+ // Act
+ Dictionary result = ConfigEnvVars.GenerateEnvVarsFromObject(
+ target, "KernelMemory", "Services", "AzureQueues");
+ foreach (var v in result) { Console.WriteLine($"{v.Key}: {v.Value}"); }
+
+ // Assert
+ Assert.Equal(10, result.Count);
+ Assert.Equal("ConnectionString", result["KernelMemory__Services__AzureQueues__Auth"]);
+ Assert.Equal("http://endpoint", result["KernelMemory__Services__AzureQueues__ConnectionString"]);
+ Assert.Equal("acct", result["KernelMemory__Services__AzureQueues__Account"]);
+ Assert.Equal("acctKey", result["KernelMemory__Services__AzureQueues__AccountKey"]);
+ Assert.Equal("sfx", result["KernelMemory__Services__AzureQueues__EndpointSuffix"]);
+ Assert.Equal("5", result["KernelMemory__Services__AzureQueues__PollDelayMsecs"]);
+ Assert.Equal("6", result["KernelMemory__Services__AzureQueues__FetchBatchSize"]);
+ Assert.Equal("7", result["KernelMemory__Services__AzureQueues__FetchLockSeconds"]);
+ Assert.Equal("8", result["KernelMemory__Services__AzureQueues__MaxRetriesBeforePoisonQueue"]);
+ Assert.Equal("dl", result["KernelMemory__Services__AzureQueues__PoisonQueueSuffix"]);
+ }
+
+ [Fact]
+ public void ItWorksForOpenAIConfig()
+ {
+ // Arrange
+ var target = new OpenAIConfig
+ {
+ TextGenerationType = OpenAIConfig.TextGenerationTypes.Chat,
+ APIKey = "key",
+ OrgId = "org",
+ Endpoint = "openai.com",
+ TextModel = "dv",
+ TextModelMaxTokenTotal = 100,
+ TextModelTokenizer = "o200k",
+ EmbeddingModel = "ada",
+ EmbeddingModelMaxTokenTotal = 200,
+ EmbeddingModelTokenizer = "cl100k",
+ EmbeddingDimensions = 444,
+ MaxEmbeddingBatchSize = 20,
+ MaxRetries = 8
+ };
+
+ // Act
+ Dictionary result = ConfigEnvVars.GenerateEnvVarsFromObject(
+ target, "KernelMemory", "Services", "OpenAI");
+ foreach (var v in result) { Console.WriteLine($"{v.Key}: {v.Value}"); }
+
+ // Assert
+ Assert.Equal(13, result.Count);
+ Assert.Equal("Chat", result["KernelMemory__Services__OpenAI__TextGenerationType"]);
+ Assert.Equal("key", result["KernelMemory__Services__OpenAI__APIKey"]);
+ Assert.Equal("org", result["KernelMemory__Services__OpenAI__OrgId"]);
+ Assert.Equal("openai.com", result["KernelMemory__Services__OpenAI__Endpoint"]);
+ Assert.Equal("dv", result["KernelMemory__Services__OpenAI__TextModel"]);
+ Assert.Equal("100", result["KernelMemory__Services__OpenAI__TextModelMaxTokenTotal"]);
+ Assert.Equal("o200k", result["KernelMemory__Services__OpenAI__TextModelTokenizer"]);
+ Assert.Equal("ada", result["KernelMemory__Services__OpenAI__EmbeddingModel"]);
+ Assert.Equal("200", result["KernelMemory__Services__OpenAI__EmbeddingModelMaxTokenTotal"]);
+ Assert.Equal("cl100k", result["KernelMemory__Services__OpenAI__EmbeddingModelTokenizer"]);
+ Assert.Equal("444", result["KernelMemory__Services__OpenAI__EmbeddingDimensions"]);
+ Assert.Equal("20", result["KernelMemory__Services__OpenAI__MaxEmbeddingBatchSize"]);
+ Assert.Equal("8", result["KernelMemory__Services__OpenAI__MaxRetries"]);
+ }
+
+ [Fact]
+ public void ItWorksForSimpleFileStorageConfig()
+ {
+ // Arrange
+ var target = new SimpleFileStorageConfig
+ {
+ StorageType = FileSystemTypes.Disk,
+ Directory = "c:/"
+ };
+
+ // Act
+ Dictionary result = ConfigEnvVars.GenerateEnvVarsFromObject(
+ target, "KernelMemory", "Services", "SimpleFileStorage");
+ foreach (var v in result) { Console.WriteLine($"{v.Key}: {v.Value}"); }
+
+ // Assert
+ Assert.Equal(2, result.Count);
+ Assert.Equal("Disk", result["KernelMemory__Services__SimpleFileStorage__StorageType"]);
+ Assert.Equal("c:/", result["KernelMemory__Services__SimpleFileStorage__Directory"]);
+ }
+
+ [Fact]
+ public void ItWorksForSimpleVectorDbConfig()
+ {
+ // Arrange
+ var target = new SimpleVectorDbConfig
+ {
+ StorageType = FileSystemTypes.Disk,
+ Directory = "c:/"
+ };
+
+ // Act
+ Dictionary result = ConfigEnvVars.GenerateEnvVarsFromObject(
+ target, "KernelMemory", "Services", "SimpleVectorDb");
+ foreach (var v in result) { Console.WriteLine($"{v.Key}: {v.Value}"); }
+
+ // Assert
+ Assert.Equal(2, result.Count);
+ Assert.Equal("Disk", result["KernelMemory__Services__SimpleVectorDb__StorageType"]);
+ Assert.Equal("c:/", result["KernelMemory__Services__SimpleVectorDb__Directory"]);
+ }
+
+ [Fact]
+ public void ItWorksForSimpleQueuesConfig()
+ {
+ // Arrange
+ var target = new SimpleQueuesConfig
+ {
+ StorageType = FileSystemTypes.Disk,
+ Directory = "c:/",
+ PollDelayMsecs = 1,
+ DispatchFrequencyMsecs = 2,
+ FetchBatchSize = 3,
+ FetchLockSeconds = 4,
+ MaxRetriesBeforePoisonQueue = 5,
+ PoisonQueueSuffix = "dl"
+ };
+
+ // Act
+ Dictionary result = ConfigEnvVars.GenerateEnvVarsFromObject(
+ target, "KernelMemory", "Services", "SimpleQueues");
+ foreach (var v in result) { Console.WriteLine($"{v.Key}: {v.Value}"); }
+
+ // Assert
+ Assert.Equal(8, result.Count);
+ Assert.Equal("Disk", result["KernelMemory__Services__SimpleQueues__StorageType"]);
+ Assert.Equal("c:/", result["KernelMemory__Services__SimpleQueues__Directory"]);
+ Assert.Equal("1", result["KernelMemory__Services__SimpleQueues__PollDelayMsecs"]);
+ Assert.Equal("2", result["KernelMemory__Services__SimpleQueues__DispatchFrequencyMsecs"]);
+ Assert.Equal("3", result["KernelMemory__Services__SimpleQueues__FetchBatchSize"]);
+ Assert.Equal("4", result["KernelMemory__Services__SimpleQueues__FetchLockSeconds"]);
+ Assert.Equal("5", result["KernelMemory__Services__SimpleQueues__MaxRetriesBeforePoisonQueue"]);
+ Assert.Equal("dl", result["KernelMemory__Services__SimpleQueues__PoisonQueueSuffix"]);
+ }
+}
diff --git a/tools/AzureBlobUpload/Properties/launchSettings.json.example b/tools/AzureBlobUpload/Properties/launchSettings.json.example
new file mode 100644
index 000000000..836b15a7b
--- /dev/null
+++ b/tools/AzureBlobUpload/Properties/launchSettings.json.example
@@ -0,0 +1,15 @@
+{
+ "profiles": {
+ "run": {
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "BLOB_CONN_STRING": "DefaultEndpointsProtocol=https;AccountName=...FOO...;AccountKey=...KEY...;EndpointSuffix=core.windows.net",
+ "BLOB_CONTAINER": "...NAME...",
+ "BLOB_PATH": "/",
+ "DOCUMENT_ID": "...NAME..."
+ },
+ "commandName": "Project",
+ "launchBrowser": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/README.md b/tools/README.md
index a3865e77d..6b772dbaa 100644
--- a/tools/README.md
+++ b/tools/README.md
@@ -1,33 +1,41 @@
-# Kernel memory web service scripts
+# Tools
-### upload-file.sh
+This folder contains a list of various tools used during development.
+
+- `aspire` folder: some .NET Aspire configurations
+- `dev` folder: build, test, release scripts
+- `InteractiveSetup` folder: project used to generate/update `appsettings.development.json` files
+
+# Kernel Memory from CLI
+
+### km-cli/upload-file.sh
Simple client for command line uploads to Kernel Memory.
Instructions:
```bash
-./upload-file.sh -h
+./km-cli/upload-file.sh -h
```
-### ask.sh
+### km-cli/ask.sh
Simple client for asking questions about your documents from the command line.
Instructions:
```bash
-./ask.sh -h
+./km-cli/ask.sh -h
```
-### search.sh
+### km-cli/search.sh
Simple client for searching your indexed documents from the command line.
Instructions:
```bash
-./search.sh -h
+./km-cli/search.sh -h
```
# Vector DB scripts
diff --git a/tools/aspire/Aspire.Extensions/Aspire.Extensions.csproj b/tools/aspire/Aspire.Extensions/Aspire.Extensions.csproj
new file mode 100644
index 000000000..060b77dbb
--- /dev/null
+++ b/tools/aspire/Aspire.Extensions/Aspire.Extensions.csproj
@@ -0,0 +1,22 @@
+
+
+
+ net8.0
+ enable
+ enable
+ Microsoft.KernelMemory.Aspire
+ Microsoft.KernelMemory.Aspire
+ false
+ $(NoWarn);IDE0058;IDE0160;IDE0008;
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/aspire/Aspire.Extensions/AspireExtensions.cs b/tools/aspire/Aspire.Extensions/AspireExtensions.cs
new file mode 100644
index 000000000..d09341b50
--- /dev/null
+++ b/tools/aspire/Aspire.Extensions/AspireExtensions.cs
@@ -0,0 +1,123 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Microsoft.KernelMemory.Configuration;
+
+namespace Microsoft.KernelMemory.Aspire;
+
+public static class AspireExtensions
+{
+ public static IResourceBuilder WithKmServiceConfig(
+ this IResourceBuilder builder, string serviceName, object config)
+ where T : IResourceWithEnvironment
+ {
+ return builder.WithKmConfig(config, "KernelMemory", "Services", serviceName);
+ }
+
+ public static IResourceBuilder WithKmConfig(
+ this IResourceBuilder builder, object config, params string[] parents)
+ where T : IResourceWithEnvironment
+ {
+ Dictionary result = ConfigEnvVars.GenerateEnvVarsFromObject(config, parents);
+ foreach (var v in result)
+ {
+ builder.WithEnvironment(v.Key, v.Value);
+ }
+
+ return builder;
+ }
+
+ public static IResourceBuilder WithKmTextEmbeddingGenerationEnvironment(
+ this IResourceBuilder builder, string? serviceName, object? config = null)
+ where T : IResourceWithEnvironment
+ {
+ builder
+ .WithEnvironment("KernelMemory__DataIngestion__EmbeddingGeneratorTypes__0", serviceName ?? "")
+ .WithEnvironment("KernelMemory__Retrieval__EmbeddingGeneratorType", serviceName ?? "");
+ if (serviceName != null && config != null)
+ {
+ builder.WithKmServiceConfig(serviceName, config);
+ }
+
+ return builder;
+ }
+
+ public static IResourceBuilder WithKmTextGenerationEnvironment(
+ this IResourceBuilder builder, string? serviceName, object? config = null)
+ where T : IResourceWithEnvironment
+ {
+ builder.WithEnvironment("KernelMemory__TextGeneratorType", serviceName ?? "");
+ if (serviceName != null && config != null)
+ {
+ builder.WithKmServiceConfig(serviceName, config);
+ }
+
+ return builder;
+ }
+
+ public static IResourceBuilder WithKmDocumentStorageEnvironment(
+ this IResourceBuilder builder, string? serviceName, object? config = null)
+ where T : IResourceWithEnvironment
+ {
+ builder.WithEnvironment("KernelMemory__DocumentStorageType", serviceName ?? "");
+ if (serviceName != null && config != null)
+ {
+ builder.WithKmServiceConfig(serviceName, config);
+ }
+
+ return builder;
+ }
+
+ public static IResourceBuilder WithKmMemoryDbEnvironment(
+ this IResourceBuilder builder, string? serviceName, object? config = null)
+ where T : IResourceWithEnvironment
+ {
+ builder
+ .WithEnvironment("KernelMemory__DataIngestion__MemoryDbTypes__0", serviceName ?? "")
+ .WithEnvironment("KernelMemory__Retrieval__MemoryDbType", serviceName ?? "");
+ if (serviceName != null && config != null)
+ {
+ builder.WithKmServiceConfig(serviceName, config);
+ }
+
+ return builder;
+ }
+
+ public static IResourceBuilder WithKmOrchestrationEnvironment(
+ this IResourceBuilder builder, string? serviceName, object? config = null)
+ where T : IResourceWithEnvironment
+ {
+ builder.WithEnvironment("KernelMemory__DataIngestion__DistributedOrchestration__QueueType", serviceName ?? "");
+ if (serviceName != null && config != null)
+ {
+ builder.WithKmServiceConfig(serviceName, config);
+ }
+
+ return builder;
+ }
+
+ public static IResourceBuilder WithKmContentSafetyModerationEnvironment(
+ this IResourceBuilder builder, string? serviceName, object? config = null)
+ where T : IResourceWithEnvironment
+ {
+ builder.WithEnvironment("KernelMemory__ContentModerationType", serviceName ?? "");
+ if (serviceName != null && config != null)
+ {
+ builder.WithKmServiceConfig(serviceName, config);
+ }
+
+ return builder;
+ }
+
+ public static IResourceBuilder WithKmOcrEnvironment(
+ this IResourceBuilder builder, string? serviceName, object? config = null)
+ where T : IResourceWithEnvironment
+ {
+ builder.WithEnvironment("KernelMemory__DataIngestion__ImageOcrType", serviceName ?? "");
+ if (serviceName != null && config != null)
+ {
+ builder.WithKmServiceConfig(serviceName, config);
+ }
+
+ return builder;
+ }
+}
diff --git a/tools/aspire/all-azure/Program.cs b/tools/aspire/all-azure/Program.cs
new file mode 100644
index 000000000..708163472
--- /dev/null
+++ b/tools/aspire/all-azure/Program.cs
@@ -0,0 +1,55 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Microsoft.KernelMemory.Safety.AzureAIContentSafety;
+using Projects;
+
+namespace Microsoft.KernelMemory.Aspire.AppHost;
+
+internal static class Program
+{
+ private static readonly AzureAIContentSafetyConfig s_azureAIContentSafetyConfig = new();
+ private static readonly AzureAIDocIntelConfig s_azureAIDocIntelConfig = new();
+ private static readonly AzureAISearchConfig s_azureAISearchConfig = new();
+ private static readonly AzureBlobsConfig s_azureBlobsConfig = new();
+ private static readonly AzureOpenAIConfig s_azureOpenAIEmbeddingConfig = new();
+ private static readonly AzureOpenAIConfig s_azureOpenAITextConfig = new();
+ private static readonly AzureQueuesConfig s_azureQueuesConfig = new();
+
+ internal static void Main()
+ {
+ new ConfigurationBuilder()
+ .AddJsonFile("appsettings.json")
+ .AddJsonFile("appsettings.development.json", optional: true)
+ .AddJsonFile("appsettings.Development.json", optional: true)
+ .Build()
+ .BindSection("KernelMemory:Services:AzureAIContentSafety", s_azureAIContentSafetyConfig)
+ .BindSection("KernelMemory:Services:AzureAIDocIntel", s_azureAIDocIntelConfig)
+ .BindSection("KernelMemory:Services:AzureAISearch", s_azureAISearchConfig)
+ .BindSection("KernelMemory:Services:AzureBlobs", s_azureBlobsConfig)
+ .BindSection("KernelMemory:Services:AzureOpenAIEmbedding", s_azureOpenAIEmbeddingConfig)
+ .BindSection("KernelMemory:Services:AzureOpenAIText", s_azureOpenAITextConfig)
+ .BindSection("KernelMemory:Services:AzureQueues", s_azureQueuesConfig);
+
+ RunFromCode();
+ }
+
+ private static void RunFromCode()
+ {
+ var builder = DistributedApplication.CreateBuilder();
+
+ builder.AddProject("kernel-memory")
+ .WithHttpEndpoint(targetPort: 20001)
+ .WithEnvironment("ASPNETCORE_URLS", "http://+:20001")
+ .WithEnvironment("ASPNETCORE_ENVIRONMENT", "Development")
+ .WithEnvironment("KernelMemory__Service__OpenApiEnabled", "True")
+ .WithKmTextEmbeddingGenerationEnvironment("AzureOpenAIEmbedding", s_azureOpenAIEmbeddingConfig)
+ .WithKmTextGenerationEnvironment("AzureOpenAIText", s_azureOpenAITextConfig)
+ .WithKmMemoryDbEnvironment("AzureAISearch", s_azureAISearchConfig)
+ .WithKmOrchestrationEnvironment("AzureQueues", s_azureQueuesConfig)
+ .WithKmDocumentStorageEnvironment("AzureBlobs", s_azureBlobsConfig)
+ .WithKmContentSafetyModerationEnvironment("AzureAIContentSafety", s_azureAIContentSafetyConfig)
+ .WithKmOcrEnvironment("AzureAIDocIntel", s_azureAIDocIntelConfig);
+
+ builder.Build().Run();
+ }
+}
diff --git a/tools/aspire/all-azure/Properties/launchSettings.json b/tools/aspire/all-azure/Properties/launchSettings.json
new file mode 100644
index 000000000..72bdeb8df
--- /dev/null
+++ b/tools/aspire/all-azure/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "https": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "applicationUrl": "https://localhost:20100;http://localhost:20101",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:20102",
+ "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:20103"
+ }
+ },
+ "http": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:20101",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:20102",
+ "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20103"
+ }
+ }
+ }
+}
diff --git a/tools/aspire/all-azure/all-azure.csproj b/tools/aspire/all-azure/all-azure.csproj
new file mode 100644
index 000000000..3e837fe47
--- /dev/null
+++ b/tools/aspire/all-azure/all-azure.csproj
@@ -0,0 +1,26 @@
+
+
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ true
+ Microsoft.KernelMemory.Aspire.AppHost
+ $(NoWarn);IDE0058;IDE0160;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/aspire/all-azure/appsettings.json b/tools/aspire/all-azure/appsettings.json
new file mode 100644
index 000000000..ae8033834
--- /dev/null
+++ b/tools/aspire/all-azure/appsettings.json
@@ -0,0 +1,151 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning",
+ "Aspire.Hosting.Dcp": "Warning"
+ }
+ },
+ "KernelMemory": {
+ "Services": {
+ "AzureAIContentSafety": {
+ // "ApiKey" or "AzureIdentity". For other options see .
+ // AzureIdentity: use automatic AAD authentication mechanism. You can test locally
+ // using the env vars AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET.
+ "Auth": "AzureIdentity",
+ "Endpoint": "https://<...>",
+ "APIKey": "",
+ "GlobalSafetyThreshold": 0.0,
+ "IgnoredWords": []
+ },
+ "AzureAISearch": {
+ // "ApiKey" or "AzureIdentity". For other options see .
+ // AzureIdentity: use automatic AAD authentication mechanism. You can test locally
+ // using the env vars AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET.
+ "Auth": "AzureIdentity",
+ "Endpoint": "https://<...>",
+ "APIKey": "",
+ // Hybrid search is not enabled by default. Note that when using hybrid search
+ // relevance scores are different, usually lower, than when using just vector search
+ "UseHybridSearch": false,
+ // Helps improve relevance score consistency for search services with multiple replicas by
+ // attempting to route a given request to the same replica for that session. Use this when
+ // favoring consistent scoring over lower latency. Can adversely affect performance.
+ //
+ // Whether to use sticky sessions, which can help getting more consistent results.
+ // When using sticky sessions, a best-effort attempt will be made to target the same replica set.
+ // Be wary that reusing the same replica repeatedly can interfere with the load balancing of
+ // the requests across replicas and adversely affect the performance of the search service.
+ //
+ // See https://learn.microsoft.com/rest/api/searchservice/documents/search-post?view=rest-searchservice-2024-07-01&tabs=HTTP#request-body
+ "UseStickySessions": false
+ },
+ "AzureAIDocIntel": {
+ // "APIKey" or "AzureIdentity".
+ // AzureIdentity: use automatic AAD authentication mechanism. You can test locally
+ // using the env vars AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET.
+ "Auth": "AzureIdentity",
+ // Required when Auth == APIKey
+ "APIKey": "",
+ "Endpoint": ""
+ },
+ "AzureBlobs": {
+ // "ConnectionString" or "AzureIdentity". For other options see .
+ // AzureIdentity: use automatic AAD authentication mechanism. You can test locally
+ // using the env vars AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET.
+ "Auth": "AzureIdentity",
+ // Azure Storage account name, required when using AzureIdentity auth
+ // Note: you can use an env var 'KernelMemory__Services__AzureBlobs__Account' to set this
+ "Account": "",
+ // Container where to create directories and upload files
+ "Container": "smemory",
+ // Required when Auth == ConnectionString
+ // Note: you can use an env var 'KernelMemory__Services__AzureBlobs__ConnectionString' to set this
+ "ConnectionString": "",
+ // Setting used only for country clouds
+ "EndpointSuffix": "core.windows.net"
+ },
+ "AzureOpenAIEmbedding": {
+ // "ApiKey" or "AzureIdentity"
+ // AzureIdentity: use automatic AAD authentication mechanism. You can test locally
+ // using the env vars AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET.
+ "Auth": "AzureIdentity",
+ "Endpoint": "https://<...>.openai.azure.com/",
+ "APIKey": "",
+ // Your Azure Deployment name
+ "Deployment": "",
+ // The max number of tokens supported by model deployed
+ // See https://learn.microsoft.com/azure/ai-services/openai/concepts/models
+ "MaxTokenTotal": 8191,
+ // Which tokenizer to use to correctly measure the size of chunks.
+ // Supported values: "p50k", "cl100k", "o200k". Leave it empty if unsure.
+ // - Use p50k for the old text-davinci-003 models
+ // - Use cl100k for the old gpt-3.4 and gpt-4 family, and for text embedding models
+ // - Use o200k for the most recent gpt-4o family
+ "Tokenizer": "cl100k",
+ // The number of dimensions output embeddings should have.
+ // Only supported in "text-embedding-3" and later models developed with
+ // MRL, see https://arxiv.org/abs/2205.13147
+ "EmbeddingDimensions": null,
+ // How many embeddings to calculate in parallel. The max value depends on
+ // the model and deployment in use.
+ // See https://learn.microsoft.com/azure/ai-services/openai/reference#embeddings
+ "MaxEmbeddingBatchSize": 1,
+ // How many times to retry in case of throttling.
+ "MaxRetries": 10,
+ // Thumbprints of certificates that should be trusted for HTTPS requests when SSL policy errors are detected.
+ // This should only be used for local development when using a proxy to call the OpenAI endpoints.
+ "TrustedCertificateThumbprints": []
+ },
+ "AzureOpenAIText": {
+ // "ApiKey" or "AzureIdentity"
+ // AzureIdentity: use automatic AAD authentication mechanism. You can test locally
+ // using the env vars AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET.
+ "Auth": "AzureIdentity",
+ "Endpoint": "https://<...>.openai.azure.com/",
+ "APIKey": "",
+ "Deployment": "",
+ // The max number of tokens supported by model deployed
+ // See https://learn.microsoft.com/azure/ai-services/openai/concepts/models
+ "MaxTokenTotal": 16384,
+ // Which tokenizer to use to correctly measure the size of chunks.
+ // Supported values: "p50k", "cl100k", "o200k". Leave it empty if unsure.
+ // - Use p50k for the old text-davinci-003 models
+ // - Use cl100k for the old gpt-3.4 and gpt-4 family, and for text embedding models
+ // - Use o200k for the most recent gpt-4o family
+ "Tokenizer": "o200k",
+ // "ChatCompletion" or "TextCompletion"
+ "APIType": "ChatCompletion",
+ // How many times to retry in case of throttling.
+ "MaxRetries": 10,
+ // Thumbprints of certificates that should be trusted for HTTPS requests when SSL policy errors are detected.
+ // This should only be used for local development when using a proxy to call the OpenAI endpoints.
+ "TrustedCertificateThumbprints": []
+ },
+ "AzureQueues": {
+ // "ConnectionString" or "AzureIdentity". For other options see .
+ // AzureIdentity: use automatic AAD authentication mechanism. You can test locally
+ // using the env vars AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET.
+ "Auth": "AzureIdentity",
+ // Azure Storage account name, required when using AzureIdentity auth
+ // Note: you can use an env var 'KernelMemory__Services__AzureQueue__Account' to set this
+ "Account": "",
+ // Required when Auth == ConnectionString
+ // Note: you can use an env var 'KernelMemory__Services__AzureQueue__ConnectionString' to set this
+ "ConnectionString": "",
+ // Setting used only for country clouds
+ "EndpointSuffix": "core.windows.net",
+ // How often to check if there are new messages
+ "PollDelayMsecs": 100,
+ // How many messages to fetch at a time
+ "FetchBatchSize": 3,
+ // How long to lock messages once fetched. Azure Queue default is 30 secs
+ "FetchLockSeconds": 300,
+ // How many times to dequeue a messages and process before moving it to a poison queue
+ "MaxRetriesBeforePoisonQueue": 20,
+ // Suffix used for the poison queues.
+ "PoisonQueueSuffix": "-poison"
+ }
+ }
+ }
+}
diff --git a/tools/aspire/all-azure/run.sh b/tools/aspire/all-azure/run.sh
new file mode 100755
index 000000000..fb33b2f3e
--- /dev/null
+++ b/tools/aspire/all-azure/run.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+set -e
+
+cd "$(dirname "${BASH_SOURCE[0]:-$0}")"
+
+ASPNETCORE_ENVIRONMENT=Development dotnet run
diff --git a/tools/aspire/volatile-openai/Program.cs b/tools/aspire/volatile-openai/Program.cs
new file mode 100644
index 000000000..5891970d6
--- /dev/null
+++ b/tools/aspire/volatile-openai/Program.cs
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Microsoft.KernelMemory.DocumentStorage.DevTools;
+using Microsoft.KernelMemory.MemoryStorage.DevTools;
+using Microsoft.KernelMemory.Pipeline.Queue.DevTools;
+using Projects;
+
+namespace Microsoft.KernelMemory.Aspire.AppHost;
+
+// Run KM in volatile mode, with OpenAI models
+internal static class Program
+{
+ private static readonly SimpleFileStorageConfig s_simpleFileStorageConfig = new();
+ private static readonly SimpleQueuesConfig s_simpleQueuesConfig = new();
+ private static readonly SimpleVectorDbConfig s_simpleVectorDbConfig = new();
+ private static readonly OpenAIConfig s_openAIConfig = new();
+
+ internal static void Main()
+ {
+ new ConfigurationBuilder()
+ .AddJsonFile("appsettings.json")
+ .AddJsonFile("appsettings.development.json", optional: true)
+ .AddJsonFile("appsettings.Development.json", optional: true)
+ .Build()
+ .BindSection("KernelMemory:Services:SimpleFileStorage", s_simpleFileStorageConfig)
+ .BindSection("KernelMemory:Services:SimpleQueues", s_simpleQueuesConfig)
+ .BindSection("KernelMemory:Services:SimpleVectorDb", s_simpleVectorDbConfig)
+ .BindSection("KernelMemory:Services:OpenAI", s_openAIConfig);
+
+ RunFromCode();
+ }
+
+ private static void RunFromCode()
+ {
+ var builder = DistributedApplication.CreateBuilder();
+ builder.AddProject("kernel-memory")
+ .WithHttpEndpoint(targetPort: 21001)
+ .WithEnvironment("ASPNETCORE_URLS", "http://+:21001")
+ .WithEnvironment("ASPNETCORE_ENVIRONMENT", "Development")
+ .WithEnvironment("KernelMemory__Service__OpenApiEnabled", "True")
+ .WithKmTextEmbeddingGenerationEnvironment("OpenAI", s_openAIConfig)
+ .WithKmTextGenerationEnvironment("OpenAI", s_openAIConfig)
+ .WithKmMemoryDbEnvironment("SimpleVectorDb", s_simpleVectorDbConfig)
+ .WithKmOrchestrationEnvironment("SimpleQueues", s_simpleQueuesConfig)
+ .WithKmDocumentStorageEnvironment("SimpleFileStorage", s_simpleFileStorageConfig)
+ .WithKmContentSafetyModerationEnvironment(null) // ensure moderation is disabled
+ .WithKmOcrEnvironment(null); // ensure OCR is disabled;
+
+ builder.Build().Run();
+ }
+}
diff --git a/tools/aspire/volatile-openai/Properties/launchSettings.json b/tools/aspire/volatile-openai/Properties/launchSettings.json
new file mode 100644
index 000000000..67ee32301
--- /dev/null
+++ b/tools/aspire/volatile-openai/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "https": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "applicationUrl": "https://localhost:21100;http://localhost:21101",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21102",
+ "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:21103"
+ }
+ },
+ "http": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:21101",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:21102",
+ "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:21103"
+ }
+ }
+ }
+}
diff --git a/tools/aspire/volatile-openai/appsettings.json b/tools/aspire/volatile-openai/appsettings.json
new file mode 100644
index 000000000..eda793a16
--- /dev/null
+++ b/tools/aspire/volatile-openai/appsettings.json
@@ -0,0 +1,46 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning",
+ "Aspire.Hosting.Dcp": "Warning"
+ }
+ },
+ "KernelMemory": {
+ "Services": {
+ "OpenAI": {
+ "APIKey": "sk-..."
+ },
+ "SimpleFileStorage": {
+ // Options: "Disk" or "Volatile". Volatile data is lost after each execution.
+ "StorageType": "Volatile",
+ // Directory where files are stored.
+ "Directory": "_files"
+ },
+ "SimpleQueues": {
+ // Options: "Disk" or "Volatile". Volatile data is lost after each execution.
+ "StorageType": "Volatile",
+ // Directory where files are stored.
+ "Directory": "_queues",
+ // How often to check if there are new messages.
+ "PollDelayMsecs": 100,
+ // How often to dispatch messages in the queue.
+ "DispatchFrequencyMsecs": 100,
+ // How many messages to fetch at a time.
+ "FetchBatchSize": 3,
+ // How long to lock messages once fetched.
+ "FetchLockSeconds": 300,
+ // How many times to retry processing a failing message.
+ "MaxRetriesBeforePoisonQueue": 1,
+ // Suffix used for the poison queue directories
+ "PoisonQueueSuffix": ".poison"
+ },
+ "SimpleVectorDb": {
+ // Options: "Disk" or "Volatile". Volatile data is lost after each execution.
+ "StorageType": "Volatile",
+ // Directory where files are stored.
+ "Directory": "_vectors"
+ },
+ }
+ }
+}
diff --git a/tools/aspire/volatile-openai/run.sh b/tools/aspire/volatile-openai/run.sh
new file mode 100755
index 000000000..fb33b2f3e
--- /dev/null
+++ b/tools/aspire/volatile-openai/run.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+set -e
+
+cd "$(dirname "${BASH_SOURCE[0]:-$0}")"
+
+ASPNETCORE_ENVIRONMENT=Development dotnet run
diff --git a/tools/aspire/volatile-openai/volatile-openai.csproj b/tools/aspire/volatile-openai/volatile-openai.csproj
new file mode 100644
index 000000000..3e837fe47
--- /dev/null
+++ b/tools/aspire/volatile-openai/volatile-openai.csproj
@@ -0,0 +1,26 @@
+
+
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ true
+ Microsoft.KernelMemory.Aspire.AppHost
+ $(NoWarn);IDE0058;IDE0160;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/dockerize-amd64.sh b/tools/dev/dockerize-amd64.sh
similarity index 88%
rename from tools/dockerize-amd64.sh
rename to tools/dev/dockerize-amd64.sh
index a41a43e8e..7b1d205f4 100755
--- a/tools/dockerize-amd64.sh
+++ b/tools/dev/dockerize-amd64.sh
@@ -28,8 +28,10 @@ docker buildx build --no-cache --load \
--build-arg RUN_IMAGE_TAG=8.0-alpine-amd64 \
-t ${IMG}${TAG} .
-echo "Signing in as ${USR}..."
-docker login -u ${USR}
+# echo "Signing in as ${USR}..."
+# docker login -u ${USR}
echo "Pushing ${IMG}${TAG}..."
docker push "${IMG}${TAG}"
+
+echo "Docker image push complete."
diff --git a/tools/dockerize-arm64.sh b/tools/dev/dockerize-arm64.sh
similarity index 96%
rename from tools/dockerize-arm64.sh
rename to tools/dev/dockerize-arm64.sh
index 3b221b522..37064900e 100755
--- a/tools/dockerize-arm64.sh
+++ b/tools/dev/dockerize-arm64.sh
@@ -54,8 +54,8 @@ docker buildx build --no-cache --load \
-t ${IMG}${TAG1} -t ${IMG}${TAG2} \
.
-echo "Signing in as ${USR}..."
-docker login -u ${USR}
+# echo "Signing in as ${USR}..."
+# docker login -u ${USR}
# Push images to Docker registry
for IMAGE_TAG in "${TAG1}" "${TAG2}"; do
diff --git a/tools/dev/get-azure-token.py b/tools/dev/get-azure-token.py
new file mode 100644
index 000000000..6873fff88
--- /dev/null
+++ b/tools/dev/get-azure-token.py
@@ -0,0 +1,22 @@
+# Copyright (c) Microsoft. All rights reserved.
+
+# This script generates an Azure access token you might to call
+# Azure services directly for some test, e.g. with Postman.
+
+from azure.identity import DefaultAzureCredential
+
+def get_azure_access_token(scope):
+ try:
+ return DefaultAzureCredential().get_token(scope).token
+ except Exception as e:
+ print(f"Error generating token: {e}")
+ return None
+
+if __name__ == "__main__":
+ # Replace the scope with the Azure service you want to call
+ scope = "https://cognitiveservices.azure.com/.default"
+ access_token = get_azure_access_token(scope)
+ if access_token:
+ print(f"Access Token: {access_token}")
+ else:
+ print("Failed to generate access token")
diff --git a/tools/ask.sh b/tools/km-cli/ask.sh
similarity index 100%
rename from tools/ask.sh
rename to tools/km-cli/ask.sh
diff --git a/tools/search.sh b/tools/km-cli/search.sh
similarity index 100%
rename from tools/search.sh
rename to tools/km-cli/search.sh
diff --git a/tools/upload-file.sh b/tools/km-cli/upload-file.sh
similarity index 100%
rename from tools/upload-file.sh
rename to tools/km-cli/upload-file.sh