diff --git a/README.md b/README.md index 44422bd..0324cdf 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ -This sample shows how to build a serverless AI chat experience with Retrieval-Augmented Generation using [LangChain.js](https://js.langchain.com/) and Azure. The application is hosted on [Azure Static Web Apps](https://learn.microsoft.com/azure/static-web-apps/overview) and [Azure Functions](https://learn.microsoft.com/azure/azure-functions/functions-overview?pivots=programming-language-javascript), with [Azure Cosmos DB for MongoDB vCore](https://learn.microsoft.com/azure/cosmos-db/mongodb/vcore/) as the vector database. You can use it as a starting point for building more complex AI applications. +This sample shows how to build a serverless AI chat experience with Retrieval-Augmented Generation using [LangChain.js](https://js.langchain.com/) and Azure. The application is hosted on [Azure Static Web Apps](https://learn.microsoft.com/azure/static-web-apps/overview) and [Azure Functions](https://learn.microsoft.com/azure/azure-functions/functions-overview?pivots=programming-language-javascript), with [Azure AI Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search) as the vector database. You can use it as a starting point for building more complex AI applications. > [!TIP] > You can test this application locally without any cost using [Ollama](https://ollama.com/). Follow the instructions in the [Local Development](#local-development) section to get started. @@ -44,7 +44,7 @@ This application is made from multiple components: - A serverless API built with [Azure Functions](https://learn.microsoft.com/azure/azure-functions/functions-overview?pivots=programming-language-javascript) and using [LangChain.js](https://js.langchain.com/) to ingest the documents and generate responses to the user chat queries. The code is located in the `packages/api` folder. -- A database to store the text extracted from the documents and the vectors generated by LangChain.js, using [Azure Cosmos DB for MongoDB vCore](https://learn.microsoft.com/azure/cosmos-db/mongodb/vcore/). +- A database to store the text extracted from the documents and the vectors generated by LangChain.js, using [Azure AI Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search). - A file storage to store the source documents, using [Azure Blob Storage](https://learn.microsoft.com/azure/storage/blobs/storage-blobs-introduction). @@ -161,13 +161,16 @@ Note that the documents are uploaded automatically when deploying the sample to - **Azure account**. If you're new to Azure, [get an Azure account for free](https://azure.microsoft.com/free) to get free Azure credits to get started. If you're a student, you can also get free credits with [Azure for Students](https://aka.ms/azureforstudents). - **Azure subscription with access enabled for the Azure OpenAI service**. You can request access with [this form](https://aka.ms/oaiapply). +- **Azure account permissions**: + - Your Azure account must have `Microsoft.Authorization/roleAssignments/write` permissions, such as [Role Based Access Control Administrator](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#role-based-access-control-administrator-preview), [User Access Administrator](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#user-access-administrator), or [Owner](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#owner). If you don't have subscription-level permissions, you must be granted [RBAC](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#role-based-access-control-administrator-preview) for an existing resource group and [deploy to that existing group](docs/deploy_existing.md#resource-group). + - Your Azure account also needs `Microsoft.Resources/deployments/write` permissions on the subscription level. #### Deploy the sample 1. Open a terminal and navigate to the root of the project. 2. Authenticate with Azure by running `azd auth login`. 3. Run `azd up` to deploy the application to Azure. This will provision Azure resources, deploy this sample, and build the search index based on the files found in the `./data` folder. - - You will be prompted to select a base location for the resources. Choose a location that is closest to you. + - You will be prompted to select a base location for the resources. If you're unsure of which location to choose, select `eastus2`. - By default, the OpenAI resource will be deployed to `eastus2`. You can set a different location with `azd env set AZURE_OPENAI_RESOURCE_GROUP_LOCATION `. Currently only a short list of locations is accepted. That location list is based on the [OpenAI model availability table](https://learn.microsoft.com/azure/ai-services/openai/concepts/models#standard-deployment-model-availability) and may become outdated as availability changes. The deployment process will take a few minutes. Once it's done, you'll see the URL of the web app in the terminal. @@ -194,7 +197,7 @@ Here are some resources to learn more about the technologies used in this sample - [LangChain.js documentation](https://js.langchain.com) - [Generative AI For Beginners](https://github.com/microsoft/generative-ai-for-beginners) - [Azure OpenAI Service](https://learn.microsoft.com/azure/ai-services/openai/overview) -- [Azure Cosmos DB for MongoDB vCore](https://learn.microsoft.com/azure/cosmos-db/mongodb/vcore/) +- [Azure AI Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search) - [Ask YouTube: LangChain.js + Azure Quickstart sample](https://github.com/Azure-Samples/langchainjs-quickstart-demo) - [Chat + Enterprise data with Azure OpenAI and Azure AI Search](https://github.com/Azure-Samples/azure-search-openai-javascript) - [Revolutionize your Enterprise Data with Chat: Next-gen Apps w/ Azure OpenAI and AI Search](https://aka.ms/entgptsearchblog) diff --git a/docs/faq.md b/docs/faq.md index b29da7d..a8b7120 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -7,7 +7,7 @@ Retrieval-Augmented Generation (RAG) is a method used in artificial intelligence At its core, RAG involves two main components: -- **Retriever**: Think "_like a search engine_", finding relevant information from a knowledgebase, usually a vector database. In this sample, we're using Azure CosmosDB for MongoDB vCore as our vector database. +- **Retriever**: Think "_like a search engine_", finding relevant information from a knowledgebase, usually a vector database. In this sample, we're using Azure AI Search as our vector database. - **Generator**: Acts like a writer, taking the prompt and information retrieved to create a response. We're using here a Large Language Model (LLM) for this task. diff --git a/docs/images/architecture.drawio.png b/docs/images/architecture.drawio.png index 23d5104..6e564ff 100644 Binary files a/docs/images/architecture.drawio.png and b/docs/images/architecture.drawio.png differ diff --git a/docs/readme.md b/docs/readme.md index ea8f7a2..1a56444 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -17,7 +17,7 @@ description: Build your own serverless AI Chat with Retrieval-Augmented-Generati -This sample shows how to build a serverless AI chat experience with Retrieval-Augmented Generation using [LangChain.js](https://js.langchain.com/) and Azure. The application is hosted on [Azure Static Web Apps](https://learn.microsoft.com/azure/static-web-apps/overview) and [Azure Functions](https://learn.microsoft.com/azure/azure-functions/functions-overview?pivots=programming-language-javascript), with [Azure Cosmos DB for MongoDB vCore](https://learn.microsoft.com/azure/cosmos-db/mongodb/vcore/) as the vector database. You can use it as a starting point for building more complex AI applications. +This sample shows how to build a serverless AI chat experience with Retrieval-Augmented Generation using [LangChain.js](https://js.langchain.com/) and Azure. The application is hosted on [Azure Static Web Apps](https://learn.microsoft.com/azure/static-web-apps/overview) and [Azure Functions](https://learn.microsoft.com/azure/azure-functions/functions-overview?pivots=programming-language-javascript), with [Azure AI Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search) as the vector database. You can use it as a starting point for building more complex AI applications. ![Animation showing the chat app in action](./images/demo.gif) @@ -37,7 +37,7 @@ This application is made from multiple components: - A serverless API built with [Azure Functions](https://learn.microsoft.com/azure/azure-functions/functions-overview?pivots=programming-language-javascript) and using [LangChain.js](https://js.langchain.com/) to ingest the documents and generate responses to the user chat queries. The code is located in the `packages/api` folder. -- A database to store the text extracted from the documents and the vectors generated by LangChain.js, using [Azure Cosmos DB for MongoDB vCore](https://learn.microsoft.com/azure/cosmos-db/mongodb/vcore/). +- A database to store the text extracted from the documents and the vectors generated by LangChain.js, using [Azure AI Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search). - A file storage to store the source documents, using [Azure Blob Storage](https://learn.microsoft.com/azure/storage/blobs/storage-blobs-introduction). @@ -48,6 +48,9 @@ This application is made from multiple components: - [Git](https://git-scm.com/downloads) - Azure account. If you're new to Azure, [get an Azure account for free](https://azure.microsoft.com/free) to get free Azure credits to get started. If you're a student, you can also get free credits with [Azure for Students](https://aka.ms/azureforstudents). - Azure subscription with access enabled for the Azure OpenAI service. You can request access with [this form](https://aka.ms/oaiapply). +- Azure account permissions: + - Your Azure account must have `Microsoft.Authorization/roleAssignments/write` permissions, such as [Role Based Access Control Administrator](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#role-based-access-control-administrator-preview), [User Access Administrator](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#user-access-administrator), or [Owner](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#owner). If you don't have subscription-level permissions, you must be granted [RBAC](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#role-based-access-control-administrator-preview) for an existing resource group and [deploy to that existing group](docs/deploy_existing.md#resource-group). + - Your Azure account also needs `Microsoft.Resources/deployments/write` permissions on the subscription level. ## Setup the sample @@ -65,7 +68,7 @@ You can run this project directly in your browser by using GitHub Codespaces, wh 1. Open a terminal at the root of the project. 2. Authenticate with Azure by running `azd auth login`. 3. Run `azd up` to deploy the application to Azure. This will provision Azure resources, deploy this sample, and build the search index based on the files found in the `./data` folder. - - You will be prompted to select a base location for the resources. Choose a location that is closest to you. + - You will be prompted to select a base location for the resources. If you're unsure of which location to choose, select `eastus2`. - By default, the OpenAI resource will be deployed to `eastus2`. You can set a different location with `azd env set AZURE_OPENAI_RESOURCE_GROUP_LOCATION `. Currently only a short list of locations is accepted. That location list is based on the [OpenAI model availability table](https://learn.microsoft.com/azure/ai-services/openai/concepts/models#standard-deployment-model-availability) and may become outdated as availability changes. The deployment process will take a few minutes. Once it's done, you'll see the URL of the web app in the terminal. @@ -109,7 +112,7 @@ Here are some resources to learn more about the technologies used in this sample - [LangChain.js documentation](https://js.langchain.com) - [Generative AI For Beginners](https://github.com/microsoft/generative-ai-for-beginners) - [Azure OpenAI Service](https://learn.microsoft.com/azure/ai-services/openai/overview) -- [Azure Cosmos DB for MongoDB vCore](https://learn.microsoft.com/azure/cosmos-db/mongodb/vcore/) +- [Azure AI Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search) - [Ask YouTube: LangChain.js + Azure Quickstart sample](https://github.com/Azure-Samples/langchainjs-quickstart-demo) - [Chat + Enterprise data with Azure OpenAI and Azure AI Search](https://github.com/Azure-Samples/azure-search-openai-javascript) - [Revolutionize your Enterprise Data with Chat: Next-gen Apps w/ Azure OpenAI and AI Search](https://aka.ms/entgptsearchblog) diff --git a/infra/core/ai/cognitiveservices.bicep b/infra/core/ai/cognitiveservices.bicep index a485731..83e7515 100644 --- a/infra/core/ai/cognitiveservices.bicep +++ b/infra/core/ai/cognitiveservices.bicep @@ -20,6 +20,7 @@ param networkAcls object = empty(allowedIpRules) ? { ipRules: allowedIpRules defaultAction: 'Deny' } +param disableLocalAuth bool = false resource account 'Microsoft.CognitiveServices/accounts@2023-05-01' = { name: name @@ -30,6 +31,7 @@ resource account 'Microsoft.CognitiveServices/accounts@2023-05-01' = { customSubDomainName: customSubDomainName publicNetworkAccess: publicNetworkAccess networkAcls: networkAcls + disableLocalAuth: disableLocalAuth } sku: sku } @@ -51,4 +53,3 @@ resource deployment 'Microsoft.CognitiveServices/accounts/deployments@2023-05-01 output endpoint string = account.properties.endpoint output id string = account.id output name string = account.name -output apiKey string = account.listKeys().key1 diff --git a/infra/core/database/cosmos-mongo-db-vcore.bicep b/infra/core/database/cosmos-mongo-db-vcore.bicep deleted file mode 100644 index 495ec2d..0000000 --- a/infra/core/database/cosmos-mongo-db-vcore.bicep +++ /dev/null @@ -1,39 +0,0 @@ -metadata description = 'Creates an Azure Cosmos DB for MongoDB vCore account with a database.' -param accountName string -@secure() -param administratorLogin string -@secure() -param administratorLoginPassword string = newGuid() -param location string = resourceGroup().location -param skuName string = 'Free' -param tags object = {} - -resource cosmos 'Microsoft.DocumentDB/mongoClusters@2023-11-15-preview' = { - name: accountName - location: location - tags: tags - properties: { - administratorLogin: administratorLogin - administratorLoginPassword: administratorLoginPassword - createMode: 'Default' - serverVersion: '6.0' - nodeGroupSpecs: [ - { - kind: 'Shard' - sku: skuName - diskSizeGB: 32 - enableHa: false - nodeCount: 1 - } - ] - } - resource firewallRule 'firewallRules' = { - name: 'AllowAll' - properties: { - startIpAddress: '0.0.0.0' - endIpAddress: '255.255.255.255' - } - } -} - -output connectionString string = replace(cosmos.properties.connectionString, ':', '${administratorLogin}:${administratorLoginPassword}') diff --git a/infra/core/search/search-services.bicep b/infra/core/search/search-services.bicep new file mode 100644 index 0000000..33fd83e --- /dev/null +++ b/infra/core/search/search-services.bicep @@ -0,0 +1,68 @@ +metadata description = 'Creates an Azure AI Search instance.' +param name string +param location string = resourceGroup().location +param tags object = {} + +param sku object = { + name: 'standard' +} + +param authOptions object = {} +param disableLocalAuth bool = false +param disabledDataExfiltrationOptions array = [] +param encryptionWithCmk object = { + enforcement: 'Unspecified' +} +@allowed([ + 'default' + 'highDensity' +]) +param hostingMode string = 'default' +param networkRuleSet object = { + bypass: 'None' + ipRules: [] +} +param partitionCount int = 1 +@allowed([ + 'enabled' + 'disabled' +]) +param publicNetworkAccess string = 'enabled' +param replicaCount int = 1 +@allowed([ + 'disabled' + 'free' + 'standard' +]) +param semanticSearch string = 'disabled' + +var searchIdentityProvider = (sku.name == 'free') ? null : { + type: 'SystemAssigned' +} + +resource search 'Microsoft.Search/searchServices@2021-04-01-preview' = { + name: name + location: location + tags: tags + // The free tier does not support managed identity + identity: searchIdentityProvider + properties: { + authOptions: disableLocalAuth ? null : authOptions + disableLocalAuth: disableLocalAuth + disabledDataExfiltrationOptions: disabledDataExfiltrationOptions + encryptionWithCmk: encryptionWithCmk + hostingMode: hostingMode + networkRuleSet: networkRuleSet + partitionCount: partitionCount + publicNetworkAccess: publicNetworkAccess + replicaCount: replicaCount + semanticSearch: semanticSearch + } + sku: sku +} + +output id string = search.id +output endpoint string = 'https://${name}.search.windows.net/' +output name string = search.name +output principalId string = !empty(searchIdentityProvider) ? search.identity.principalId : '' + diff --git a/infra/core/security/role.bicep b/infra/core/security/role.bicep new file mode 100644 index 0000000..0b30cfd --- /dev/null +++ b/infra/core/security/role.bicep @@ -0,0 +1,21 @@ +metadata description = 'Creates a role assignment for a service principal.' +param principalId string + +@allowed([ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' +]) +param principalType string = 'ServicePrincipal' +param roleDefinitionId string + +resource role 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().id, resourceGroup().id, principalId, roleDefinitionId) + properties: { + principalId: principalId + principalType: principalType + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) + } +} diff --git a/infra/core/storage/storage-account.bicep b/infra/core/storage/storage-account.bicep index a56266a..4b6febb 100644 --- a/infra/core/storage/storage-account.bicep +++ b/infra/core/storage/storage-account.bicep @@ -60,8 +60,5 @@ resource storage 'Microsoft.Storage/storageAccounts@2022-05-01' = { } } -var sharedKey = storage.listKeys().keys[0].value - output name string = storage.name output primaryEndpoints object = storage.properties.primaryEndpoints -output connectionString string = 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${sharedKey};EndpointSuffix=core.windows.net' diff --git a/infra/main.bicep b/infra/main.bicep index 1a8d017..bdf2aae 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -14,8 +14,11 @@ param webappName string = 'webapp' param apiServiceName string = 'api' param appServicePlanName string = '' param storageAccountName string = '' -param cosmosAccountName string = '' -param mongoDbSkuName string = 'Free' +param searchServiceName string = '' + +// The free tier does not support managed identity (required) or semantic search (optional) +@allowed(['basic', 'standard', 'standard2', 'standard3', 'storage_optimized_l1', 'storage_optimized_l2']) +param searchServiceSkuName string @description('Location for the OpenAI resource group') @allowed(['australiaeast', 'canadaeast', 'eastus', 'eastus2', 'francecentral', 'japaneast', 'northcentralus', 'swedencentral', 'switzerlandnorth', 'uksouth', 'westeurope']) @@ -27,8 +30,6 @@ param mongoDbSkuName string = 'Free' param openAiLocation string // Set in main.parameters.json param openAiSkuName string = 'S0' param openAiUrl string = '' -@secure() -param openAiKey string = '' // Location is not relevant here as it's only for the built-in api // which is not used here. Static Web App is a global service otherwise @@ -52,11 +53,18 @@ param embeddingsDeploymentCapacity int = 30 param blobContainerName string = 'files' +// Id of the user or app to assign application roles +param principalId string = '' + +// Differentiates between automated and manual deployments +param isContinuousDeployment bool // Set in main.parameters.json + var abbrs = loadJsonContent('abbreviations.json') var resourceToken = toLower(uniqueString(subscription().id, environmentName, location)) var tags = { 'azd-env-name': environmentName } var finalOpenAiUrl = empty(openAiUrl) ? 'https://${openAi.outputs.name}.openai.azure.com' : openAiUrl -var finalOpenAiApiKey = empty(openAiKey) ? openAi.outputs.apiKey : openAiKey +var storageUrl = 'https://${storage.outputs.name}.blob.${environment().suffixes.storage}' +var searchUrl = 'https://${search.outputs.name}.search.windows.net' // Organize resources in a resource group resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { @@ -90,16 +98,17 @@ module api './core/host/functions.bicep' = { runtimeVersion: '20' appServicePlanId: appServicePlan.outputs.id storageAccountName: storage.outputs.name + managedIdentity: true appSettings: { - AZURE_OPENAI_API_KEY: finalOpenAiApiKey AZURE_OPENAI_API_ENDPOINT: finalOpenAiUrl AZURE_OPENAI_API_DEPLOYMENT_NAME: chatDeploymentName AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME: embeddingsDeploymentName - AZURE_COSMOSDB_CONNECTION_STRING: cosmos.outputs.connectionString - AZURE_STORAGE_CONNECTION_STRING: storage.outputs.connectionString + AZURE_AISEARCH_ENDPOINT: searchUrl + AZURE_STORAGE_URL: storageUrl AZURE_STORAGE_CONTAINER_NAME: blobContainerName } } + dependsOn: empty(openAiUrl) ? [] : [openAi] } // Compute plan for the Azure Functions API @@ -125,27 +134,16 @@ module storage './core/storage/storage-account.bicep' = { name: !empty(storageAccountName) ? storageAccountName : '${abbrs.storageStorageAccounts}${resourceToken}' location: location tags: tags + allowBlobPublicAccess: false containers: [ { name: blobContainerName - publicAccess: 'Container' + publicAccess: 'None' } ] } } -module cosmos 'core/database/cosmos-mongo-db-vcore.bicep' = { - name: 'cosmos-mongo' - scope: resourceGroup - params: { - accountName: !empty(cosmosAccountName) ? cosmosAccountName : '${abbrs.documentDBDatabaseAccounts}${resourceToken}' - administratorLogin: 'admin${resourceToken}' - skuName: mongoDbSkuName - location: location - tags: tags - } -} - module openAi 'core/ai/cognitiveservices.bicep' = if (empty(openAiUrl)) { name: 'openai' scope: resourceGroup @@ -156,6 +154,7 @@ module openAi 'core/ai/cognitiveservices.bicep' = if (empty(openAiUrl)) { sku: { name: openAiSkuName } + disableLocalAuth: true deployments: [ { name: chatDeploymentName @@ -182,21 +181,128 @@ module openAi 'core/ai/cognitiveservices.bicep' = if (empty(openAiUrl)) { } } +module search 'core/search/search-services.bicep' = { + name: 'search' + scope: resourceGroup + params: { + name: !empty(searchServiceName) ? searchServiceName : '${abbrs.searchSearchServices}${resourceToken}' + location: location + tags: tags + disableLocalAuth: true + authOptions: null + sku: { + name: searchServiceSkuName + } + } +} + +// Managed identity roles assignation +// --------------------------------------------------------------------------- + +// User roles +module openAiRoleUser 'core/security/role.bicep' = if (!isContinuousDeployment) { + scope: resourceGroup + name: 'openai-role-user' + params: { + principalId: principalId + // Cognitive Services OpenAI User + roleDefinitionId: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' + principalType: 'User' + } +} + +module storageRoleUser 'core/security/role.bicep' = if (!isContinuousDeployment) { + scope: resourceGroup + name: 'storage-contrib-role-user' + params: { + principalId: principalId + // Storage Blob Data Contributor + roleDefinitionId: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' + principalType: 'User' + } +} + +module searchIndexContribRoleUser 'core/security/role.bicep' = { + scope: resourceGroup + name: 'search-index-contrib-role-user' + params: { + principalId: principalId + // Search Index Data Contributor + roleDefinitionId: '8ebe5a00-799e-43f5-93ac-243d3dce84a7' + principalType: 'User' + } +} + +module searchContribRoleIndexerUser 'core/security/role.bicep' = { + scope: resourceGroup + name: 'search-contrib-role-user' + params: { + principalId: principalId + // Search Service Contributor + roleDefinitionId: '7ca78c08-252a-4471-8644-bb5ff32d4ba0' + principalType: 'User' + } +} + +// System roles +module openAiRoleApi 'core/security/role.bicep' = { + scope: resourceGroup + name: 'openai-role-api' + params: { + principalId: api.outputs.identityPrincipalId + // Cognitive Services OpenAI User + roleDefinitionId: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' + principalType: 'ServicePrincipal' + } +} + +module storageRoleApi 'core/security/role.bicep' = { + scope: resourceGroup + name: 'storage-role-api' + params: { + principalId: api.outputs.identityPrincipalId + // Storage Blob Data Contributor + roleDefinitionId: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' + principalType: 'ServicePrincipal' + } +} + +module searchIndexContribRoleApi 'core/security/role.bicep' = { + scope: resourceGroup + name: 'search-index-contrib-role-api' + params: { + principalId: api.outputs.identityPrincipalId + // Search Index Data Contributor + roleDefinitionId: '8ebe5a00-799e-43f5-93ac-243d3dce84a7' + principalType: 'ServicePrincipal' + } +} + +module searchContribRoleIndexerApi 'core/security/role.bicep' = { + scope: resourceGroup + name: 'search-contrib-role-api' + params: { + principalId: api.outputs.identityPrincipalId + // Search Service Contributor + roleDefinitionId: '7ca78c08-252a-4471-8644-bb5ff32d4ba0' + principalType: 'ServicePrincipal' + } +} + output AZURE_LOCATION string = location output AZURE_TENANT_ID string = tenant().tenantId output AZURE_RESOURCE_GROUP string = resourceGroup.name output AZURE_OPENAI_API_ENDPOINT string = finalOpenAiUrl -output AZURE_OPENAI_API_KEY string = finalOpenAiApiKey output AZURE_OPENAI_API_DEPLOYMENT_NAME string = chatDeploymentName output AZURE_OPENAI_API_MODEL string = chatModelName output AZURE_OPENAI_API_MODEL_VERSION string = chatModelVersion output AZURE_OPENAI_API_EMBEDDINGS_DEPLOYMENT_NAME string = embeddingsDeploymentName output AZURE_OPENAI_API_EMBEDDINGS_MODEL string = embeddingsModelName output AZURE_OPENAI_API_EMBEDDINGS_MODEL_VERSION string = embeddingsModelVersion -output AZURE_COSMOSDB_CONNECTION_STRING string = cosmos.outputs.connectionString -output AZURE_STORAGE_CONNECTION_STRING string = storage.outputs.connectionString +output AZURE_STORAGE_URL string = storageUrl output AZURE_STORAGE_CONTAINER_NAME string = blobContainerName +output AZURE_AISEARCH_ENDPOINT string = searchUrl output API_URL string = api.outputs.uri output WEBAPP_URL string = webapp.outputs.uri diff --git a/infra/main.parameters.json b/infra/main.parameters.json index 196dc90..d015798 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -11,15 +11,12 @@ "location": { "value": "${AZURE_LOCATION}" }, + "principalId": { + "value": "${AZURE_PRINCIPAL_ID}" + }, "openAiLocation": { "value": "${AZURE_OPENAI_LOCATION=eastus2}" }, - "openAiUrl": { - "value": "${OPENAI_URL}" - }, - "openAiKey": { - "value": "${OPENAI_KEY}" - }, "chatModelName": { "value": "${AZURE_OPENAI_API_MODEL=gpt-35-turbo}" }, @@ -35,8 +32,11 @@ "webappLocation": { "value": "${AZURE_WEBAPP_LOCATION=eastus2}" }, - "mongoDbSkuName": { - "value": "${AZURE_MONGODB_SKU=Free}" + "searchServiceSkuName": { + "value": "${AZURE_SEARCH_SERVICE_SKU=basic}" + }, + "isContinuousDeployment": { + "value": "${CI=false}" } } } diff --git a/package-lock.json b/package-lock.json index 951f096..5375184 100644 --- a/package-lock.json +++ b/package-lock.json @@ -85,17 +85,6 @@ "node": ">=18.0.0" } }, - "node_modules/@azure-rest/core-client/node_modules/@azure/core-tracing": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz", - "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@azure/abort-controller": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", @@ -131,6 +120,34 @@ "node": ">=18.0.0" } }, + "node_modules/@azure/core-client": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", + "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.9.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@azure/core-http": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.4.tgz", @@ -155,6 +172,42 @@ "node": ">=14.0.0" } }, + "node_modules/@azure/core-http-compat": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.1.2.tgz", + "integrity": "sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-client": "^1.3.0", + "@azure/core-rest-pipeline": "^1.3.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-http-compat/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-http/node_modules/@azure/core-tracing": { + "version": "1.0.0-preview.13", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz", + "integrity": "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==", + "dependencies": { + "@opentelemetry/api": "^1.0.1", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@azure/core-lro": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz", @@ -220,17 +273,6 @@ "node": ">=18.0.0" } }, - "node_modules/@azure/core-rest-pipeline/node_modules/@azure/core-tracing": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz", - "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@azure/core-sse": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@azure/core-sse/-/core-sse-2.1.2.tgz", @@ -243,15 +285,14 @@ } }, "node_modules/@azure/core-tracing": { - "version": "1.0.0-preview.13", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz", - "integrity": "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz", + "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==", "dependencies": { - "@opentelemetry/api": "^1.0.1", - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/core-util": { @@ -290,6 +331,30 @@ "node": ">=18.0" } }, + "node_modules/@azure/identity": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.1.0.tgz", + "integrity": "sha512-BhYkF8Xr2gXjyDxocm0pc9RI5J5a1jw8iW0dw6Bx95OGdYbuMyFZrrwNw4eYSqQ2BB6FZOqpJP3vjsAqRcvDhw==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.5.0", + "@azure/core-client": "^1.4.0", + "@azure/core-rest-pipeline": "^1.1.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.3.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^3.11.1", + "@azure/msal-node": "^2.6.6", + "events": "^3.0.0", + "jws": "^4.0.0", + "open": "^8.0.0", + "stoppable": "^1.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@azure/logger": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.2.tgz", @@ -301,6 +366,38 @@ "node": ">=18.0.0" } }, + "node_modules/@azure/msal-browser": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.13.0.tgz", + "integrity": "sha512-fD906nmJei3yE7la6DZTdUtXKvpwzJURkfsiz9747Icv4pit77cegSm6prJTKLQ1fw4iiZzrrWwxnhMLrTf5gQ==", + "dependencies": { + "@azure/msal-common": "14.9.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "14.9.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.9.0.tgz", + "integrity": "sha512-yzBPRlWPnTBeixxLNI3BBIgF5/bHpbhoRVuuDBnYjCyWRavaPUsKAHUDYLqpGkBLDciA6TCc6GOxN4/S3WiSxg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.7.0.tgz", + "integrity": "sha512-wXD8LkUvHICeSWZydqg6o8Yvv+grlBEcmLGu+QEI4FcwFendbTEZrlSygnAXXSOCVaGAirWLchca35qrgpO6Jw==", + "dependencies": { + "@azure/msal-common": "14.9.0", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@azure/openai": { "version": "1.0.0-beta.11", "resolved": "https://registry.npmjs.org/@azure/openai/-/openai-1.0.0-beta.11.tgz", @@ -318,6 +415,25 @@ "node": ">=18.0.0" } }, + "node_modules/@azure/search-documents": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@azure/search-documents/-/search-documents-12.0.0.tgz", + "integrity": "sha512-d9d53f2WWBpLHifk+LVn+AG52zuXvjgxJAdaH6kuT2qwrO1natcigtTgBM8qrI3iDYaDXsQhJSIMEgg9WKSoWA==", + "dependencies": { + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.3.0", + "@azure/core-http-compat": "^2.0.1", + "@azure/core-paging": "^1.1.1", + "@azure/core-rest-pipeline": "^1.3.0", + "@azure/core-tracing": "^1.0.0", + "@azure/logger": "^1.0.0", + "events": "^3.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@azure/storage-blob": { "version": "12.17.0", "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.17.0.tgz", @@ -336,6 +452,18 @@ "node": ">=14.0.0" } }, + "node_modules/@azure/storage-blob/node_modules/@azure/core-tracing": { + "version": "1.0.0-preview.13", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz", + "integrity": "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==", + "dependencies": { + "@opentelemetry/api": "^1.0.1", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.24.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", @@ -1099,9 +1227,9 @@ } }, "node_modules/@langchain/azure-openai": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@langchain/azure-openai/-/azure-openai-0.0.7.tgz", - "integrity": "sha512-fMH/kDAe8wOQ3j5mwaqFHjxsxtAgBLAfeMoxTgev7nC/76c4wRboSY4lb4FnwilNw4EXpB2Jg/K2QV19UyPOPw==", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@langchain/azure-openai/-/azure-openai-0.0.8.tgz", + "integrity": "sha512-8ckAdL33jqPPEABwsdIYao/NZr7c47XTZZ0gj+BO//EDHuXYlAiZC0XS+iS5OI0aGqJFt0eKh/fCuCHxT4xDeQ==", "dependencies": { "@azure/core-auth": "^1.5.0", "@azure/openai": "1.0.0-beta.11", @@ -1115,11 +1243,11 @@ } }, "node_modules/@langchain/community": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@langchain/community/-/community-0.0.48.tgz", - "integrity": "sha512-jG7dpJkgKtwbrSLsxW4mXmECopTj5tRt4+B+QcKCqZm7yEghFR44Xj5OkDWtzzsjpL47RJck5AJ8MsQnmi7WDQ==", + "version": "0.0.53", + "resolved": "https://registry.npmjs.org/@langchain/community/-/community-0.0.53.tgz", + "integrity": "sha512-iFqZPt4MRssGYsQoKSXWJQaYTZCC7WNuilp2JCCs3wKmJK3l6mR0eV+PDrnT+TaDHUVxt/b0rwgM0sOiy0j2jA==", "dependencies": { - "@langchain/core": "~0.1.56", + "@langchain/core": "~0.1.60", "@langchain/openai": "~0.0.28", "expr-eval": "^2.0.2", "flat": "^5.0.2", @@ -1154,11 +1282,12 @@ "@gradientai/nodejs-sdk": "^1.2.0", "@huggingface/inference": "^2.6.4", "@mozilla/readability": "*", + "@neondatabase/serverless": "*", "@opensearch-project/opensearch": "*", "@pinecone-database/pinecone": "*", "@planetscale/database": "^1.8.0", "@premai/prem-sdk": "^0.3.25", - "@qdrant/js-client-rest": "^1.2.0", + "@qdrant/js-client-rest": "^1.8.2", "@raycast/api": "^1.55.2", "@rockset/client": "^0.9.1", "@smithy/eventstream-codec": "^2.0.5", @@ -1171,7 +1300,7 @@ "@tensorflow/tfjs-converter": "*", "@tensorflow/tfjs-core": "*", "@upstash/redis": "^1.20.6", - "@upstash/vector": "^1.0.2", + "@upstash/vector": "^1.0.7", "@vercel/kv": "^0.2.3", "@vercel/postgres": "^0.5.0", "@writerai/writer-sdk": "^0.40.2", @@ -1195,7 +1324,7 @@ "firebase-admin": "^11.9.0 || ^12.0.0", "google-auth-library": "^8.9.0", "googleapis": "^126.0.1", - "hnswlib-node": "^1.4.2", + "hnswlib-node": "^3.0.0", "html-to-text": "^9.0.5", "interface-datastore": "^8.2.11", "ioredis": "^5.3.2", @@ -1291,6 +1420,9 @@ "@mozilla/readability": { "optional": true }, + "@neondatabase/serverless": { + "optional": true + }, "@opensearch-project/opensearch": { "optional": true }, @@ -1513,17 +1645,17 @@ } }, "node_modules/@langchain/community/node_modules/zod-to-json-schema": { - "version": "3.22.5", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.22.5.tgz", - "integrity": "sha512-+akaPo6a0zpVCCseDed504KBJUQpEW5QZw7RMneNmKw+fGaML1Z9tUNLnHHAC8x6dzVRO1eB2oEMyZRnuBZg7Q==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.0.tgz", + "integrity": "sha512-az0uJ243PxsRIa2x1WmNE/pnuA05gUq/JB8Lwe1EDCCL/Fz9MgjYQ0fPlyc2Tcv6aF2ZA7WM5TWaRZVEFaAIag==", "peerDependencies": { - "zod": "^3.22.4" + "zod": "^3.23.3" } }, "node_modules/@langchain/core": { - "version": "0.1.57", - "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.1.57.tgz", - "integrity": "sha512-6wOwidPkkRcANrOKl88+YYpm3jHfpg6W8EqZHQCImSAlxdEhyDSq2eeQKHOPCFCrfNWkClaNn+Wlzzz4Qwf9Tg==", + "version": "0.1.61", + "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.1.61.tgz", + "integrity": "sha512-C8OkAly+ugvXsL8TACCmFv9WTTcT4gvQaG6NbrXCOzibBCywfxxcTqEMOyg3zIKpxHEmR0DHqh0OiJRHocnsCg==", "dependencies": { "ansi-styles": "^5.0.0", "camelcase": "6", @@ -1531,6 +1663,7 @@ "js-tiktoken": "^1.0.8", "langsmith": "~0.1.7", "ml-distance": "^4.0.0", + "mustache": "^4.2.0", "p-queue": "^6.6.2", "p-retry": "4", "uuid": "^9.0.0", @@ -1565,11 +1698,11 @@ } }, "node_modules/@langchain/core/node_modules/zod-to-json-schema": { - "version": "3.22.5", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.22.5.tgz", - "integrity": "sha512-+akaPo6a0zpVCCseDed504KBJUQpEW5QZw7RMneNmKw+fGaML1Z9tUNLnHHAC8x6dzVRO1eB2oEMyZRnuBZg7Q==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.0.tgz", + "integrity": "sha512-az0uJ243PxsRIa2x1WmNE/pnuA05gUq/JB8Lwe1EDCCL/Fz9MgjYQ0fPlyc2Tcv6aF2ZA7WM5TWaRZVEFaAIag==", "peerDependencies": { - "zod": "^3.22.4" + "zod": "^3.23.3" } }, "node_modules/@langchain/openai": { @@ -1588,11 +1721,23 @@ } }, "node_modules/@langchain/openai/node_modules/zod-to-json-schema": { - "version": "3.22.5", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.22.5.tgz", - "integrity": "sha512-+akaPo6a0zpVCCseDed504KBJUQpEW5QZw7RMneNmKw+fGaML1Z9tUNLnHHAC8x6dzVRO1eB2oEMyZRnuBZg7Q==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.0.tgz", + "integrity": "sha512-az0uJ243PxsRIa2x1WmNE/pnuA05gUq/JB8Lwe1EDCCL/Fz9MgjYQ0fPlyc2Tcv6aF2ZA7WM5TWaRZVEFaAIag==", "peerDependencies": { - "zod": "^3.22.4" + "zod": "^3.23.3" + } + }, + "node_modules/@langchain/textsplitters": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@langchain/textsplitters/-/textsplitters-0.0.0.tgz", + "integrity": "sha512-3hPesWomnmVeYMppEGYbyv0v/sRUugUdlFBNn9m1ueJYHAIKbvCErkWxNUH3guyKKYgJVrkvZoQxcd9faucSaw==", + "dependencies": { + "@langchain/core": "~0.1", + "js-tiktoken": "^1.0.11" + }, + "engines": { + "node": ">=18" } }, "node_modules/@lit-labs/ssr-dom-shim": { @@ -1612,6 +1757,8 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.5.tgz", "integrity": "sha512-XLNOMH66KhJzUJNwT/qlMnS4WsNDWD5ASdyaSH3EtK+F4r/CFGa3jT4GNi4mfOitGvWXtdLgQJkQjxSVrio+jA==", + "optional": true, + "peer": true, "dependencies": { "sparse-bitfield": "^3.0.3" } @@ -1682,9 +1829,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.3.tgz", - "integrity": "sha512-X9alQ3XM6I9IlSlmC8ddAvMSyG1WuHk5oUnXGw+yUBs3BFoTizmG1La/Gr8fVJvDWAq+zlYTZ9DBgrlKRVY06g==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.16.4.tgz", + "integrity": "sha512-GkhjAaQ8oUTOKE4g4gsZ0u8K/IHU1+2WQSgS1TwTcYvL+sjbaQjNHFXbOJ6kgqGHIO1DfUhI/Sphi9GkRT9K+Q==", "cpu": [ "arm" ], @@ -1695,9 +1842,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.3.tgz", - "integrity": "sha512-eQK5JIi+POhFpzk+LnjKIy4Ks+pwJ+NXmPxOCSvOKSNRPONzKuUvWE+P9JxGZVxrtzm6BAYMaL50FFuPe0oWMQ==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.16.4.tgz", + "integrity": "sha512-Bvm6D+NPbGMQOcxvS1zUl8H7DWlywSXsphAeOnVeiZLQ+0J6Is8T7SrjGTH29KtYkiY9vld8ZnpV3G2EPbom+w==", "cpu": [ "arm64" ], @@ -1708,9 +1855,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.3.tgz", - "integrity": "sha512-Od4vE6f6CTT53yM1jgcLqNfItTsLt5zE46fdPaEmeFHvPs5SjZYlLpHrSiHEKR1+HdRfxuzXHjDOIxQyC3ptBA==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.16.4.tgz", + "integrity": "sha512-i5d64MlnYBO9EkCOGe5vPR/EeDwjnKOGGdd7zKFhU5y8haKhQZTN2DgVtpODDMxUr4t2K90wTUJg7ilgND6bXw==", "cpu": [ "arm64" ], @@ -1721,9 +1868,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.3.tgz", - "integrity": "sha512-0IMAO21axJeNIrvS9lSe/PGthc8ZUS+zC53O0VhF5gMxfmcKAP4ESkKOCwEi6u2asUrt4mQv2rjY8QseIEb1aw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.16.4.tgz", + "integrity": "sha512-WZupV1+CdUYehaZqjaFTClJI72fjJEgTXdf4NbW69I9XyvdmztUExBtcI2yIIU6hJtYvtwS6pkTkHJz+k08mAQ==", "cpu": [ "x64" ], @@ -1734,9 +1881,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.3.tgz", - "integrity": "sha512-ge2DC7tHRHa3caVEoSbPRJpq7azhG+xYsd6u2MEnJ6XzPSzQsTKyXvh6iWjXRf7Rt9ykIUWHtl0Uz3T6yXPpKw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.16.4.tgz", + "integrity": "sha512-ADm/xt86JUnmAfA9mBqFcRp//RVRt1ohGOYF6yL+IFCYqOBNwy5lbEK05xTsEoJq+/tJzg8ICUtS82WinJRuIw==", "cpu": [ "arm" ], @@ -1747,9 +1894,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.14.3.tgz", - "integrity": "sha512-ljcuiDI4V3ySuc7eSk4lQ9wU8J8r8KrOUvB2U+TtK0TiW6OFDmJ+DdIjjwZHIw9CNxzbmXY39wwpzYuFDwNXuw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.16.4.tgz", + "integrity": "sha512-tJfJaXPiFAG+Jn3cutp7mCs1ePltuAgRqdDZrzb1aeE3TktWWJ+g7xK9SNlaSUFw6IU4QgOxAY4rA+wZUT5Wfg==", "cpu": [ "arm" ], @@ -1760,9 +1907,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.3.tgz", - "integrity": "sha512-Eci2us9VTHm1eSyn5/eEpaC7eP/mp5n46gTRB3Aar3BgSvDQGJZuicyq6TsH4HngNBgVqC5sDYxOzTExSU+NjA==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.16.4.tgz", + "integrity": "sha512-7dy1BzQkgYlUTapDTvK997cgi0Orh5Iu7JlZVBy1MBURk7/HSbHkzRnXZa19ozy+wwD8/SlpJnOOckuNZtJR9w==", "cpu": [ "arm64" ], @@ -1773,9 +1920,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.3.tgz", - "integrity": "sha512-UrBoMLCq4E92/LCqlh+blpqMz5h1tJttPIniwUgOFJyjWI1qrtrDhhpHPuFxULlUmjFHfloWdixtDhSxJt5iKw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.16.4.tgz", + "integrity": "sha512-zsFwdUw5XLD1gQe0aoU2HVceI6NEW7q7m05wA46eUAyrkeNYExObfRFQcvA6zw8lfRc5BHtan3tBpo+kqEOxmg==", "cpu": [ "arm64" ], @@ -1786,9 +1933,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.3.tgz", - "integrity": "sha512-5aRjvsS8q1nWN8AoRfrq5+9IflC3P1leMoy4r2WjXyFqf3qcqsxRCfxtZIV58tCxd+Yv7WELPcO9mY9aeQyAmw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.16.4.tgz", + "integrity": "sha512-p8C3NnxXooRdNrdv6dBmRTddEapfESEUflpICDNKXpHvTjRRq1J82CbU5G3XfebIZyI3B0s074JHMWD36qOW6w==", "cpu": [ "ppc64" ], @@ -1799,9 +1946,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.3.tgz", - "integrity": "sha512-sk/Qh1j2/RJSX7FhEpJn8n0ndxy/uf0kI/9Zc4b1ELhqULVdTfN6HL31CDaTChiBAOgLcsJ1sgVZjWv8XNEsAQ==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.16.4.tgz", + "integrity": "sha512-Lh/8ckoar4s4Id2foY7jNgitTOUQczwMWNYi+Mjt0eQ9LKhr6sK477REqQkmy8YHY3Ca3A2JJVdXnfb3Rrwkng==", "cpu": [ "riscv64" ], @@ -1812,9 +1959,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.3.tgz", - "integrity": "sha512-jOO/PEaDitOmY9TgkxF/TQIjXySQe5KVYB57H/8LRP/ux0ZoO8cSHCX17asMSv3ruwslXW/TLBcxyaUzGRHcqg==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.16.4.tgz", + "integrity": "sha512-1xwwn9ZCQYuqGmulGsTZoKrrn0z2fAur2ujE60QgyDpHmBbXbxLaQiEvzJWDrscRq43c8DnuHx3QorhMTZgisQ==", "cpu": [ "s390x" ], @@ -1825,9 +1972,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.3.tgz", - "integrity": "sha512-8ybV4Xjy59xLMyWo3GCfEGqtKV5M5gCSrZlxkPGvEPCGDLNla7v48S662HSGwRd6/2cSneMQWiv+QzcttLrrOA==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.16.4.tgz", + "integrity": "sha512-LuOGGKAJ7dfRtxVnO1i3qWc6N9sh0Em/8aZ3CezixSTM+E9Oq3OvTsvC4sm6wWjzpsIlOCnZjdluINKESflJLA==", "cpu": [ "x64" ], @@ -1838,9 +1985,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.3.tgz", - "integrity": "sha512-s+xf1I46trOY10OqAtZ5Rm6lzHre/UiLA1J2uOhCFXWkbZrJRkYBPO6FhvGfHmdtQ3Bx793MNa7LvoWFAm93bg==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.16.4.tgz", + "integrity": "sha512-ch86i7KkJKkLybDP2AtySFTRi5fM3KXp0PnHocHuJMdZwu7BuyIKi35BE9guMlmTpwwBTB3ljHj9IQXnTCD0vA==", "cpu": [ "x64" ], @@ -1851,9 +1998,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.3.tgz", - "integrity": "sha512-+4h2WrGOYsOumDQ5S2sYNyhVfrue+9tc9XcLWLh+Kw3UOxAvrfOrSMFon60KspcDdytkNDh7K2Vs6eMaYImAZg==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.16.4.tgz", + "integrity": "sha512-Ma4PwyLfOWZWayfEsNQzTDBVW8PZ6TUUN1uFTBQbF2Chv/+sjenE86lpiEwj2FiviSmSZ4Ap4MaAfl1ciF4aSA==", "cpu": [ "arm64" ], @@ -1864,9 +2011,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.3.tgz", - "integrity": "sha512-T1l7y/bCeL/kUwh9OD4PQT4aM7Bq43vX05htPJJ46RTI4r5KNt6qJRzAfNfM+OYMNEVBWQzR2Gyk+FXLZfogGw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.16.4.tgz", + "integrity": "sha512-9m/ZDrQsdo/c06uOlP3W9G2ENRVzgzbSXmXHT4hwVaDQhYcRpi9bgBT0FTG9OhESxwK0WjQxYOSfv40cU+T69w==", "cpu": [ "ia32" ], @@ -1877,9 +2024,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.3.tgz", - "integrity": "sha512-/BypzV0H1y1HzgYpxqRaXGBRqfodgoBBCcsrujT6QRcakDQdfU+Lq9PENPh5jB4I44YWq+0C2eHsHya+nZY1sA==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.16.4.tgz", + "integrity": "sha512-YunpoOAyGLDseanENHmbFvQSfVL5BxW3k7hhy0eN4rb3gS/ct75dVD0EXOWIqFT/nE8XYW6LP6vz6ctKRi0k9A==", "cpu": [ "x64" ], @@ -1902,9 +2049,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.9", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.9.tgz", - "integrity": "sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg==", + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", "dev": true, "dependencies": { "@types/estree": "*", @@ -1995,27 +2142,31 @@ "node_modules/@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "optional": true, + "peer": true }, "node_modules/@types/whatwg-url": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.4.tgz", "integrity": "sha512-lXCmTWSHJvf0TRSO58nm978b8HJ/EdsSsEKLd3ODHFjo+3VGAyyTp4v50nWvwtzBxSMQrVOK7tcuN0zGPLICMw==", + "optional": true, + "peer": true, "dependencies": { "@types/webidl-conversions": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz", - "integrity": "sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", + "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/type-utils": "7.6.0", - "@typescript-eslint/utils": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/type-utils": "7.7.1", + "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.3.1", @@ -2041,15 +2192,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.6.0.tgz", - "integrity": "sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz", + "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/typescript-estree": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4" }, "engines": { @@ -2069,13 +2220,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz", - "integrity": "sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", + "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0" + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2086,13 +2237,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz", - "integrity": "sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", + "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.6.0", - "@typescript-eslint/utils": "7.6.0", + "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/utils": "7.7.1", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2113,9 +2264,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.6.0.tgz", - "integrity": "sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", + "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2126,13 +2277,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz", - "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", + "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/visitor-keys": "7.6.0", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/visitor-keys": "7.7.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2183,17 +2334,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz", - "integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", + "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.15", "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.6.0", - "@typescript-eslint/types": "7.6.0", - "@typescript-eslint/typescript-estree": "7.6.0", + "@typescript-eslint/scope-manager": "7.7.1", + "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/typescript-estree": "7.7.1", "semver": "^7.6.0" }, "engines": { @@ -2208,12 +2359,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz", - "integrity": "sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", + "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.6.0", + "@typescript-eslint/types": "7.7.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -3213,6 +3364,8 @@ "version": "6.6.0", "resolved": "https://registry.npmjs.org/bson/-/bson-6.6.0.tgz", "integrity": "sha512-BVINv2SgcMjL4oYbBuCQTpE3/VKOSxrOA8Cj/wQP7izSzlBGVomdm+TcUd0Pzy0ytLSSDweCKQ6X3f5veM5LQA==", + "optional": true, + "peer": true, "engines": { "node": ">=16.20.1" } @@ -3240,6 +3393,11 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3308,9 +3466,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001610", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001610.tgz", - "integrity": "sha512-QFutAY4NgaelojVMjY63o6XlZyORPaLfyMnsl3HgnWdJUcX6K0oaJymHjH8PT5Gk7sTm8rvC/c5COUQKXqmOMA==", + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", "dev": true, "funding": [ { @@ -3624,9 +3782,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", - "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", + "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", "dev": true, "dependencies": { "browserslist": "^4.23.0" @@ -3929,10 +4087,18 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/electron-to-chromium": { - "version": "1.4.736", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.736.tgz", - "integrity": "sha512-Rer6wc3ynLelKNM4lOCg7/zPQj8tPOCB2hzD32PX9wd3hgRRi9MxEbmkFCokzcEhRVMiOVLjnL9ig9cefJ+6+Q==", + "version": "1.4.746", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.746.tgz", + "integrity": "sha512-jeWaIta2rIG2FzHaYIhSuVWqC6KJYo7oSBX4Jv7g+aVujKztfvdpf+n6MGwZdC5hQXbax4nntykLH2juIQrfPg==", "dev": true }, "node_modules/emoji-regex": { @@ -6314,7 +6480,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, "bin": { "is-docker": "cli.js" }, @@ -6600,7 +6765,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, "dependencies": { "is-docker": "^2.0.0" }, @@ -6743,6 +6907,65 @@ "node": ">=0.10.0" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken/node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -6753,14 +6976,15 @@ } }, "node_modules/langchain": { - "version": "0.1.33", - "resolved": "https://registry.npmjs.org/langchain/-/langchain-0.1.33.tgz", - "integrity": "sha512-IrRd839x8eAmDutHNDMHGzIjufyWt/ckJrnRB2WifIJmtLWNRNQo5jZd7toeBU0UOVOQxoPtQGYf8lR0ar7vIQ==", + "version": "0.1.36", + "resolved": "https://registry.npmjs.org/langchain/-/langchain-0.1.36.tgz", + "integrity": "sha512-NTbnCL/jKWIeEI//Nm1oG8nhW3vkYWvEMr1MPotmTThTfeKfO87eV/OAzAyh6Ruy6GFs/qofRgQZGIe6XvXTNQ==", "dependencies": { "@anthropic-ai/sdk": "^0.9.1", "@langchain/community": "~0.0.47", - "@langchain/core": "~0.1.56", + "@langchain/core": "~0.1.60", "@langchain/openai": "~0.0.28", + "@langchain/textsplitters": "~0.0.0", "binary-extensions": "^2.2.0", "js-tiktoken": "^1.0.7", "js-yaml": "^4.1.0", @@ -6789,6 +7013,7 @@ "@gomomento/sdk-web": "^1.51.1", "@google-ai/generativelanguage": "^0.2.1", "@google-cloud/storage": "^6.10.1 || ^7.7.0", + "@mendable/firecrawl-js": "^0.0.13", "@notionhq/client": "^2.2.10", "@pinecone-database/pinecone": "*", "@supabase/supabase-js": "^2.10.0", @@ -6861,6 +7086,9 @@ "@google-cloud/storage": { "optional": true }, + "@mendable/firecrawl-js": { + "optional": true + }, "@notionhq/client": { "optional": true }, @@ -6999,11 +7227,11 @@ } }, "node_modules/langchain/node_modules/zod-to-json-schema": { - "version": "3.22.5", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.22.5.tgz", - "integrity": "sha512-+akaPo6a0zpVCCseDed504KBJUQpEW5QZw7RMneNmKw+fGaML1Z9tUNLnHHAC8x6dzVRO1eB2oEMyZRnuBZg7Q==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.0.tgz", + "integrity": "sha512-az0uJ243PxsRIa2x1WmNE/pnuA05gUq/JB8Lwe1EDCCL/Fz9MgjYQ0fPlyc2Tcv6aF2ZA7WM5TWaRZVEFaAIag==", "peerDependencies": { - "zod": "^3.22.4" + "zod": "^3.23.3" } }, "node_modules/langchainhub": { @@ -7012,9 +7240,9 @@ "integrity": "sha512-Woyb8YDHgqqTOZvWIbm2CaFDGfZ4NTSyXV687AG4vXEfoNo7cGQp7nhl7wL3ehenKWmNEmcxCLgOZzW8jE6lOQ==" }, "node_modules/langsmith": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.1.14.tgz", - "integrity": "sha512-iEzQLLB7/0nRpAwNBAR7B7N64fyByg5UsNjSvLaCCkQ9AS68PSafjB8xQkyI8QXXrGjU1dEqDRoa8m4SUuRdUw==", + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.1.18.tgz", + "integrity": "sha512-LHk0aIFAl3/iiKvUzAiM8Xdm13bRO70XERQeHCF99fL2X815Jc47nxu6m7usSuQC8sw6rirCKZbGm18cqdUEzA==", "dependencies": { "@types/uuid": "^9.0.1", "commander": "^10.0.1", @@ -7152,9 +7380,9 @@ } }, "node_modules/lit": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.2.tgz", - "integrity": "sha512-VZx5iAyMtX7CV4K8iTLdCkMaYZ7ipjJZ0JcSdJ0zIdGxxyurjIn7yuuSxNBD7QmjvcNJwr0JS4cAdAtsy7gZ6w==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.3.tgz", + "integrity": "sha512-l4slfspEsnCcHVRTvaP7YnkTZEZggNFywLEIhQaGhYDczG+tu/vlgm/KaWIEjIp+ZyV20r2JnZctMb8LeLCG7Q==", "dependencies": { "@lit/reactive-element": "^2.0.4", "lit-element": "^4.0.4", @@ -7253,9 +7481,9 @@ } }, "node_modules/lit-element": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.4.tgz", - "integrity": "sha512-98CvgulX6eCPs6TyAIQoJZBCQPo80rgXR+dVBs61cstJXqtI+USQZAbA4gFHh6L/mxBx9MrgPLHLsUgDUHAcCQ==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.5.tgz", + "integrity": "sha512-iTWskWZEtn9SyEf4aBG6rKT8GABZMrTWop1+jopsEOgEcugcXJGKuX5bEbkq9qfzY+XB4MAgCaSPwnNpdsNQ3Q==", "dependencies": { "@lit-labs/ssr-dom-shim": "^1.2.0", "@lit/reactive-element": "^2.0.4", @@ -7263,9 +7491,9 @@ } }, "node_modules/lit-html": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.1.2.tgz", - "integrity": "sha512-3OBZSUrPnAHoKJ9AMjRL/m01YJxQMf+TMHanNtTHG68ubjnZxK0RFl102DPzsw4mWnHibfZIBJm3LWCZ/LmMvg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.1.3.tgz", + "integrity": "sha512-FwIbqDD8O/8lM4vUZ4KvQZjPPNx7V1VhT7vmRB8RBAO0AU6wuTVdoXiu2CivVjEGdugvcbPNBLtPE1y0ifplHA==", "dependencies": { "@types/trusted-types": "^2.0.2" } @@ -7313,12 +7541,47 @@ "integrity": "sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==", "dev": true }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/log-symbols": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", @@ -7451,7 +7714,9 @@ "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true, + "peer": true }, "node_modules/meow": { "version": "13.2.0", @@ -7631,6 +7896,8 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.5.0.tgz", "integrity": "sha512-Fozq68InT+JKABGLqctgtb8P56pRrJFkbhW0ux+x1mdHeyinor8oNzJqwLjV/t5X5nJGfTlluxfyMnOXNggIUA==", + "optional": true, + "peer": true, "dependencies": { "@mongodb-js/saslprep": "^1.1.5", "bson": "^6.4.0", @@ -7676,6 +7943,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.0.tgz", "integrity": "sha512-t1Vf+m1I5hC2M5RJx/7AtxgABy1cZmIPQRMXw+gEIPn/cZNF3Oiy+l0UIypUwVB5trcWHq3crg2g3uAR9aAwsQ==", + "optional": true, + "peer": true, "dependencies": { "@types/whatwg-url": "^11.0.2", "whatwg-url": "^13.0.0" @@ -7686,6 +7955,14 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -7723,9 +8000,9 @@ "peer": true }, "node_modules/node-abi": { - "version": "3.57.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.57.0.tgz", - "integrity": "sha512-Dp+A9JWxRaKuHP35H77I4kCKesDy5HUDEmScia2FyncMTOXASMyg251F5PhFoDA5uqBrDDffiLpbqnrZmNXW+g==", + "version": "3.62.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.62.0.tgz", + "integrity": "sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==", "dependencies": { "semver": "^7.3.5" }, @@ -8002,7 +8279,6 @@ "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dev": true, "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", @@ -8144,15 +8420,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, "engines": { "node": ">=8" } }, "node_modules/openai": { - "version": "4.33.1", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.33.1.tgz", - "integrity": "sha512-0DH572aSxGTT1JPOXgJQ9mjiuSPg/7scPot8hLc5I1mfQxPxLXTZWJpWerKaIWOuPkR2nrB0SamGDEehH8RuWA==", + "version": "4.38.3", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.38.3.tgz", + "integrity": "sha512-mIL9WtrFNOanpx98mJ+X/wkoepcxdqqu0noWFoNQHl/yODQ47YM7NEYda7qp8JfjqpLFVxY9mQhshoS/Fqac0A==", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", @@ -8595,6 +8870,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "devOptional": true, "engines": { "node": ">=6" } @@ -8953,9 +9229,9 @@ } }, "node_modules/rollup": { - "version": "4.14.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.3.tgz", - "integrity": "sha512-ag5tTQKYsj1bhrFC9+OEWqb5O6VYgtQDO9hPDBMmIbePwhfSr+ExlcU741t8Dhw5DkPCQf6noz0jb36D6W9/hw==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.16.4.tgz", + "integrity": "sha512-kuaTJSUbz+Wsb2ATGvEknkI12XV40vIiHmLuFlejoo7HtDok/O5eDDD0UpCVY5bBX5U5RYo8wWP83H7ZsqVEnA==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -8968,22 +9244,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.14.3", - "@rollup/rollup-android-arm64": "4.14.3", - "@rollup/rollup-darwin-arm64": "4.14.3", - "@rollup/rollup-darwin-x64": "4.14.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.14.3", - "@rollup/rollup-linux-arm-musleabihf": "4.14.3", - "@rollup/rollup-linux-arm64-gnu": "4.14.3", - "@rollup/rollup-linux-arm64-musl": "4.14.3", - "@rollup/rollup-linux-powerpc64le-gnu": "4.14.3", - "@rollup/rollup-linux-riscv64-gnu": "4.14.3", - "@rollup/rollup-linux-s390x-gnu": "4.14.3", - "@rollup/rollup-linux-x64-gnu": "4.14.3", - "@rollup/rollup-linux-x64-musl": "4.14.3", - "@rollup/rollup-win32-arm64-msvc": "4.14.3", - "@rollup/rollup-win32-ia32-msvc": "4.14.3", - "@rollup/rollup-win32-x64-msvc": "4.14.3", + "@rollup/rollup-android-arm-eabi": "4.16.4", + "@rollup/rollup-android-arm64": "4.16.4", + "@rollup/rollup-darwin-arm64": "4.16.4", + "@rollup/rollup-darwin-x64": "4.16.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.16.4", + "@rollup/rollup-linux-arm-musleabihf": "4.16.4", + "@rollup/rollup-linux-arm64-gnu": "4.16.4", + "@rollup/rollup-linux-arm64-musl": "4.16.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.16.4", + "@rollup/rollup-linux-riscv64-gnu": "4.16.4", + "@rollup/rollup-linux-s390x-gnu": "4.16.4", + "@rollup/rollup-linux-x64-gnu": "4.16.4", + "@rollup/rollup-linux-x64-musl": "4.16.4", + "@rollup/rollup-win32-arm64-msvc": "4.16.4", + "@rollup/rollup-win32-ia32-msvc": "4.16.4", + "@rollup/rollup-win32-x64-msvc": "4.16.4", "fsevents": "~2.3.2" } }, @@ -9351,6 +9627,8 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "peer": true, "dependencies": { "memory-pager": "^1.0.2" } @@ -9393,6 +9671,15 @@ "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -9713,9 +10000,9 @@ } }, "node_modules/terser": { - "version": "5.30.3", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", - "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", + "version": "5.30.4", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.4.tgz", + "integrity": "sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==", "dev": true, "peer": true, "dependencies": { @@ -9808,6 +10095,8 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "optional": true, + "peer": true, "dependencies": { "punycode": "^2.3.0" }, @@ -10112,9 +10401,9 @@ } }, "node_modules/vite": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", - "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", + "version": "5.2.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz", + "integrity": "sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==", "dev": true, "dependencies": { "esbuild": "^0.20.1", @@ -10273,6 +10562,8 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "optional": true, + "peer": true, "engines": { "node": ">=12" } @@ -10387,6 +10678,8 @@ "version": "13.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "optional": true, + "peer": true, "dependencies": { "tr46": "^4.1.1", "webidl-conversions": "^7.0.0" @@ -10732,9 +11025,9 @@ } }, "node_modules/zod": { - "version": "3.22.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", - "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "version": "3.23.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.3.tgz", + "integrity": "sha512-tPvq1B/2Yu/dh2uAIH2/BhUlUeLIUvAjr6dpL/75I0pCYefHgjhXk1o1Kob3kTU8C7yU1j396jFHlsVWFi9ogg==", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -10752,14 +11045,15 @@ "license": "MIT", "dependencies": { "@azure/functions": "^4.0.0", + "@azure/identity": "^4.1.0", + "@azure/search-documents": "^12.0.0", "@azure/storage-blob": "^12.17.0", - "@langchain/azure-openai": "^0.0.7", - "@langchain/community": "^0.0.48", - "@langchain/core": "^0.1.51", + "@langchain/azure-openai": "^0.0.8", + "@langchain/community": "^0.0.53", + "@langchain/core": "^0.1.61", "dotenv": "^16.4.5", "faiss-node": "^0.5.1", - "langchain": "^0.1.31", - "mongodb": "^6.5.0", + "langchain": "^0.1.36", "pdf-parse": "^1.1.1" }, "devDependencies": { diff --git a/package.json b/package.json index 391c220..48ca6fc 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "azure", "azure-functions", "azure-static-web-apps", - "azure-cosmos-db", + "azure-ai-search", "mongodb" ], "author": "Microsoft", diff --git a/packages/api/package.json b/packages/api/package.json index 0014a49..dde7901 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -15,14 +15,15 @@ "license": "MIT", "dependencies": { "@azure/functions": "^4.0.0", + "@azure/identity": "^4.1.0", + "@azure/search-documents": "^12.0.0", "@azure/storage-blob": "^12.17.0", - "@langchain/azure-openai": "^0.0.7", - "@langchain/community": "^0.0.48", - "@langchain/core": "^0.1.51", + "@langchain/azure-openai": "^0.0.8", + "@langchain/community": "^0.0.53", + "@langchain/core": "^0.1.61", "dotenv": "^16.4.5", "faiss-node": "^0.5.1", - "langchain": "^0.1.31", - "mongodb": "^6.5.0", + "langchain": "^0.1.36", "pdf-parse": "^1.1.1" }, "devDependencies": { diff --git a/packages/api/src/functions/chat-post.ts b/packages/api/src/functions/chat-post.ts index ee8b776..c4ab247 100644 --- a/packages/api/src/functions/chat-post.ts +++ b/packages/api/src/functions/chat-post.ts @@ -10,12 +10,13 @@ import { ChatOllama } from '@langchain/community/chat_models/ollama'; import { FaissStore } from '@langchain/community/vectorstores/faiss'; import { ChatPromptTemplate, PromptTemplate } from '@langchain/core/prompts'; import { createStuffDocumentsChain } from 'langchain/chains/combine_documents'; -import { AzureCosmosDBVectorStore } from '@langchain/community/vectorstores/azure_cosmosdb'; +import { AzureAISearchVectorStore } from '@langchain/community/vectorstores/azure_aisearch'; import { createRetrievalChain } from 'langchain/chains/retrieval'; import 'dotenv/config'; import { badRequest, data, serviceUnavailable } from '../http-response'; import { ollamaChatModel, ollamaEmbeddingsModel, faissStoreFolder } from '../constants'; import { ChatRequest, ChatResponseChunk } from '../models'; +import { getCredentials } from '../security'; const systemPrompt = `Assistant helps the Consto Real Estate company customers with questions and support requests. Be brief in your answers. Answer only in plain text format. Answer ONLY with information from the sources below. If there isn't enough information in the sources, say you don't know. Do not generate answers that don't use the sources. If asking a clarifying question to the user would help, ask the question. @@ -55,10 +56,11 @@ export async function postChat(request: HttpRequest, context: InvocationContext) let store: VectorStore; if (azureOpenAiEndpoint) { + const credentials = getCredentials(); // Initialize models and vector database - embeddings = new AzureOpenAIEmbeddings(); - model = new AzureChatOpenAI(); - store = new AzureCosmosDBVectorStore(embeddings, {}); + embeddings = new AzureOpenAIEmbeddings({ credentials }); + model = new AzureChatOpenAI({ credentials }); + store = new AzureAISearchVectorStore(embeddings, { credentials }); } else { // If no environment variables are set, it means we are running locally context.log('No Azure OpenAI endpoint set, using Ollama models and local DB'); @@ -74,7 +76,7 @@ export async function postChat(request: HttpRequest, context: InvocationContext) ['system', systemPrompt], ['human', '{input}'], ]), - documentPrompt: PromptTemplate.fromTemplate('{filename}: {page_content}\n'), + documentPrompt: PromptTemplate.fromTemplate('{source}: {page_content}\n'), }); // Create the chain to retrieve the documents from the database diff --git a/packages/api/src/functions/documents-get.ts b/packages/api/src/functions/documents-get.ts index 0683f4f..ec2b509 100644 --- a/packages/api/src/functions/documents-get.ts +++ b/packages/api/src/functions/documents-get.ts @@ -6,19 +6,22 @@ import { HttpRequest, HttpResponseInit, InvocationContext, app } from '@azure/fu import { BlobServiceClient } from '@azure/storage-blob'; import 'dotenv/config'; import { data, notFound } from '../http-response'; +import { getCredentials } from '../security'; async function getDocument(request: HttpRequest, context: InvocationContext): Promise { - const connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING; + const storageUrl = process.env.AZURE_STORAGE_URL; const containerName = process.env.AZURE_STORAGE_CONTAINER_NAME; const { fileName } = request.params; try { let fileData: Uint8Array; - if (connectionString && containerName) { + if (storageUrl && containerName) { // Retrieve the file from Azure Blob Storage context.log(`Reading blob from: "${containerName}/${fileName}"`); - const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString); + + const credentials = getCredentials(); + const blobServiceClient = new BlobServiceClient(storageUrl, credentials); const containerClient = blobServiceClient.getContainerClient(containerName); const response = await containerClient.getBlobClient(fileName).download(); diff --git a/packages/api/src/functions/documents-post.ts b/packages/api/src/functions/documents-post.ts index 1db4e66..9d0e8b9 100644 --- a/packages/api/src/functions/documents-post.ts +++ b/packages/api/src/functions/documents-post.ts @@ -2,16 +2,17 @@ import { HttpRequest, HttpResponseInit, InvocationContext, app } from '@azure/fu import { AzureOpenAIEmbeddings } from '@langchain/azure-openai'; import { PDFLoader } from 'langchain/document_loaders/fs/pdf'; import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter'; -import { AzureCosmosDBVectorStore } from '@langchain/community/vectorstores/azure_cosmosdb'; +import { AzureAISearchVectorStore } from '@langchain/community/vectorstores/azure_aisearch'; import { OllamaEmbeddings } from '@langchain/community/embeddings/ollama'; import { FaissStore } from '@langchain/community/vectorstores/faiss'; import 'dotenv/config'; import { BlobServiceClient } from '@azure/storage-blob'; import { badRequest, serviceUnavailable, ok } from '../http-response'; import { ollamaEmbeddingsModel, faissStoreFolder } from '../constants'; +import { getCredentials } from '../security'; export async function postDocuments(request: HttpRequest, context: InvocationContext): Promise { - const connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING; + const storageUrl = process.env.AZURE_STORAGE_URL; const containerName = process.env.AZURE_STORAGE_CONTAINER_NAME; const azureOpenAiEndpoint = process.env.AZURE_OPENAI_API_ENDPOINT; @@ -31,7 +32,7 @@ export async function postDocuments(request: HttpRequest, context: InvocationCon splitPages: false, }); const rawDocument = await loader.load(); - rawDocument[0].metadata.filename = filename; + rawDocument[0].metadata.source = filename; // Split the text into smaller chunks const splitter = new RecursiveCharacterTextSplitter({ @@ -42,9 +43,9 @@ export async function postDocuments(request: HttpRequest, context: InvocationCon // Generate embeddings and save in database if (azureOpenAiEndpoint) { - const store = await AzureCosmosDBVectorStore.fromDocuments(documents, new AzureOpenAIEmbeddings(), {}); - await store.createIndex(); - await store.close(); + const credentials = getCredentials(); + const embeddings = new AzureOpenAIEmbeddings({ credentials }); + await AzureAISearchVectorStore.fromDocuments(documents, embeddings, { credentials }); } else { // If no environment variables are set, it means we are running locally context.log('No Azure OpenAI endpoint set, using Ollama models and local DB'); @@ -53,10 +54,11 @@ export async function postDocuments(request: HttpRequest, context: InvocationCon await store.save(faissStoreFolder); } - if (connectionString && containerName) { + if (storageUrl && containerName) { // Upload the PDF file to Azure Blob Storage context.log(`Uploading file to blob storage: "${containerName}/${filename}"`); - const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString); + const credentials = getCredentials(); + const blobServiceClient = new BlobServiceClient(storageUrl, credentials); const containerClient = blobServiceClient.getContainerClient(containerName); const blockBlobClient = containerClient.getBlockBlobClient(filename); const buffer = await file.arrayBuffer(); diff --git a/packages/api/src/security.ts b/packages/api/src/security.ts new file mode 100644 index 0000000..db6af9d --- /dev/null +++ b/packages/api/src/security.ts @@ -0,0 +1,11 @@ +import { DefaultAzureCredential } from '@azure/identity'; + +let credentials: DefaultAzureCredential | undefined; + +export function getCredentials(): DefaultAzureCredential { + // Use the current user identity to authenticate. + // No secrets needed, it uses `az login` or `azd auth login` locally, + // and managed identity when deployed on Azure. + credentials ||= new DefaultAzureCredential(); + return credentials; +}