diff --git a/cli/magic-config.ts b/cli/magic-config.ts index 008040fdb..40ff5867b 100644 --- a/cli/magic-config.ts +++ b/cli/magic-config.ts @@ -151,6 +151,7 @@ const embeddingModels = [ options.bedrockRoleArn = config.bedrock?.roleArn; options.guardrailsEnable = config.bedrock?.guardrails?.enabled; options.guardrails = config.bedrock?.guardrails; + options.bedrockAgents = config.bedrock?.agents; options.sagemakerModels = config.llms?.sagemaker ?? []; options.enableSagemakerModels = config.llms?.sagemaker ? config.llms?.sagemaker.length > 0 @@ -343,6 +344,17 @@ async function processCreateOptions(options: any): Promise { }, initial: options.guardrails?.version ?? "DRAFT", }, + { + type: "confirm", + name: "bedrockAgents", + message: "Do you want to deploy a sample Bedrock Agent?", + initial: options.bedrockAgents ?? false, + skip() { + return !["us-east-1", "us-west-2"].includes( + (this as any).state.answers.bedrockRegion + ); + }, + }, { type: "confirm", name: "enableSagemakerModels", @@ -461,8 +473,9 @@ async function processCreateOptions(options: any): Promise { { type: "input", name: "sagemakerCronStopSchedule", - hint: "This cron format is using AWS eventbridge cron syntax see docs for more information", - message: "Stop schedule for Sagmaker models expressed in AWS cron format", + hint: "This cron format is using AWS EventBridge cron syntax see docs for more information", + message: + "Stop schedule for Sagemaker models expressed in AWS cron format", skip(): boolean { return !(this as any).state.answers.enableCronFormat.includes("cron"); }, @@ -1151,6 +1164,7 @@ async function processCreateOptions(options: any): Promise { identifier: answers.guardrailsIdentifier, version: answers.guardrailsVersion, }, + agents: answers.bedrockAgents, } : undefined, llms: { diff --git a/lib/agents/index.ts b/lib/agents/index.ts new file mode 100644 index 000000000..1f0550f49 --- /dev/null +++ b/lib/agents/index.ts @@ -0,0 +1,161 @@ +import * as cdk from "aws-cdk-lib"; +import { Construct } from "constructs"; +import * as lambda from "aws-cdk-lib/aws-lambda"; +import * as iam from "aws-cdk-lib/aws-iam"; +import * as path from "path"; +import * as geo from "aws-cdk-lib/aws-location"; +import { bedrock } from "@cdklabs/generative-ai-cdk-constructs"; +import { Bucket } from "aws-cdk-lib/aws-s3"; +import { BucketDeployment, Source } from "aws-cdk-lib/aws-s3-deployment"; +import { VectorIndex } from "@cdklabs/generative-ai-cdk-constructs/lib/cdk-lib/opensearch-vectorindex"; +import { VectorCollection } from "@cdklabs/generative-ai-cdk-constructs/lib/cdk-lib/opensearchserverless"; +import { NagSuppressions } from "cdk-nag"; + +export class BedrockWeatherAgent extends Construct { + constructor(scope: Construct, id: string) { + super(scope, id); + + const powertools = lambda.LayerVersion.fromLayerVersionArn( + this, + "powertools", + `arn:aws:lambda:${ + cdk.Stack.of(this).region + }:017000801446:layer:AWSLambdaPowertoolsPythonV2:58` + ); + + const placeIndex = new geo.CfnPlaceIndex(this, "place-index", { + dataSource: "Esri", + indexName: "PlaceIndex", + pricingPlan: "RequestBasedUsage", + }); + + const vectorStore = new VectorCollection(this, "vector-collection"); + const vectorIndex = new VectorIndex(this, "vector-index", { + collection: vectorStore, + indexName: "weather", + vectorField: "vector", + vectorDimensions: 1536, + mappings: [ + { + mappingField: "AMAZON_BEDROCK_TEXT_CHUNK", + dataType: "text", + filterable: true, + }, + { + mappingField: "AMAZON_BEDROCK_METADATA", + dataType: "text", + filterable: false, + }, + ], + }); + + const modulesLayer = new lambda.LayerVersion(this, "modules-layer", { + code: lambda.Code.fromDockerBuild( + path.join(__dirname, "weather/modules") + ), + compatibleRuntimes: [lambda.Runtime.PYTHON_3_12], + description: "Layer with required modules for the agent", + }); + + const weather = new lambda.Function(this, "weather", { + runtime: lambda.Runtime.PYTHON_3_12, + description: + "Lambda function that implements APIs to retrieve weather data", + code: lambda.Code.fromAsset(path.join(__dirname, "weather")), + handler: "lambda.handler", + environment: { + LOCATION_INDEX: placeIndex.indexName, + }, + memorySize: 512, + timeout: cdk.Duration.seconds(10), + layers: [powertools, modulesLayer], + }); + + const policy = new iam.Policy(this, "weather-policy", { + statements: [ + new iam.PolicyStatement({ + actions: ["geo:SearchPlaceIndexForText"], + resources: ["*"], + }), + ], + }); + weather.role?.attachInlinePolicy(policy); + + const kb = new bedrock.KnowledgeBase(this, "weather-kb", { + embeddingsModel: bedrock.BedrockFoundationModel.TITAN_EMBED_TEXT_V1, + vectorField: "vector", + vectorIndex: vectorIndex, + vectorStore: vectorStore, + indexName: "weather", + instruction: "answers questions about WMO and metereology", + }); + + const bucket = new Bucket(this, "bedrock-kb-datasource-bucket", { + enforceSSL: true, + }); + + const keyPrefix = "my-docs"; + new bedrock.S3DataSource(this, "my-docs-datasource", { + bucket: bucket, + dataSourceName: "my-docs", + knowledgeBase: kb, + inclusionPrefixes: [keyPrefix], + }); + + const agent = new bedrock.Agent(this, "weather-agent", { + foundationModel: + bedrock.BedrockFoundationModel.ANTHROPIC_CLAUDE_INSTANT_V1_2, + instruction: `You are a weather expert and answer user question about weather in different places. +If you are asked to provide historical date, you need to answer with a summary of the weather over the period. +You answer the questions in the same language they have been asked.`, + description: "an agent to interact with a weather api", + knowledgeBases: [kb], + name: "WeatherTeller", + }); + + agent.addActionGroup({ + actionGroupExecutor: weather, + apiSchema: bedrock.ApiSchema.fromAsset( + path.join(__dirname, "weather", "schema.json") + ), + actionGroupState: "ENABLED", + }); + + agent.addActionGroup({ + parentActionGroupSignature: "AMAZON.UserInput", + actionGroupState: "ENABLED", + actionGroupName: "UserInputAction", + }); + + new BucketDeployment(this, "my-docs-files", { + destinationBucket: bucket, + destinationKeyPrefix: keyPrefix, + sources: [Source.asset(path.join(__dirname, "my-documents"))], + }); + + new cdk.CfnOutput(this, "weather-function-name", { + value: weather.functionName, + }); + + NagSuppressions.addResourceSuppressions(weather.role!, [ + { + id: "AwsSolutions-IAM4", + reason: "IAM role implicitly created by CDK.", + }, + ]); + + NagSuppressions.addResourceSuppressions(policy, [ + { + id: "AwsSolutions-IAM5", + reason: "IAM role implicitly created by CDK.", + }, + ]); + + NagSuppressions.addResourceSuppressions(bucket, [ + { + id: "AwsSolutions-S1", + reason: "Access logs not required", + }, + ]); + } +} diff --git a/lib/agents/my-documents/README.md b/lib/agents/my-documents/README.md new file mode 100644 index 000000000..2749f91bc --- /dev/null +++ b/lib/agents/my-documents/README.md @@ -0,0 +1 @@ +Add your documents to this folder to get them uploaded diff --git a/lib/agents/weather/event.json b/lib/agents/weather/event.json new file mode 100644 index 000000000..ca1b688ad --- /dev/null +++ b/lib/agents/weather/event.json @@ -0,0 +1,34 @@ +{ + "messageVersion": "1.0", + "agent": { + "name": "alfa", + "id": "beta", + "alias": "alfa", + "version": "1.2" + }, + "inputText": "any text", + "sessionId": "1234", + "actionGroup": "mygroup", + "apiPath": "/current_weather", + "httpMethod": "GET", + "parameters": [ + { + "name": "place", + "type": "string", + "value": "Milan" + } + ], + "requestBody": { + "content": { + "application/json": { + "properties": [ + { + "name": "place", + "type": "string", + "value": "Milan" + } + ] + } + } + } +} diff --git a/lib/agents/weather/lambda.py b/lib/agents/weather/lambda.py new file mode 100644 index 000000000..4c8a4a76b --- /dev/null +++ b/lib/agents/weather/lambda.py @@ -0,0 +1,140 @@ +from aws_lambda_powertools import Tracer +from aws_lambda_powertools.event_handler import BedrockAgentResolver +from aws_lambda_powertools.event_handler.openapi.params import Query +from pydantic import BaseModel +from typing import List +import boto3 +import os +import requests +from typing import Annotated +import pandas as pd +import datetime + +tracer = Tracer() + + +class Weather(BaseModel): + time: str + temperature: str + precipitation: str + + +class Period(BaseModel): + start_date: str + end_date: str + + +app = BedrockAgentResolver() + + +def get_metric_and_unit(w: dict, name: str) -> str: + return f"{w['current'][name]} {w['current_units'][name]}" + + +@app.get("/current_weather", description="get the current weather for a given place") +def get_current_weather( + place: Annotated[str, Query(description="the name of the place")] +) -> Weather: + resp = loc_client.search_place_index_for_text( + IndexName=os.environ.get( + "LOCATION_INDEX", os.environ.get("PLACE_INDEX", "Test") + ), + Text=place, + ) + [lon, lat] = resp["Results"][0]["Place"]["Geometry"]["Point"] + q = ( + "https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}" + + "¤t=temperature_2m,precipitation" + ) + w = requests.get(q.format(lat=lat, lon=lon)).json() + + return Weather( + time=w["current"]["time"], + temperature=get_metric_and_unit(w, "temperature_2m"), + precipitation=get_metric_and_unit(w, "precipitation"), + ) + + +@app.get( + "/absolute_period_dates", + description="get the absolute start and end date for a period in YYYY-MM-DD" + + " format given the number of day difference from the today", +) +def get_absolute_period_dates( + startPeriodDeltaDays: Annotated[ + int, + Query( + description="the difference in days from the today" + + " to the start date of the period" + ), + ], + endPeriodDeltaDays: Annotated[ + int, + Query( + description="the difference in days from the today" + + " to the end date of the period" + ), + ], +) -> Period: + today = datetime.date.today() + p = Period() + p.start_date = (today - datetime.timedelta(startPeriodDeltaDays)).isoformat() + p.end_date = (today - datetime.timedelta(endPeriodDeltaDays)).isoformat() + return p + + +@app.get( + "/historical_weather", + description="get the historical daily mean temperature and precipitation" + + " for a given place for a range of dates", +) +def get_historical_weather( + place: Annotated[str, Query(description="the name of the place")], + fromDate: Annotated[str, Query(description="starting date in YYYY-MM-DD format")], + toDate: Annotated[str, Query(description="ending date in YYYY-MM-DD format")], +) -> List[Weather]: + resp = loc_client.search_place_index_for_text( + IndexName=os.environ.get( + "LOCATION_INDEX", os.environ.get("PLACE_INDEX", "Test") + ), + Text=place, + ) + [lon, lat] = resp["Results"][0]["Place"]["Geometry"]["Point"] + q = ( + "https://archive-api.open-meteo.com/v1/archive?latitude={lat}&longitude={lon}" + + "&start_date={fromDate}&end_date={toDate}&hourly=temperature_2m,precipitation" + ) + resp = requests.get( + q.format(lat=lat, lon=lon, fromDate=fromDate, toDate=toDate) + ).json() + hourly_values = pd.DataFrame(resp["hourly"]) + hourly_values["time"] = pd.to_datetime(hourly_values["time"]) + hourly_values = hourly_values.set_index("time") + hourly_values = hourly_values.resample("D").agg( + {"temperature_2m": "mean", "precipitation": "sum"} + ) + return [ + Weather( + time=str(hourly_values.iloc[i].name).split(" ")[0], + temperature=hourly_values.iloc[i][0], + precipitation=hourly_values.iloc[i][1], + ) + for i in range(hourly_values.shape[0]) + ] + + +def handler(event, context): + print(event) + resp = app.resolve(event, context) + print(resp) + return resp + + +if __name__ == "__main__": + with open("schema.json", "w") as f: + f.write(app.get_openapi_json_schema()) +else: + sess = boto3.Session( + region_name=os.environ.get("LOCATION_AWS_REGION", os.environ.get("AWS_REGION")) + ) + loc_client = sess.client("location") diff --git a/lib/agents/weather/modules/Dockerfile b/lib/agents/weather/modules/Dockerfile new file mode 100644 index 000000000..7f91218b0 --- /dev/null +++ b/lib/agents/weather/modules/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.12-slim + +RUN apt update -y && apt install zip -y + +ADD requirements.txt . + +RUN mkdir -p /asset/python && pip install -r requirements.txt -t /asset/python diff --git a/lib/agents/weather/modules/requirements.txt b/lib/agents/weather/modules/requirements.txt new file mode 100644 index 000000000..d7689b616 --- /dev/null +++ b/lib/agents/weather/modules/requirements.txt @@ -0,0 +1,2 @@ +requests==2.29 +pandas==2.2 \ No newline at end of file diff --git a/lib/agents/weather/schema.json b/lib/agents/weather/schema.json new file mode 100644 index 000000000..5ad986711 --- /dev/null +++ b/lib/agents/weather/schema.json @@ -0,0 +1,257 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Powertools API", + "version": "1.0.0" + }, + "servers": [ + { + "url": "/" + } + ], + "paths": { + "/current_weather": { + "get": { + "summary": "GET /current_weather", + "description": "get the current weather for a given place", + "operationId": "get_current_weather_current_weather_get", + "parameters": [ + { + "description": "the name of the place", + "required": true, + "schema": { + "type": "string", + "title": "Place", + "description": "the name of the place" + }, + "name": "place", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Weather" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/absolute_period_dates": { + "get": { + "summary": "GET /absolute_period_dates", + "description": "get the absolute start and end date for a period in YYYY-MM-DD format given the number of day difference from the today", + "operationId": "get_absolute_period_dates_absolute_period_dates_get", + "parameters": [ + { + "description": "the difference in days from the today to the start date of the period", + "required": true, + "schema": { + "type": "integer", + "title": "Startperioddeltadays", + "description": "the difference in days from the today to the start date of the period" + }, + "name": "startPeriodDeltaDays", + "in": "query" + }, + { + "description": "the difference in days from the today to the end date of the period", + "required": true, + "schema": { + "type": "integer", + "title": "Endperioddeltadays", + "description": "the difference in days from the today to the end date of the period" + }, + "name": "endPeriodDeltaDays", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Period" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/historical_weather": { + "get": { + "summary": "GET /historical_weather", + "description": "get the historical daily mean temperature and precipitation for a given place for a range of dates", + "operationId": "get_historical_weather_historical_weather_get", + "parameters": [ + { + "description": "the name of the place", + "required": true, + "schema": { + "type": "string", + "title": "Place", + "description": "the name of the place" + }, + "name": "place", + "in": "query" + }, + { + "description": "starting date in YYYY-MM-DD format", + "required": true, + "schema": { + "type": "string", + "title": "Fromdate", + "description": "starting date in YYYY-MM-DD format" + }, + "name": "fromDate", + "in": "query" + }, + { + "description": "ending date in YYYY-MM-DD format", + "required": true, + "schema": { + "type": "string", + "title": "Todate", + "description": "ending date in YYYY-MM-DD format" + }, + "name": "toDate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Weather" + }, + "type": "array", + "title": "Return" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + "type": "array", + "title": "Detail" + } + }, + "type": "object", + "title": "HTTPValidationError" + }, + "Period": { + "properties": { + "start_date": { + "type": "string", + "title": "Start Date" + }, + "end_date": { + "type": "string", + "title": "End Date" + } + }, + "type": "object", + "required": ["start_date", "end_date"], + "title": "Period" + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + }, + "type": "array", + "title": "Location" + }, + "msg": { + "type": "string", + "title": "Message" + }, + "type": { + "type": "string", + "title": "Error Type" + } + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError" + }, + "Weather": { + "properties": { + "time": { + "type": "string", + "title": "Time" + }, + "temperature": { + "type": "string", + "title": "Temperature" + }, + "precipitation": { + "type": "string", + "title": "Precipitation" + } + }, + "type": "object", + "required": ["time", "temperature", "precipitation"], + "title": "Weather" + } + } + } +} diff --git a/lib/agents/weather/test.yaml b/lib/agents/weather/test.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/lib/aws-genai-llm-chatbot-stack.ts b/lib/aws-genai-llm-chatbot-stack.ts index bcadb8c70..7e59c3cb7 100644 --- a/lib/aws-genai-llm-chatbot-stack.ts +++ b/lib/aws-genai-llm-chatbot-stack.ts @@ -1,6 +1,6 @@ import * as cdk from "aws-cdk-lib"; import { Construct } from "constructs"; -import { SystemConfig, ModelInterface, Direction } from "./shared/types"; +import { SystemConfig, ModelInterface } from "./shared/types"; import { Authentication } from "./authentication"; import { Monitoring } from "./monitoring"; import { UserInterface } from "./user-interface"; @@ -10,8 +10,8 @@ import { RagEngines } from "./rag-engines"; import { Models } from "./models"; import { LangChainInterface } from "./model-interfaces/langchain"; import { IdeficsInterface } from "./model-interfaces/idefics"; -import * as subscriptions from "aws-cdk-lib/aws-sns-subscriptions"; -import * as sns from "aws-cdk-lib/aws-sns"; +import { BedrockAgentInterface } from "./model-interfaces/bedrock-agents"; +import { BedrockWeatherAgent } from "./agents"; import * as iam from "aws-cdk-lib/aws-iam"; import * as cr from "aws-cdk-lib/custom-resources"; import { NagSuppressions } from "cdk-nag"; @@ -51,6 +51,10 @@ export class AwsGenAILLMChatbotStack extends cdk.Stack { }); } + if (props.config.bedrock?.agents) { + new BedrockWeatherAgent(this, "weather-agent"); + } + const chatBotApi = new ChatBotApi(this, "ChatBotApi", { shared, config: props.config, @@ -67,6 +71,21 @@ export class AwsGenAILLMChatbotStack extends cdk.Stack { (model) => model.interface === ModelInterface.LangChain ); + let bedrockAgentsInterface: BedrockAgentInterface | undefined; + if (props.config.bedrock?.enabled) { + bedrockAgentsInterface = new BedrockAgentInterface( + this, + "IBedrockAgent", + { + shared, + config: props.config, + messagesTopic: chatBotApi.messagesTopic, + sessionsTable: chatBotApi.sessionsTable, + byUserIdIndex: chatBotApi.byUserIdIndex, + } + ); + } + // check if any deployed model requires langchain interface or if bedrock is enabled from config let langchainInterface: LangChainInterface | undefined; if (langchainModels.length > 0 || props.config.bedrock?.enabled) { @@ -79,24 +98,6 @@ export class AwsGenAILLMChatbotStack extends cdk.Stack { byUserIdIndex: chatBotApi.byUserIdIndex, }); - // Route all incoming messages targeted to langchain to the langchain model interface queue - chatBotApi.messagesTopic.addSubscription( - new subscriptions.SqsSubscription(langchainInterface.ingestionQueue, { - filterPolicyWithMessageBody: { - direction: sns.FilterOrPolicy.filter( - sns.SubscriptionFilter.stringFilter({ - allowlist: [Direction.In], - }) - ), - modelInterface: sns.FilterOrPolicy.filter( - sns.SubscriptionFilter.stringFilter({ - allowlist: [ModelInterface.LangChain], - }) - ), - }, - }) - ); - for (const model of models.models) { if (model.interface === ModelInterface.LangChain) { langchainInterface.addSageMakerEndpoint(model); @@ -122,24 +123,6 @@ export class AwsGenAILLMChatbotStack extends cdk.Stack { chatbotFilesBucket: chatBotApi.filesBucket, }); - // Route all incoming messages targeted to idefics to the idefics model interface queue - chatBotApi.messagesTopic.addSubscription( - new subscriptions.SqsSubscription(ideficsInterface.ingestionQueue, { - filterPolicyWithMessageBody: { - direction: sns.FilterOrPolicy.filter( - sns.SubscriptionFilter.stringFilter({ - allowlist: [Direction.In], - }) - ), - modelInterface: sns.FilterOrPolicy.filter( - sns.SubscriptionFilter.stringFilter({ - allowlist: [ModelInterface.MultiModal], - }) - ), - }, - }) - ); - for (const model of models.models) { // if model name contains idefics then add to idefics interface if (model.interface === ModelInterface.MultiModal) { @@ -242,6 +225,9 @@ export class AwsGenAILLMChatbotStack extends cdk.Stack { chatBotApi.outBoundQueue, ideficsInterface.ingestionQueue, ...(langchainInterface ? [langchainInterface.ingestionQueue] : []), + ...(bedrockAgentsInterface + ? [bedrockAgentsInterface.ingestionQueue] + : []), ], aurora: ragEngines?.auroraPgVector?.database, opensearch: ragEngines?.openSearchVector?.openSearchCollection, @@ -338,6 +324,24 @@ export class AwsGenAILLMChatbotStack extends cdk.Stack { ] ); + NagSuppressions.addResourceSuppressionsByPath( + this, + [ + `/${this.stackName}/IBedrockAgent/RequestHandler/ServiceRole/DefaultPolicy/Resource`, + `/${this.stackName}/IBedrockAgent/RequestHandler/ServiceRole/Resource`, + ], + [ + { + id: "AwsSolutions-IAM4", + reason: "IAM role implicitly created by CDK.", + }, + { + id: "AwsSolutions-IAM5", + reason: "IAM role implicitly created by CDK.", + }, + ] + ); + // RAG configuration if (props.config.rag.enabled) { NagSuppressions.addResourceSuppressionsByPath( @@ -505,6 +509,7 @@ export class AwsGenAILLMChatbotStack extends cdk.Stack { } } } + // Implicitly created resources with changing paths NagSuppressions.addStackSuppressions(this, [ { diff --git a/lib/chatbot-api/rest-api.ts b/lib/chatbot-api/rest-api.ts index 39607a75b..2dbe3dea4 100644 --- a/lib/chatbot-api/rest-api.ts +++ b/lib/chatbot-api/rest-api.ts @@ -307,6 +307,9 @@ export class ApiResolvers extends Construct { "bedrock:ListCustomModels", "bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream", + "bedrock:ListAgents", + "bedrock:GetAgent", + "bedrock:InvokeAgent", ], resources: ["*"], }) diff --git a/lib/chatbot-api/schema/schema.graphql b/lib/chatbot-api/schema/schema.graphql index 4601bfdb3..7f457086e 100644 --- a/lib/chatbot-api/schema/schema.graphql +++ b/lib/chatbot-api/schema/schema.graphql @@ -177,6 +177,10 @@ type Model @aws_cognito_user_pools { inputModalities: [String!]! outputModalities: [String!]! streaming: Boolean! + isAgent: Boolean + agentId: String + agentVersion: String + agentIsUpdated: Boolean } type PassageRank @aws_cognito_user_pools { diff --git a/lib/model-interfaces/bedrock-agents/README.md b/lib/model-interfaces/bedrock-agents/README.md new file mode 100644 index 000000000..8afa75a4f --- /dev/null +++ b/lib/model-interfaces/bedrock-agents/README.md @@ -0,0 +1,67 @@ +# Support additional models + +You can find examples of model adapters in [functions/request-handler/adapters/](./functions/request-handler/adapters/) + + +1. Create your own adapter under [functions/request-handler/adapters/](./functions/request-handler/adapters/). + +```python +import os + +from langchain.chat_models import ChatOpenAI + +from ..base import ModelAdapter +from ..registry import registry + +# 1. Write your own adapter for your model +class GPTAdapter(ModelAdapter): + def __init__(self, model_id, *args, **kwargs): + self.model_id = model_id + + super().__init__(*args, **kwargs) + + # 2. Define your langchain LLM based on the target model. + def get_llm(self, model_kwargs={}): + if not os.environ.get("OPENAI_API_KEY"): + raise Exception("OPENAI_API_KEY must be set in the environment") + + return ChatOpenAI(model_name=self.model_id, temperature=0, **model_kwargs) + + # (OPTIONAL) 3.If you need to override the default prompt, override the get_prompt method. + # If not you can remove this and leverage the get_prompt from the base adapater. + # must return a PromptTemplate + def get_prompt(self): + template = """The following is a friendly conversation between a human and an AI. If the AI does not know the answer to a question, it truthfully says it does not know. + + Current conversation: + {chat_history} + + Question: {input}""" + input_variables = ["input", "chat_history"] + prompt_template_args = { + "chat_history": "{chat_history}", + "input_variables": input_variables, + "template": template, + } + prompt_template = PromptTemplate(**prompt_template_args) + + return prompt_template + ... + +# 4. Finally, Register the adapter to match the model id coming from the select UI +# RegEx expression will allow you to use the same adapter for a different models matching your regex. +# For example `^openai*` will match all model IDs starting with `openai` such `openai.gpt-4` +registry.register(r"^openai*", GPTAdapter) +``` + +2. Make sure the `__init__.py` files are updated so that your adapter is correctly imported. + - Example model adapter [__init__.py](./functions/request-handler/adapters/openai/gpt.py) + - Adapters [__init__.py](./functions/request-handler/adapters/__init__.py) + +Ensure the registry regex + +``` +registry.register(r"^openai*", GPTAdapter) +``` + +is correct so that [your adapter is picked up](./functions/request-handler/index.py#L74) correctly from the model ID sent from the UI diff --git a/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/__init__.py b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/__init__.py new file mode 100644 index 000000000..c48fe6adb --- /dev/null +++ b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/__init__.py @@ -0,0 +1,3 @@ +# flake8: noqa +from .bedrock import * +from .base import Mode diff --git a/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/base/__init__.py b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/base/__init__.py new file mode 100644 index 000000000..efcc5606c --- /dev/null +++ b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/base/__init__.py @@ -0,0 +1,2 @@ +# flake8: noqa +from .base import AgentAdapter, Mode diff --git a/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/base/base.py b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/base/base.py new file mode 100644 index 000000000..a8330faad --- /dev/null +++ b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/base/base.py @@ -0,0 +1,36 @@ +import os +from enum import Enum +from aws_lambda_powertools import Logger +from typing import Optional, Iterator +from genai_core.langchain import DynamoDBChatMessageHistory +from pydantic import BaseModel +from abc import abstractmethod + +logger = Logger() + + +class Mode(Enum): + AGENT = "agent" + + +class AgentAdapter(BaseModel): + agent_id: str + session_id: str + user_id: str + region: Optional[str] = None + mode: Mode = Mode.AGENT + + def get_chat_history(self): + return DynamoDBChatMessageHistory( + table_name=os.environ["SESSIONS_TABLE_NAME"], + session_id=self.session_id, + user_id=self.user_id, + ) + + def run(self, prompt: str) -> Iterator[str]: + return self._invoke_agent( + prompt=prompt, + ) + + @abstractmethod + def _invoke_agent(self, prompt: str, session_id: str) -> Iterator[str]: ... diff --git a/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/bedrock/__init__.py b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/bedrock/__init__.py new file mode 100644 index 000000000..f208a36cb --- /dev/null +++ b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/bedrock/__init__.py @@ -0,0 +1,2 @@ +# flake8: noqa +from .base import BedrockAgent, AgentInputOutputAdapter diff --git a/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/bedrock/base.py b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/bedrock/base.py new file mode 100644 index 000000000..b07b10806 --- /dev/null +++ b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/bedrock/base.py @@ -0,0 +1,122 @@ +from abc import ABC +from typing import Any, Dict, Iterator, Optional +from pydantic import root_validator, Extra +from ..base import AgentAdapter +from aws_lambda_powertools import Logger + +logger = Logger() + + +class AgentInputOutputAdapter: + """Adapter class to prepare the inputs to a format + that LLM model expects. + + It also provides helper function to extract + the generated text from the model response.""" + + @classmethod + def prepare_output_stream(cls, response: Any) -> Iterator[str]: + stream = response.get("completion") + + if stream is None: + yield "" + + for event in stream: + logger.info("Stream event", event=event) + chunk = event.get("chunk") + # chunk obj format varies with provider + yield chunk["bytes"].decode("utf8") + + @classmethod + def prepare_agent_answer(cls, chunk: Any) -> str: + return chunk["bytes"].decode("utf8") + + +class BedrockAgent(AgentAdapter, ABC): + """Base class for Bedrock models.""" + + client: Any #: :meta private: + + region_name: Optional[str] = None + """The aws region e.g., `us-west-2`. Fallsback to AWS_DEFAULT_REGION env variable + or region specified in ~/.aws/config in case it is not provided here. + """ + + credentials_profile_name: Optional[str] = None + """The name of the profile in the ~/.aws/credentials or ~/.aws/config files, which + has either access keys or role information specified. + If not specified, the default credential profile or, if on an EC2 instance, + credentials from IMDS will be used. + See: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html + """ + + agent_id: str + """Id of the agent to call""" + + agent_alias_id: str = "TSTALIASID" + """The alias id for the agent. Defaults to the draft version.""" + + @property + def _llm_type(self) -> str: + """Return type of llm.""" + return "amazon_bedrock" + + class Config: + """Configuration for this pydantic object.""" + + extra = Extra.forbid + + @root_validator() + def validate_environment(cls, values: Dict) -> Dict: + """Validate that AWS credentials to and python package exists in environment.""" + + # Skip creating new client if passed in constructor + if values["client"] is not None: + return values + + try: + import boto3 + + if values["credentials_profile_name"] is not None: + session = boto3.Session(profile_name=values["credentials_profile_name"]) + else: + # use default credentials + session = boto3.Session() + + client_params = {} + if values["region_name"]: + client_params["region_name"] = values["region_name"] + + values["client"] = session.client("bedrock-agent-runtime", **client_params) + + except ImportError: + raise ModuleNotFoundError( + "Could not import boto3 python package. " + "Please install it with `pip install boto3`." + ) + except Exception as e: + raise ValueError( + "Could not load credentials to authenticate with AWS client. " + "Please check that credentials in the specified " + "profile name are valid." + ) from e + + return values + + def _invoke_agent( + self, + prompt: str, + ) -> Iterator[str]: + try: + response = self.client.invoke_agent( + enableTrace=True, + inputText=prompt, + agentId=self.agent_id, + agentAliasId=self.agent_alias_id, + sessionId=self.session_id, + ) + except Exception as e: + raise ValueError(f"Error raised by bedrock service: {e}") + + for event in response["completion"]: + yield event diff --git a/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/openai/__init__.py b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/openai/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/openai/gpt.py b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/openai/gpt.py new file mode 100644 index 000000000..f3ecbd190 --- /dev/null +++ b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/openai/gpt.py @@ -0,0 +1,31 @@ +import os +from langchain.chat_models import ChatOpenAI +from ..base import ModelAdapter +from ..registry import registry + + +class GPTAdapter(ModelAdapter): + def __init__(self, model_id, *args, **kwargs): + self.model_id = model_id + + super().__init__(*args, **kwargs) + + def get_llm(self, model_kwargs={}): + if not os.environ.get("OPENAI_API_KEY"): + raise Exception("OPENAI_API_KEY must be set in the environment") + + params = {} + if "streaming" in model_kwargs: + params["streaming"] = model_kwargs["streaming"] + if "temperature" in model_kwargs: + params["temperature"] = model_kwargs["temperature"] + if "maxTokens" in model_kwargs: + params["max_tokens"] = model_kwargs["maxTokens"] + + return ChatOpenAI( + model_name=self.model_id, callbacks=[self.callback_handler], **params + ) + + +# Register the adapter +registry.register(r"^openai*", GPTAdapter) diff --git a/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/registry/__init__.py b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/registry/__init__.py new file mode 100644 index 000000000..8626c6013 --- /dev/null +++ b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/registry/__init__.py @@ -0,0 +1,3 @@ +from .index import AdapterRegistry + +registry = AdapterRegistry() diff --git a/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/registry/index.py b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/registry/index.py new file mode 100644 index 000000000..fe00e0cf0 --- /dev/null +++ b/lib/model-interfaces/bedrock-agents/functions/request-handler/adapters/registry/index.py @@ -0,0 +1,26 @@ +import re +from ..base import AgentAdapter + + +class AdapterRegistry: + def __init__(self): + # The registry is a dictionary where: + # Keys are compiled regular expressions + # Values are model IDs + self.registry = {} + + def register(self, regex: str, agent: AgentAdapter): + # Compiles the regex and stores it in the registry + self.registry[re.compile(regex)] = agent + + def get_adapter(self, agent_id: str): + # Iterates over the registered regexs + for regex, adapter in self.registry.items(): + # If a match is found, returns the associated model ID + if regex.match(agent_id): + return adapter + # If no match is found, returns None + raise ValueError( + f"Adapter for model {agent_id} not found in registry." + + " Available adapters: {self.registry}" + ) diff --git a/lib/model-interfaces/bedrock-agents/functions/request-handler/index.py b/lib/model-interfaces/bedrock-agents/functions/request-handler/index.py new file mode 100644 index 000000000..6d72686da --- /dev/null +++ b/lib/model-interfaces/bedrock-agents/functions/request-handler/index.py @@ -0,0 +1,167 @@ +import os +import json +import uuid +from datetime import datetime +from aws_lambda_powertools import Logger, Tracer +from aws_lambda_powertools.utilities import parameters +from aws_lambda_powertools.utilities.batch import BatchProcessor, EventType +from aws_lambda_powertools.utilities.batch.exceptions import BatchProcessingError +from aws_lambda_powertools.utilities.data_classes.sqs_event import SQSRecord +from aws_lambda_powertools.utilities.typing import LambdaContext +from adapters.bedrock import BedrockAgent, AgentInputOutputAdapter + +from genai_core.utils.websocket import send_to_client +from genai_core.types import ChatbotAction + +processor = BatchProcessor(event_type=EventType.SQS) +tracer = Tracer() +logger = Logger() + +AWS_REGION = os.environ["AWS_REGION"] +CONFIG_PARAMETER_NAME = os.environ["CONFIG_PARAMETER_NAME"] + +sequence_number = 0 +config = json.loads(parameters.get_parameter(CONFIG_PARAMETER_NAME)) + + +def handle_run(record): + user_id = record["userId"] + data = record["data"] + agent_id = data["agentId"] + prompt = data["text"] + session_id = data.get("sessionId") + + if not session_id: + session_id = str(uuid.uuid4()) + + # get the adapter from the registry + + # create an agent adapter to invoke a Bedrock Agent using agentId and agentAliasId + agent = BedrockAgent( + agent_id=agent_id, + user_id=user_id, + session_id=session_id, + region_name=config.get("bedrock", {}).get("region", AWS_REGION), + ) + # call the agent + response = agent.run( + prompt, + ) + + logger.info("Bedrock Agent response", response=response) + sequence_number = 0 + run_id = str(uuid.uuid4()) + for r in response: + # this is specific to Bedrock agents, would need a way to generalize + # it if we are to introduce other agents + if "chunk" in list(r.keys()): + send_to_client( + { + "type": "text", + "action": ChatbotAction.FINAL_RESPONSE.value, + "timestamp": str(int(round(datetime.now().timestamp()))), + "userId": user_id, + "data": { + "sessionId": session_id, + "type": "text", + "content": AgentInputOutputAdapter.prepare_agent_answer( + r["chunk"] + ), + "metadata": { + "modelId": agent_id, + "modelKwargs": None, + "mode": "agent", + "sessionId": session_id, + "userId": user_id, + "documents": [], + "prompts": [prompt], + }, + }, + } + ) + if "trace" in list(r.keys()): + send_to_client( + { + "type": "text", + "action": ChatbotAction.AGENT_TRACE.value, + "timestamp": str(int(round(datetime.now().timestamp()))), + "userId": user_id, + "data": { + "sessionId": session_id, + "type": "text", + "sequence": sequence_number, + "runId": run_id, + "content": json.dumps(r["trace"]), + "metadata": { + "modelId": agent_id, + "modelKwargs": None, + "mode": "agent", + }, + }, + } + ) + sequence_number += 1 + + +@tracer.capture_method +def record_handler(record: SQSRecord): + payload: str = record.body + message: dict = json.loads(payload) + detail: dict = json.loads(message["Message"]) + logger.info("Incoming event", detail=detail) + + if detail["action"] == ChatbotAction.RUN.value: + handle_run(detail) + elif detail["action"] == ChatbotAction.HEARTBEAT.value: + pass + + +def handle_failed_records(records): + for triplet in records: + _, error, record = triplet + payload: str = record.body + message: dict = json.loads(payload) + detail: dict = json.loads(message["Message"]) + logger.info("Failed event", detail=detail) + user_id = detail["userId"] + data = detail.get("data", {}) + session_id = data.get("sessionId", "") + + send_to_client( + { + "type": "text", + "action": "error", + "direction": "OUT", + "userId": user_id, + "timestamp": str(int(round(datetime.now().timestamp()))), + "data": { + "sessionId": session_id, + "content": "Something went wrong", + "type": "text", + }, + } + ) + + +@logger.inject_lambda_context(log_event=True) +@tracer.capture_lambda_handler +def handler(event, context: LambdaContext): + batch = event["Records"] + + try: + with processor(records=batch, handler=record_handler): + processed_messages = processor.process() + except BatchProcessingError as e: + logger.error(e) + + for message in processed_messages: + logger.info( + "Request complete with status " + message[0], + status=message[0], + cause=message[1], + ) + handle_failed_records( + message for message in processed_messages if message[0] == "fail" + ) + + return processor.response() diff --git a/lib/model-interfaces/bedrock-agents/index.ts b/lib/model-interfaces/bedrock-agents/index.ts new file mode 100644 index 000000000..3e9d0f7d3 --- /dev/null +++ b/lib/model-interfaces/bedrock-agents/index.ts @@ -0,0 +1,120 @@ +import * as cdk from "aws-cdk-lib"; +import * as dynamodb from "aws-cdk-lib/aws-dynamodb"; +import * as iam from "aws-cdk-lib/aws-iam"; +import * as lambda from "aws-cdk-lib/aws-lambda"; +import * as lambdaEventSources from "aws-cdk-lib/aws-lambda-event-sources"; +import * as logs from "aws-cdk-lib/aws-logs"; + +import * as sns from "aws-cdk-lib/aws-sns"; +import * as sqs from "aws-cdk-lib/aws-sqs"; +import { Construct } from "constructs"; +import * as path from "path"; +import { Shared } from "../../shared"; +import { Direction, ModelInterface, SystemConfig } from "../../shared/types"; +import { SqsSubscription } from "aws-cdk-lib/aws-sns-subscriptions"; + +interface BedrockAgentInterfaceProps { + readonly shared: Shared; + readonly config: SystemConfig; + readonly messagesTopic: sns.Topic; + readonly sessionsTable: dynamodb.Table; + readonly byUserIdIndex: string; +} + +export class BedrockAgentInterface extends Construct { + public readonly ingestionQueue: sqs.Queue; + public readonly requestHandler: lambda.Function; + + constructor(scope: Construct, id: string, props: BedrockAgentInterfaceProps) { + super(scope, id); + + const requestHandler = new lambda.Function(this, "RequestHandler", { + vpc: props.shared.vpc, + code: props.shared.sharedCode.bundleWithLambdaAsset( + path.join(__dirname, "./functions/request-handler") + ), + handler: "index.handler", + runtime: props.shared.pythonRuntime, + architecture: props.shared.lambdaArchitecture, + tracing: lambda.Tracing.ACTIVE, + timeout: cdk.Duration.minutes(15), + memorySize: 1024, + logRetention: props.config.logRetention ?? logs.RetentionDays.ONE_WEEK, + loggingFormat: lambda.LoggingFormat.JSON, + layers: [props.shared.powerToolsLayer, props.shared.commonLayer], + environment: { + ...props.shared.defaultEnvironmentVariables, + CONFIG_PARAMETER_NAME: props.shared.configParameter.parameterName, + SESSIONS_TABLE_NAME: props.sessionsTable.tableName, + SESSIONS_BY_USER_ID_INDEX_NAME: props.byUserIdIndex, + MESSAGES_TOPIC_ARN: props.messagesTopic.topicArn, + }, + }); + + props.sessionsTable.grantReadWriteData(requestHandler); + props.messagesTopic.grantPublish(requestHandler); + props.shared.apiKeysSecret.grantRead(requestHandler); + props.shared.configParameter.grantRead(requestHandler); + + requestHandler.addToRolePolicy( + new iam.PolicyStatement({ + actions: ["bedrock:InvokeAgent", "bedrock:GetAgentAlias"], + resources: ["*"], + }) + ); + + if (props.config.bedrock?.roleArn) { + requestHandler.addToRolePolicy( + new iam.PolicyStatement({ + actions: ["sts:AssumeRole"], + resources: [props.config.bedrock.roleArn], + }) + ); + } + + const deadLetterQueue = new sqs.Queue(this, "DLQ", { enforceSSL: true }); + const queue = new sqs.Queue(this, "Queue", { + removalPolicy: cdk.RemovalPolicy.DESTROY, + // https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html#events-sqs-queueconfig + visibilityTimeout: cdk.Duration.minutes(15 * 6), + enforceSSL: true, + deadLetterQueue: { + queue: deadLetterQueue, + maxReceiveCount: 3, + }, + }); + + queue.addToResourcePolicy( + new iam.PolicyStatement({ + actions: ["sqs:SendMessage"], + resources: [queue.queueArn], + principals: [ + new iam.ServicePrincipal("events.amazonaws.com"), + new iam.ServicePrincipal("sqs.amazonaws.com"), + ], + }) + ); + + props.messagesTopic.addSubscription( + new SqsSubscription(queue, { + filterPolicyWithMessageBody: { + direction: sns.FilterOrPolicy.filter( + sns.SubscriptionFilter.stringFilter({ + allowlist: [Direction.In], + }) + ), + modelInterface: sns.FilterOrPolicy.filter( + sns.SubscriptionFilter.stringFilter({ + allowlist: [ModelInterface.BedrockAgent], + }) + ), + }, + }) + ); + + requestHandler.addEventSource(new lambdaEventSources.SqsEventSource(queue)); + + this.ingestionQueue = queue; + this.requestHandler = requestHandler; + } +} diff --git a/lib/model-interfaces/idefics/functions/request-handler/adapters/base.py b/lib/model-interfaces/idefics/functions/request-handler/adapters/base.py index 0bb5d1709..f359cf1ab 100644 --- a/lib/model-interfaces/idefics/functions/request-handler/adapters/base.py +++ b/lib/model-interfaces/idefics/functions/request-handler/adapters/base.py @@ -3,10 +3,12 @@ class MultiModalModelBase: @abstractmethod - def handle_run(self, prompt: str, model_kwargs: dict) -> str: ... + def handle_run(self, prompt: str, model_kwargs: dict) -> str: + ... @abstractmethod - def format_prompt(self, prompt: str, messages: list, files: list) -> str: ... + def format_prompt(self, prompt: str, messages: list, files: list) -> str: + ... def clean_prompt(self, prompt: str) -> str: return prompt diff --git a/lib/model-interfaces/idefics/functions/request-handler/adapters/idefics.py b/lib/model-interfaces/idefics/functions/request-handler/adapters/idefics.py index ce6331e59..b6eb94af7 100644 --- a/lib/model-interfaces/idefics/functions/request-handler/adapters/idefics.py +++ b/lib/model-interfaces/idefics/functions/request-handler/adapters/idefics.py @@ -17,7 +17,6 @@ def __init__(self, model_id: str): self.model_id = model_id def format_prompt(self, prompt: str, messages: list, files: list) -> str: - human_prompt_template = "User:{prompt}" human_prompt_with_image = "User:{prompt}![]({image})" ai_prompt_template = "Assistant:{prompt}" diff --git a/lib/model-interfaces/idefics/index.ts b/lib/model-interfaces/idefics/index.ts index bdb8567c0..4df7a79f1 100644 --- a/lib/model-interfaces/idefics/index.ts +++ b/lib/model-interfaces/idefics/index.ts @@ -13,9 +13,10 @@ import * as sqs from "aws-cdk-lib/aws-sqs"; import { Construct } from "constructs"; import * as path from "path"; import { Shared } from "../../shared"; -import { SystemConfig } from "../../shared/types"; +import { Direction, ModelInterface, SystemConfig } from "../../shared/types"; import { RemovalPolicy } from "aws-cdk-lib"; import { NagSuppressions } from "cdk-nag"; +import { SqsSubscription } from "aws-cdk-lib/aws-sns-subscriptions"; interface IdeficsInterfaceProps { readonly shared: Shared; @@ -250,6 +251,23 @@ export class IdeficsInterface extends Construct { }) ); + props.messagesTopic.addSubscription( + new SqsSubscription(queue, { + filterPolicyWithMessageBody: { + direction: sns.FilterOrPolicy.filter( + sns.SubscriptionFilter.stringFilter({ + allowlist: [Direction.In], + }) + ), + modelInterface: sns.FilterOrPolicy.filter( + sns.SubscriptionFilter.stringFilter({ + allowlist: [ModelInterface.MultiModal], + }) + ), + }, + }) + ); + requestHandler.addEventSource(new lambdaEventSources.SqsEventSource(queue)); this.ingestionQueue = queue; diff --git a/lib/model-interfaces/langchain/index.ts b/lib/model-interfaces/langchain/index.ts index 01153b0a3..0533732f5 100644 --- a/lib/model-interfaces/langchain/index.ts +++ b/lib/model-interfaces/langchain/index.ts @@ -11,7 +11,8 @@ import { Construct } from "constructs"; import * as path from "path"; import { RagEngines } from "../../rag-engines"; import { Shared } from "../../shared"; -import { SystemConfig } from "../../shared/types"; +import { Direction, ModelInterface, SystemConfig } from "../../shared/types"; +import { SqsSubscription } from "aws-cdk-lib/aws-sns-subscriptions"; interface LangChainInterfaceProps { readonly shared: Shared; @@ -258,6 +259,23 @@ export class LangChainInterface extends Construct { }) ); + props.messagesTopic.addSubscription( + new SqsSubscription(queue, { + filterPolicyWithMessageBody: { + direction: sns.FilterOrPolicy.filter( + sns.SubscriptionFilter.stringFilter({ + allowlist: [Direction.In], + }) + ), + modelInterface: sns.FilterOrPolicy.filter( + sns.SubscriptionFilter.stringFilter({ + allowlist: [ModelInterface.LangChain], + }) + ), + }, + }) + ); + requestHandler.addEventSource(new lambdaEventSources.SqsEventSource(queue)); this.ingestionQueue = queue; diff --git a/lib/shared/layers/python-sdk/python/genai_core/bedrock_kb/client.py b/lib/shared/layers/python-sdk/python/genai_core/bedrock_kb/client.py index d968d3351..31a81bf55 100644 --- a/lib/shared/layers/python-sdk/python/genai_core/bedrock_kb/client.py +++ b/lib/shared/layers/python-sdk/python/genai_core/bedrock_kb/client.py @@ -6,7 +6,6 @@ def get_kb_runtime_client_for_id(knowledge_base_id: str): - config = genai_core.parameters.get_config() kb_config = config.get("rag", {}).get("engines", {}).get("knowledgeBase", {}) external = kb_config.get("external", []) diff --git a/lib/shared/layers/python-sdk/python/genai_core/bedrock_kb/query.py b/lib/shared/layers/python-sdk/python/genai_core/bedrock_kb/query.py index 9a9b5345d..bae74360e 100644 --- a/lib/shared/layers/python-sdk/python/genai_core/bedrock_kb/query.py +++ b/lib/shared/layers/python-sdk/python/genai_core/bedrock_kb/query.py @@ -47,7 +47,6 @@ def _convert_records(source: str, workspace_id: str, records: List[dict]): converted_records = [] _id = 0 for record in records: - path = record.get("location", {}).get("s3Location", {}).get("uri", "") content = record.get("content", {}).get("text", "") score = record.get("score", 0) diff --git a/lib/shared/layers/python-sdk/python/genai_core/models.py b/lib/shared/layers/python-sdk/python/genai_core/models.py index a72580266..619b5e74e 100644 --- a/lib/shared/layers/python-sdk/python/genai_core/models.py +++ b/lib/shared/layers/python-sdk/python/genai_core/models.py @@ -27,6 +27,10 @@ def list_models(): if openai_models: models.extend(openai_models) + bedrock_agents = list_bedrock_agents() + if bedrock_agents: + models.extend(bedrock_agents) + azure_openai_models = list_azure_openai_models() if azure_openai_models: models.extend(azure_openai_models) @@ -34,6 +38,42 @@ def list_models(): return models +def list_bedrock_agents(): + try: + bedrock = genai_core.clients.get_bedrock_client(service_name="bedrock-agent") + if not bedrock: + return None + + response = bedrock.list_agents() + agents = [ + bedrock.get_agent(agentId=a["agentId"])["agent"] + for a in response.get("agentSummaries", []) + if a.get("agentStatus", "") == genai_core.types.AgentStatus.PREPARED.value + ] + + bedrock_agents = [ + { + "provider": Provider.BEDROCK.value, + "name": a["agentName"], + "streaming": True, + "inputModalities": [Modality.TEXT.value], + "outputModalities": [Modality.TEXT.value], + "interface": ModelInterface.AGENT.value, + "ragSupported": False, + "agentId": a["agentId"], + "agentVersion": "TSTALIASID", + "agentIsUpdated": a["preparedAt"] < a["updatedAt"], + "isAgent": True, + } + for a in agents + ] + + return bedrock_agents + except Exception as e: + logger.error("Error listing Bedrock agents:", e) + return None + + def list_openai_models(): openai = genai_core.clients.get_openai_client() if not openai: @@ -50,6 +90,7 @@ def list_openai_models(): "outputModalities": [Modality.TEXT.value], "interface": ModelInterface.LANGCHAIN.value, "ragSupported": True, + "isAgent": False, } for model in models.data if model["id"].startswith("gpt") @@ -102,6 +143,7 @@ def list_bedrock_models(): "outputModalities": model["outputModalities"], "interface": ModelInterface.LANGCHAIN.value, "ragSupported": True, + "isAgent": False, } for model in bedrock_models # Exclude embeddings and stable diffusion models @@ -135,6 +177,7 @@ def list_bedrock_finetuned_models(): "outputModalities": model["outputModalities"], "interface": ModelInterface.LANGCHAIN.value, "ragSupported": True, + "isAgent": False, } for model in bedrock_custom_models # Exclude embeddings and stable diffusion models @@ -162,6 +205,7 @@ def list_sagemaker_models(): "outputModalities": model["outputModalities"], "interface": model["interface"], "ragSupported": model["ragSupported"], + "isAgent": False, } for model in models ] diff --git a/lib/shared/layers/python-sdk/python/genai_core/types.py b/lib/shared/layers/python-sdk/python/genai_core/types.py index aa0f0b7b9..e3d014a11 100644 --- a/lib/shared/layers/python-sdk/python/genai_core/types.py +++ b/lib/shared/layers/python-sdk/python/genai_core/types.py @@ -58,9 +58,14 @@ class ModelStatus(Enum): LEGACY = "LEGACY" +class AgentStatus(Enum): + PREPARED = "PREPARED" + + class ModelInterface(Enum): LANGCHAIN = "langchain" IDEFICS = "idefics" + AGENT = "agent" class Direction(Enum): @@ -77,6 +82,7 @@ class ChatbotAction(Enum): RUN = "run" LLM_NEW_TOKEN = "llm_new_token" FINAL_RESPONSE = "final_response" + AGENT_TRACE = "agent_trace" class ChatbotMessageType(Enum): diff --git a/lib/shared/shared-asset-bundler.ts b/lib/shared/shared-asset-bundler.ts index c907602c6..480cf7dd7 100644 --- a/lib/shared/shared-asset-bundler.ts +++ b/lib/shared/shared-asset-bundler.ts @@ -2,12 +2,13 @@ import { AssetHashType, BundlingOutput, DockerImage, + Stack, aws_s3_assets, } from "aws-cdk-lib"; import { Code, S3Code } from "aws-cdk-lib/aws-lambda"; import { Asset } from "aws-cdk-lib/aws-s3-assets"; import { md5hash } from "aws-cdk-lib/core/lib/helpers-internal"; -import { Construct } from "constructs"; +import { Construct, Node } from "constructs"; import * as path from "path"; import * as fs from "fs"; @@ -33,6 +34,7 @@ function calculateHash(paths: string[]): string { export class SharedAssetBundler extends Construct { private readonly sharedAssets: string[]; private readonly WORKING_PATH = "/asset-input/"; + /** * Instantiate a new SharedAssetBundler. You then invoke `bundleWithAsset(pathToAsset)` to * bundle your asset code with the common code. @@ -60,7 +62,7 @@ export class SharedAssetBundler extends Construct { image: process.env.NODE_ENV === "test" ? DockerImage.fromRegistry("dummy-skip-build-in-test") - : DockerImage.fromBuild(path.posix.join(__dirname, "alpine-zip")), + : BuildImageProvider.getOrCreate(this), command: [ "zip", "-r", @@ -86,3 +88,24 @@ export class SharedAssetBundler extends Construct { return Code.fromBucket(asset.bucket, asset.s3ObjectKey); } } + +class BuildImageProvider extends Construct { + public static getOrCreate(scope: Construct): DockerImage { + const stack = Stack.of(scope); + const id = "build-image-provider"; + const x = + (Node.of(stack).tryFindChild(id) as BuildImageProvider) || + new BuildImageProvider(stack, id); + return x.buildImage; + } + + private readonly buildImage: DockerImage; + + constructor(scope: Construct, id: string) { + super(scope, id); + + this.buildImage = DockerImage.fromBuild( + path.posix.join(__dirname, "alpine-zip") + ); + } +} diff --git a/lib/shared/types.ts b/lib/shared/types.ts index 9011489c9..782b13a63 100644 --- a/lib/shared/types.ts +++ b/lib/shared/types.ts @@ -55,6 +55,7 @@ export enum SupportedBedrockRegion { export enum ModelInterface { LangChain = "langchain", + BedrockAgent = "agent", MultiModal = "multimodal", } @@ -107,7 +108,11 @@ export interface SystemConfig { identifier: string; version: string; }; + bedrockAgentAliasId?: string; + bedrockAgentId?: string; + agents?: boolean; }; + llms: { sagemaker: SupportedSageMakerModels[]; huggingfaceApiSecretArn?: string; diff --git a/lib/shared/web-crawler-batch-job/index.py b/lib/shared/web-crawler-batch-job/index.py index 3c6e973a6..a7a6d91dd 100644 --- a/lib/shared/web-crawler-batch-job/index.py +++ b/lib/shared/web-crawler-batch-job/index.py @@ -12,7 +12,6 @@ def main(): - response = s3_client.get_object(Bucket=PROCESSING_BUCKET_NAME, Key=OBJECT_KEY) file_content = response["Body"].read().decode("utf-8") data = json.loads(file_content) diff --git a/lib/user-interface/react-app/package-lock.json b/lib/user-interface/react-app/package-lock.json index 45edde69e..dc8ec398b 100644 --- a/lib/user-interface/react-app/package-lock.json +++ b/lib/user-interface/react-app/package-lock.json @@ -9,12 +9,11 @@ "version": "3.0.0", "dependencies": { "@aws-amplify/ui-react": "^5.3.3", + "@cloudscape-design/chat-components": "^1.0.9", + "@cloudscape-design/component-toolkit": "^1.0.0-beta.64", "@cloudscape-design/components": "^3.0.651", "@cloudscape-design/design-tokens": "^3.0.36", "@cloudscape-design/global-styles": "^1.0.27", - "@fortawesome/fontawesome-svg-core": "^6.4.2", - "@fortawesome/free-solid-svg-icons": "^6.4.2", - "@fortawesome/react-fontawesome": "^0.2.0", "aws-amplify": "^5.3.20", "luxon": "^3.4.3", "react": "^18.2.0", @@ -74,12 +73,12 @@ } }, "node_modules/@aws-amplify/analytics": { - "version": "6.5.12", - "resolved": "https://registry.npmjs.org/@aws-amplify/analytics/-/analytics-6.5.12.tgz", - "integrity": "sha512-8z3mXLzUoMkR47W9UrK/yNw7Qo98HuhYaPW9gQa0/H5mC4IIiN/ka0RurefKTx89xkPUxIuv7pAIWqMcg8NMCA==", + "version": "6.5.13", + "resolved": "https://registry.npmjs.org/@aws-amplify/analytics/-/analytics-6.5.13.tgz", + "integrity": "sha512-tqWbVFIo7KASweFVeJzWkmtzfpblyh+XQzJWO1ZAkrNjs+KxCEKvFuK3wteUcbAwRsFQEfkF3Kgx90eq4XKrfA==", "dependencies": { - "@aws-amplify/cache": "5.1.18", - "@aws-amplify/core": "5.8.12", + "@aws-amplify/cache": "5.1.19", + "@aws-amplify/core": "5.8.13", "@aws-sdk/client-firehose": "3.6.1", "@aws-sdk/client-kinesis": "3.6.1", "@aws-sdk/client-personalize-events": "3.6.1", @@ -104,25 +103,25 @@ } }, "node_modules/@aws-amplify/api": { - "version": "5.4.12", - "resolved": "https://registry.npmjs.org/@aws-amplify/api/-/api-5.4.12.tgz", - "integrity": "sha512-LHxfHpwu6hFm6sMiPB6UAKzj5Aoccp/r4527dTg6N/aQwQXyWEGkGSK4dBSSM/Sf0vPADo9jn6WGNttCXulDyw==", + "version": "5.4.13", + "resolved": "https://registry.npmjs.org/@aws-amplify/api/-/api-5.4.13.tgz", + "integrity": "sha512-3G2gLAoxG8bb+DRxVreUKHbxi6Y3MlKDXLFvHPMsxY28qUVi+ee1MBZqf6WqYBTe6H9KFIPORCMIDqFNeO2kgg==", "dependencies": { - "@aws-amplify/api-graphql": "3.4.18", - "@aws-amplify/api-rest": "3.5.12", + "@aws-amplify/api-graphql": "3.4.19", + "@aws-amplify/api-rest": "3.5.13", "tslib": "^1.8.0" } }, "node_modules/@aws-amplify/api-graphql": { - "version": "3.4.18", - "resolved": "https://registry.npmjs.org/@aws-amplify/api-graphql/-/api-graphql-3.4.18.tgz", - "integrity": "sha512-4rZ0vhfTQnP+kCL+uc0BZdHsjNU1vLj5+xOPIkNrI0Y0VdN9I2aKfWjBQx8i2BIPeF3B+xSKKuGhIJD6WCxcpg==", - "dependencies": { - "@aws-amplify/api-rest": "3.5.12", - "@aws-amplify/auth": "5.6.12", - "@aws-amplify/cache": "5.1.18", - "@aws-amplify/core": "5.8.12", - "@aws-amplify/pubsub": "5.5.12", + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/@aws-amplify/api-graphql/-/api-graphql-3.4.19.tgz", + "integrity": "sha512-Pvg57LMwAqaFeYdBJCdyWNcLdyEqpgfPZPShrBJxbpNQZsuZwzRcOe8VOibCEBQS7XJi7NNBHzq19ESuLPhXtQ==", + "dependencies": { + "@aws-amplify/api-rest": "3.5.13", + "@aws-amplify/auth": "5.6.13", + "@aws-amplify/cache": "5.1.19", + "@aws-amplify/core": "5.8.13", + "@aws-amplify/pubsub": "5.5.13", "graphql": "15.8.0", "tslib": "^1.8.0", "uuid": "^3.2.1", @@ -144,11 +143,11 @@ } }, "node_modules/@aws-amplify/api-rest": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@aws-amplify/api-rest/-/api-rest-3.5.12.tgz", - "integrity": "sha512-WWUZU7MaKxxt9xw+FwnSWfbsXEwoDbGH6G8/S0YrcQeILbutLLcW4boW3d2vRaYjjC/1saVUHyrdO1mWZ++C5Q==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@aws-amplify/api-rest/-/api-rest-3.5.13.tgz", + "integrity": "sha512-9N+mTivn/98l7Dl3VoVzBx72xh//mJX/ew9rFgH0nR8vW9Lbsk/GwGus9m7vIR18qymdWe/dfdXAb76whGzhzA==", "dependencies": { - "@aws-amplify/core": "5.8.12", + "@aws-amplify/core": "5.8.13", "axios": "^1.6.5", "tslib": "^1.8.0", "url": "0.11.0" @@ -165,11 +164,11 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-amplify/auth": { - "version": "5.6.12", - "resolved": "https://registry.npmjs.org/@aws-amplify/auth/-/auth-5.6.12.tgz", - "integrity": "sha512-NX5E2l9Ovsbfsh2R0iNweNVVY3QtJRWpBrHPIOxzhqSxiwK0Cay/+9bQ8Uv7/O8s2NHByG1+kXM7zR+iDuYxfA==", + "version": "5.6.13", + "resolved": "https://registry.npmjs.org/@aws-amplify/auth/-/auth-5.6.13.tgz", + "integrity": "sha512-vJ5RRQ3LkRgwQXy1QxxKNobNLSvt3sGbWfwt0RuCMatIqUXCSrDll6+sTwiIJVyobLunaoLvNUPF0QNO5lr8fA==", "dependencies": { - "@aws-amplify/core": "5.8.12", + "@aws-amplify/core": "5.8.13", "amazon-cognito-identity-js": "6.3.13", "buffer": "4.9.2", "tslib": "^1.8.0", @@ -182,11 +181,11 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-amplify/cache": { - "version": "5.1.18", - "resolved": "https://registry.npmjs.org/@aws-amplify/cache/-/cache-5.1.18.tgz", - "integrity": "sha512-1aZ8MvA+8PJur5cnJAbBUnCUCw3ACfjCI/s/qY+Fx1jKahci3J9Yl2+pf4A6Nk6e0IjtN6FVCOKUKcWV/5+QYQ==", + "version": "5.1.19", + "resolved": "https://registry.npmjs.org/@aws-amplify/cache/-/cache-5.1.19.tgz", + "integrity": "sha512-XX+wiD9ft0fJ32nO/rJ2Fw4oSlP6lli47yMwXYEbNAuIkw6som+2Cij12du4epOTbSXckaRGEbYTAkn30+rSAg==", "dependencies": { - "@aws-amplify/core": "5.8.12", + "@aws-amplify/core": "5.8.13", "tslib": "^1.8.0" } }, @@ -196,9 +195,9 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-amplify/core": { - "version": "5.8.12", - "resolved": "https://registry.npmjs.org/@aws-amplify/core/-/core-5.8.12.tgz", - "integrity": "sha512-kQkIRBiowtMawBPTviAkz6q9Od6IImrYxdnjFebHNqF1fuLq016jxhBLxiq5ztZDvkZX+IpSr1gzOZtNGkikvA==", + "version": "5.8.13", + "resolved": "https://registry.npmjs.org/@aws-amplify/core/-/core-5.8.13.tgz", + "integrity": "sha512-Ok6oFHQj0Bv3C6yXiQLayBKJiXXrsoQji59WRZ7kCxvymybl8ONym7PfJLoDLK9BNMrgzD97NIEACe/Av5PJmg==", "dependencies": { "@aws-crypto/sha256-js": "1.2.2", "@aws-sdk/client-cloudwatch-logs": "3.6.1", @@ -218,14 +217,14 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-amplify/datastore": { - "version": "4.7.12", - "resolved": "https://registry.npmjs.org/@aws-amplify/datastore/-/datastore-4.7.12.tgz", - "integrity": "sha512-BnyZZPvYAka6D4OHfid7/UCBvXgpZTvXTydBW0YFZ3mIoRiTZC9+rcWm0i3EjtjUuGJuzbLhxDqklXGvUsXCkg==", - "dependencies": { - "@aws-amplify/api": "5.4.12", - "@aws-amplify/auth": "5.6.12", - "@aws-amplify/core": "5.8.12", - "@aws-amplify/pubsub": "5.5.12", + "version": "4.7.13", + "resolved": "https://registry.npmjs.org/@aws-amplify/datastore/-/datastore-4.7.13.tgz", + "integrity": "sha512-6HZR13bHGMpQfrJuD00JgMxEZU+mmp3EcOYTOVZyvYwg3OuG3iHyu66ik6cEvjf/CmrWFoil9tmoruBq5y+XRg==", + "dependencies": { + "@aws-amplify/api": "5.4.13", + "@aws-amplify/auth": "5.6.13", + "@aws-amplify/core": "5.8.13", + "@aws-amplify/pubsub": "5.5.13", "amazon-cognito-identity-js": "6.3.13", "buffer": "4.9.2", "idb": "5.0.6", @@ -246,12 +245,12 @@ } }, "node_modules/@aws-amplify/geo": { - "version": "2.3.12", - "resolved": "https://registry.npmjs.org/@aws-amplify/geo/-/geo-2.3.12.tgz", - "integrity": "sha512-H8cyusFfWhXANefNJz/rYAMAmD8cNPC36xzFfXrqHJTKplEUY+3dRMvkOx2gDZpqYF8Ij9qJ5BOoPfs7Jh6ySA==", + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@aws-amplify/geo/-/geo-2.3.13.tgz", + "integrity": "sha512-ZVbIfafw2dlsdY+4/cxuZNDuQcP2wFqZiwdg0rkohmC48GLxNTsfrlCNsFRa8XCFfwuNUlsZrSJ/ItVoFQq6iA==", "dependencies": { - "@aws-amplify/core": "5.8.12", - "@aws-sdk/client-location": "3.186.3", + "@aws-amplify/core": "5.8.13", + "@aws-sdk/client-location": "3.186.4", "@turf/boolean-clockwise": "6.5.0", "camelcase-keys": "6.2.2", "tslib": "^1.8.0" @@ -263,13 +262,13 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-amplify/interactions": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/@aws-amplify/interactions/-/interactions-5.2.18.tgz", - "integrity": "sha512-K1oo6GFS7kgq86QMjmF+dabuFEeJLAu1FK1tfTyFIhvrgZ4xfVnzdTXlJhS+ZJ5ZKc6WyzVmE8di/KllI+pTAA==", + "version": "5.2.19", + "resolved": "https://registry.npmjs.org/@aws-amplify/interactions/-/interactions-5.2.19.tgz", + "integrity": "sha512-BxJYifIlSELRcYgPRzSczobqj6xqUbahhD1KWVNzVR+zF31AwcoIpxo+pf/0z66azW8L3o50Cep9GHETvs0xaA==", "dependencies": { - "@aws-amplify/core": "5.8.12", - "@aws-sdk/client-lex-runtime-service": "3.186.3", - "@aws-sdk/client-lex-runtime-v2": "3.186.3", + "@aws-amplify/core": "5.8.13", + "@aws-sdk/client-lex-runtime-service": "3.186.4", + "@aws-sdk/client-lex-runtime-v2": "3.186.4", "base-64": "1.0.0", "fflate": "0.7.3", "pako": "2.0.4", @@ -282,12 +281,12 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-amplify/notifications": { - "version": "1.6.13", - "resolved": "https://registry.npmjs.org/@aws-amplify/notifications/-/notifications-1.6.13.tgz", - "integrity": "sha512-fH1k8P1Nts/1OIy8IKQjWpJgdsql0562CPpwGBVvPnRYqnkPxvzImjZdhwTgpu+vxjDBKEky/Buu9ws+ST7Myg==", + "version": "1.6.14", + "resolved": "https://registry.npmjs.org/@aws-amplify/notifications/-/notifications-1.6.14.tgz", + "integrity": "sha512-ftRHVlP6gxp2E4KroMJwPULxd+EyjO84zjKp2v5BZ8EDYtJGCyG/6HvC/MIR0da2IyPXzwDXMPnKnEL7fRk95A==", "dependencies": { - "@aws-amplify/cache": "5.1.18", - "@aws-amplify/core": "5.8.12", + "@aws-amplify/cache": "5.1.19", + "@aws-amplify/core": "5.8.13", "@aws-amplify/rtn-push-notification": "1.1.14", "lodash": "^4.17.21", "uuid": "^3.2.1" @@ -303,12 +302,12 @@ } }, "node_modules/@aws-amplify/predictions": { - "version": "5.5.13", - "resolved": "https://registry.npmjs.org/@aws-amplify/predictions/-/predictions-5.5.13.tgz", - "integrity": "sha512-AYQ46NzaSFSztJAGd6SFqgPqTGsJGREGutg1md+INn4Zs3YCg29rTbI/SPVPcbBnH838V3EpYI6k45U3YsAFvw==", + "version": "5.5.14", + "resolved": "https://registry.npmjs.org/@aws-amplify/predictions/-/predictions-5.5.14.tgz", + "integrity": "sha512-eJzo6pnbt2FEi70Ib3Z4L3dWN5jH3pLW1hqvpAKuJjKpJ90C3dVSSTCOftbU8iu913TbXH2GvXUZ63FK3GKwEg==", "dependencies": { - "@aws-amplify/core": "5.8.12", - "@aws-amplify/storage": "5.9.13", + "@aws-amplify/core": "5.8.13", + "@aws-amplify/storage": "5.9.14", "@aws-sdk/client-comprehend": "3.6.1", "@aws-sdk/client-polly": "3.6.1", "@aws-sdk/client-rekognition": "3.6.1", @@ -336,13 +335,13 @@ } }, "node_modules/@aws-amplify/pubsub": { - "version": "5.5.12", - "resolved": "https://registry.npmjs.org/@aws-amplify/pubsub/-/pubsub-5.5.12.tgz", - "integrity": "sha512-eD57TUee9n7ECNPWFIl1TcZmQf8+usiB2vo7t6nBgjCoudYRhYh8ZPfxg94uqfDdWBXMbRoBI0JPISyEQo2xKA==", + "version": "5.5.13", + "resolved": "https://registry.npmjs.org/@aws-amplify/pubsub/-/pubsub-5.5.13.tgz", + "integrity": "sha512-64RS6igRjSLvviUPPgGDUVkK1nxF63mXjkB34d6Ds7T4THdie02Kl5YzJVSiLog1/FjyD4zf7lNF2Cy+fTqiWA==", "dependencies": { - "@aws-amplify/auth": "5.6.12", - "@aws-amplify/cache": "5.1.18", - "@aws-amplify/core": "5.8.12", + "@aws-amplify/auth": "5.6.13", + "@aws-amplify/cache": "5.1.19", + "@aws-amplify/core": "5.8.13", "buffer": "4.9.2", "graphql": "15.8.0", "tslib": "^1.8.0", @@ -371,11 +370,11 @@ "integrity": "sha512-C3y+iL8/9800wWOyIAVYAKzrHZkFeI3y2ZoJlj0xot+dCbQZkMr/XjO2ZwfC58XRKUiDKFfzCJW/XoyZlvthfw==" }, "node_modules/@aws-amplify/storage": { - "version": "5.9.13", - "resolved": "https://registry.npmjs.org/@aws-amplify/storage/-/storage-5.9.13.tgz", - "integrity": "sha512-CoIQI/6bRV3/xmYWjaHqt8lpI09LsgYdVz21pxGScOWYcuo/z2jlU8cX5q4+PmJvqEfq31X/RKiRMGHH+7yqAQ==", + "version": "5.9.14", + "resolved": "https://registry.npmjs.org/@aws-amplify/storage/-/storage-5.9.14.tgz", + "integrity": "sha512-aEMA75chg28ChJGr/KwEF6QtsQrLDphDWZ7juZuRaKi3ilmRcmXh9nL/ZrHR/7zBDqDEWVOOgHUkgVlCt6LyeA==", "dependencies": { - "@aws-amplify/core": "5.8.12", + "@aws-amplify/core": "5.8.13", "@aws-sdk/md5-js": "3.6.1", "@aws-sdk/types": "3.6.1", "buffer": "4.9.2", @@ -790,13 +789,13 @@ } }, "node_modules/@aws-sdk/client-lex-runtime-service": { - "version": "3.186.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-service/-/client-lex-runtime-service-3.186.3.tgz", - "integrity": "sha512-YP+GDY9OxyW4rJDqjreaNpiDBvH1uzO3ShJKl57hT92Kw2auDQxttcMf//J8dQXvrVkW/fVXCLI9TmtxS7XJOQ==", + "version": "3.186.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-service/-/client-lex-runtime-service-3.186.4.tgz", + "integrity": "sha512-ftPIjDR5gmoSu9YXQLWdtiSxGfdSlHSWi+Zqun24f3YHZuLACN514JppvHTcNBztpmtnCU4qx3eFjKg6aMOosg==", "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/client-sts": "3.186.3", + "@aws-sdk/client-sts": "3.186.4", "@aws-sdk/config-resolver": "3.186.0", "@aws-sdk/credential-provider-node": "3.186.0", "@aws-sdk/fetch-http-handler": "3.186.0", @@ -1445,13 +1444,13 @@ } }, "node_modules/@aws-sdk/client-lex-runtime-v2": { - "version": "3.186.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-v2/-/client-lex-runtime-v2-3.186.3.tgz", - "integrity": "sha512-4MJfSnb+qM8BYW4ToCvg7sDWN0NcEqK738hCZUV89cjp7pIHZ6osJuS/PsmZEommVj+71GviZ4buu5KUCfCGFQ==", + "version": "3.186.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lex-runtime-v2/-/client-lex-runtime-v2-3.186.4.tgz", + "integrity": "sha512-ELoZYwTIoQWVw1a+ImE1n4z8b/5DqgzXti8QSoC2VaKv8dNwDO1xWal2LJhw20HPcTkAhHL8IA3gU/tTrWXk1g==", "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/client-sts": "3.186.3", + "@aws-sdk/client-sts": "3.186.4", "@aws-sdk/config-resolver": "3.186.0", "@aws-sdk/credential-provider-node": "3.186.0", "@aws-sdk/eventstream-handler-node": "3.186.0", @@ -2156,13 +2155,13 @@ } }, "node_modules/@aws-sdk/client-location": { - "version": "3.186.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-location/-/client-location-3.186.3.tgz", - "integrity": "sha512-LCMFgoWfvKBnZhhtl93RLhrsHCalM7huaxErHSKoqWDBUDP0i7rOX73qW8E25j/vQ4emEkT0d6ts1rDu4EnlNw==", + "version": "3.186.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-location/-/client-location-3.186.4.tgz", + "integrity": "sha512-wHRVFdIDZVbae2w1axi4R8idiWH3CRZy22Zrtybfs/fvrC5xZZxFaLwXQtvPJdOf0RUGgQeOTsvJl2sInKSj+w==", "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/client-sts": "3.186.3", + "@aws-sdk/client-sts": "3.186.4", "@aws-sdk/config-resolver": "3.186.0", "@aws-sdk/credential-provider-node": "3.186.0", "@aws-sdk/fetch-http-handler": "3.186.0", @@ -3491,9 +3490,9 @@ } }, "node_modules/@aws-sdk/client-sts": { - "version": "3.186.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.186.3.tgz", - "integrity": "sha512-mnttdyYBtqO+FkDtOT3F1FGi8qD11fF5/3zYLaNuFFULqKneaIwW2YIsjFlgvPGpmoyo/tNplnZwhQ9xQtT3Sw==", + "version": "3.186.4", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.186.4.tgz", + "integrity": "sha512-KeC7eNoasv5A/cwC3uyM7xwyFiLYA0wz8YSG2rmvWHsW7vRn/95ATyNGlzNCpTQq3rlNORJ39yxpQCY7AxTb9g==", "dependencies": { "@aws-crypto/sha256-browser": "2.0.0", "@aws-crypto/sha256-js": "2.0.0", @@ -3529,7 +3528,7 @@ "@aws-sdk/util-utf8-browser": "3.186.0", "@aws-sdk/util-utf8-node": "3.186.0", "entities": "2.2.0", - "fast-xml-parser": "4.2.5", + "fast-xml-parser": "4.4.1", "tslib": "^2.3.1" }, "engines": { @@ -7726,6 +7725,22 @@ "node": ">=6.9.0" } }, + "node_modules/@cloudscape-design/chat-components": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@cloudscape-design/chat-components/-/chat-components-1.0.9.tgz", + "integrity": "sha512-/06+sh7Vk6rngTAph8RbhQQS7x0x8dHw/3fQ4Ok9r8nbor3Q73gNN7s5tpfPVBaYet+80Pfov3580iUkltArkg==", + "dependencies": { + "@cloudscape-design/component-toolkit": "^1.0.0-beta", + "@cloudscape-design/test-utils-core": "^1.0.0", + "clsx": "^1.2.1" + }, + "peerDependencies": { + "@cloudscape-design/components": "^3", + "@cloudscape-design/design-tokens": "^3", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, "node_modules/@cloudscape-design/collection-hooks": { "version": "1.0.46", "resolved": "https://registry.npmjs.org/@cloudscape-design/collection-hooks/-/collection-hooks-1.0.46.tgz", @@ -7735,18 +7750,18 @@ } }, "node_modules/@cloudscape-design/component-toolkit": { - "version": "1.0.0-beta.49", - "resolved": "https://registry.npmjs.org/@cloudscape-design/component-toolkit/-/component-toolkit-1.0.0-beta.49.tgz", - "integrity": "sha512-P8VgfZR64ZT7FcEQk9i29FMimtdJ3BmuB8xrH/Y+9wzkW9VieaqGqdkEeBeJgNjEkrh5H1SGleWVXHhh6SXfpw==", + "version": "1.0.0-beta.64", + "resolved": "https://registry.npmjs.org/@cloudscape-design/component-toolkit/-/component-toolkit-1.0.0-beta.64.tgz", + "integrity": "sha512-Bl8XG/Etu36dw+7eFK0Pv0gPp8V8mu7QyzvvJYpKv33Q/r8KWEzDsnY1GJGN5IXrFOQobpi8kaY89nju0EIwag==", "dependencies": { "@juggle/resize-observer": "^3.3.1", "tslib": "^2.3.1" } }, "node_modules/@cloudscape-design/components": { - "version": "3.0.651", - "resolved": "https://registry.npmjs.org/@cloudscape-design/components/-/components-3.0.651.tgz", - "integrity": "sha512-HJ5aI/RohbHEt/TL5AHpXNXqbeA8LbfHUfypSpazR8ZtM1u3ierZp5b9pHbAoGgceMJBrg6KgaeYBU0mGCgihw==", + "version": "3.0.711", + "resolved": "https://registry.npmjs.org/@cloudscape-design/components/-/components-3.0.711.tgz", + "integrity": "sha512-sOLMVe0BaIo1XMsr0+YZnGizevAqOLBUK3PiixOjzzbu830ragl+yYIPYm8JVKmdvtnHJGe1xPvyoaM8OzyfBg==", "dependencies": { "@cloudscape-design/collection-hooks": "^1.0.0", "@cloudscape-design/component-toolkit": "^1.0.0-beta", @@ -7774,14 +7789,14 @@ } }, "node_modules/@cloudscape-design/design-tokens": { - "version": "3.0.36", - "resolved": "https://registry.npmjs.org/@cloudscape-design/design-tokens/-/design-tokens-3.0.36.tgz", - "integrity": "sha512-RwS7z3NsMGGBXllGvdFRvxY+XXSjv4IfuBsMzUShRmtAqGLiVJ65N184UN81nOgAKpioqgIbRaj5yjAFGS8DPA==" + "version": "3.0.43", + "resolved": "https://registry.npmjs.org/@cloudscape-design/design-tokens/-/design-tokens-3.0.43.tgz", + "integrity": "sha512-TsfO58A3Q9Ad8Tc8Cbh6UbH4uJXiPpa1/HlTh78ArPcqhfjtfqJ/YIorNRwVUt56hh44C+QoMYgTNqTS7wa2Gg==" }, "node_modules/@cloudscape-design/global-styles": { - "version": "1.0.27", - "resolved": "https://registry.npmjs.org/@cloudscape-design/global-styles/-/global-styles-1.0.27.tgz", - "integrity": "sha512-26/Xt6eVB+xV+WCZJVmckiUUCYKrhQdGIr1t5gzpO/2VvERqjf+8x3buznyxNlFEfXaiKTMBtATnnYe27ARSiw==" + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/@cloudscape-design/global-styles/-/global-styles-1.0.32.tgz", + "integrity": "sha512-3X7YEnzB7U0HeWS2iGIXWgdUAfloWVm+skzJlFkj0MNGIZ7jpI5rH9u9jLFsS021a4WrpK12FM+cwgLjzAq03A==" }, "node_modules/@cloudscape-design/test-utils-core": { "version": "1.0.32", @@ -7849,70 +7864,6 @@ "react": ">=16.8.0" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/darwin-arm64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", @@ -7929,428 +7880,140 @@ "node": ">=12" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint-community/regexpp": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", + "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", "dev": true, - "optional": true, - "os": [ - "freebsd" - ], "engines": { - "node": ">=12" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", "dev": true, - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "type-fest": "^0.20.2" + }, "engines": { - "node": ">=12" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], + "node_modules/@eslint/js": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "node_modules/@floating-ui/core": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz", + "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==" + }, + "node_modules/@floating-ui/dom": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz", + "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==", + "dependencies": { + "@floating-ui/core": "^0.7.3" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "node_modules/@floating-ui/react-dom": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-0.7.2.tgz", + "integrity": "sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg==", + "dependencies": { + "@floating-ui/dom": "^0.5.3", + "use-isomorphic-layout-effect": "^1.1.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz", + "integrity": "sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g==", + "dependencies": { + "@formatjs/intl-localematcher": "0.5.4", + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz", + "integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==", + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", - "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", - "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@floating-ui/core": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz", - "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==" - }, - "node_modules/@floating-ui/dom": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz", - "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==", - "dependencies": { - "@floating-ui/core": "^0.7.3" - } - }, - "node_modules/@floating-ui/react-dom": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-0.7.2.tgz", - "integrity": "sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg==", - "dependencies": { - "@floating-ui/dom": "^0.5.3", - "use-isomorphic-layout-effect": "^1.1.1" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@formatjs/ecma402-abstract": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz", - "integrity": "sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g==", - "dependencies": { - "@formatjs/intl-localematcher": "0.5.4", - "tslib": "^2.4.0" - } - }, - "node_modules/@formatjs/fast-memoize": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz", - "integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@formatjs/icu-messageformat-parser": { - "version": "2.7.8", - "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz", - "integrity": "sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA==", - "dependencies": { - "@formatjs/ecma402-abstract": "2.0.0", - "@formatjs/icu-skeleton-parser": "1.8.2", - "tslib": "^2.4.0" + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.7.8", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz", + "integrity": "sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA==", + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/icu-skeleton-parser": "1.8.2", + "tslib": "^2.4.0" } }, "node_modules/@formatjs/icu-skeleton-parser": { @@ -8370,51 +8033,6 @@ "tslib": "^2.4.0" } }, - "node_modules/@fortawesome/fontawesome-common-types": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz", - "integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==", - "hasInstallScript": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@fortawesome/fontawesome-svg-core": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz", - "integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==", - "hasInstallScript": true, - "dependencies": { - "@fortawesome/fontawesome-common-types": "6.5.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@fortawesome/free-solid-svg-icons": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz", - "integrity": "sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==", - "hasInstallScript": true, - "dependencies": { - "@fortawesome/fontawesome-common-types": "6.5.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@fortawesome/react-fontawesome": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", - "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", - "dependencies": { - "prop-types": "^15.8.1" - }, - "peerDependencies": { - "@fortawesome/fontawesome-svg-core": "~1 || ~6", - "react": ">=16.3" - } - }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -10443,9 +10061,9 @@ } }, "node_modules/@rnx-kit/chromium-edge-launcher/node_modules/@types/node": { - "version": "18.19.43", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.43.tgz", - "integrity": "sha512-Mw/YlgXnyJdEwLoFv2dpuJaDFriX+Pc+0qOBJ57jC1H6cDxIj2xc5yUrdtArDVG0m+KV6622a4p2tenEqB3C/g==", + "version": "18.19.44", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.44.tgz", + "integrity": "sha512-ZsbGerYg72WMXUIE9fYxtvfzLEuq6q8mKERdWFnqTmOvudMxnz+CBNRoOwJ2kNpFOncrKjT1hZwxjlFgQ9qvQA==", "peer": true, "dependencies": { "undici-types": "~5.26.4" @@ -10766,9 +10384,9 @@ "dev": true }, "node_modules/@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "peer": true, "dependencies": { "@types/yargs-parser": "*" @@ -11276,22 +10894,22 @@ } }, "node_modules/aws-amplify": { - "version": "5.3.20", - "resolved": "https://registry.npmjs.org/aws-amplify/-/aws-amplify-5.3.20.tgz", - "integrity": "sha512-xJwnTlCfOD/f+qTM3tpr98ZhHWpefaj+jl+NTVgmIl4LHdgpXTP1qqaF/UEGIT0euoiDOhxAXfC1bn9RJNgJ5g==", - "dependencies": { - "@aws-amplify/analytics": "6.5.12", - "@aws-amplify/api": "5.4.12", - "@aws-amplify/auth": "5.6.12", - "@aws-amplify/cache": "5.1.18", - "@aws-amplify/core": "5.8.12", - "@aws-amplify/datastore": "4.7.12", - "@aws-amplify/geo": "2.3.12", - "@aws-amplify/interactions": "5.2.18", - "@aws-amplify/notifications": "1.6.13", - "@aws-amplify/predictions": "5.5.13", - "@aws-amplify/pubsub": "5.5.12", - "@aws-amplify/storage": "5.9.13", + "version": "5.3.21", + "resolved": "https://registry.npmjs.org/aws-amplify/-/aws-amplify-5.3.21.tgz", + "integrity": "sha512-wTzycfJ/BnMx9yjv5GXnRc0KM5IA27ZFy6v/dnj2umeG81QpbK5bJP1DOfhhRUl3vKIXIjFL+b2Pb5yVwr05ZQ==", + "dependencies": { + "@aws-amplify/analytics": "6.5.13", + "@aws-amplify/api": "5.4.13", + "@aws-amplify/auth": "5.6.13", + "@aws-amplify/cache": "5.1.19", + "@aws-amplify/core": "5.8.13", + "@aws-amplify/datastore": "4.7.13", + "@aws-amplify/geo": "2.3.13", + "@aws-amplify/interactions": "5.2.19", + "@aws-amplify/notifications": "1.6.14", + "@aws-amplify/predictions": "5.5.14", + "@aws-amplify/pubsub": "5.5.13", + "@aws-amplify/storage": "5.9.14", "tslib": "^2.0.0" } }, @@ -11632,9 +11250,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001649", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001649.tgz", - "integrity": "sha512-fJegqZZ0ZX8HOWr6rcafGr72+xcgJKI9oWfDW5DrD7ExUtgZC7a7R7ZYmZqplh7XDocFdGeIFn7roAxhOeYrPQ==", + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", "funding": [ { "type": "opencollective", @@ -12375,9 +11993,9 @@ "peer": true }, "node_modules/electron-to-chromium": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", - "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==" + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.6.tgz", + "integrity": "sha512-jwXWsM5RPf6j9dPYzaorcBSUg6AiqocPEyMpkchkvntaH9HGfOOMZwxMJjDY/XEs3T5dM7uyH1VhRMkqUU9qVw==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -12832,6 +12450,12 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "peer": true + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -13046,9 +12670,9 @@ "peer": true }, "node_modules/flow-parser": { - "version": "0.242.1", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.242.1.tgz", - "integrity": "sha512-E3ml21Q1S5cMAyPbtYslkvI6yZO5oCS/S2EoteeFH8Kx9iKOv/YOJ+dGd/yMf+H3YKfhMKjnOpyNwrO7NdddWA==", + "version": "0.243.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.243.0.tgz", + "integrity": "sha512-HCDBfH+kZcY5etWYeAqatjW78gkIryzb9XixRsA8lGI1uyYc7aCpElkkO4H+KIpoyQMiY0VAZPI4cyac3wQe8w==", "peer": true, "engines": { "node": ">=0.4.0" @@ -13074,9 +12698,9 @@ } }, "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -14926,9 +14550,9 @@ } }, "node_modules/metro": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.80.9.tgz", - "integrity": "sha512-Bc57Xf3GO2Xe4UWQsBj/oW6YfLPABEu8jfDVDiNmJvoQW4CO34oDPuYKe4KlXzXhcuNsqOtSxpbjCRRVjhhREg==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.80.10.tgz", + "integrity": "sha512-FDPi0X7wpafmDREXe1lgg3WzETxtXh6Kpq8+IwsG35R2tMyp2kFIqDdshdohuvDt1J/qDARcEPq7V/jElTb1kA==", "peer": true, "dependencies": { "@babel/code-frame": "^7.0.0", @@ -14945,34 +14569,34 @@ "debug": "^2.2.0", "denodeify": "^1.2.1", "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", - "hermes-parser": "0.20.1", + "hermes-parser": "0.23.0", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.6.3", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.80.9", - "metro-cache": "0.80.9", - "metro-cache-key": "0.80.9", - "metro-config": "0.80.9", - "metro-core": "0.80.9", - "metro-file-map": "0.80.9", - "metro-resolver": "0.80.9", - "metro-runtime": "0.80.9", - "metro-source-map": "0.80.9", - "metro-symbolicate": "0.80.9", - "metro-transform-plugins": "0.80.9", - "metro-transform-worker": "0.80.9", + "metro-babel-transformer": "0.80.10", + "metro-cache": "0.80.10", + "metro-cache-key": "0.80.10", + "metro-config": "0.80.10", + "metro-core": "0.80.10", + "metro-file-map": "0.80.10", + "metro-resolver": "0.80.10", + "metro-runtime": "0.80.10", + "metro-source-map": "0.80.10", + "metro-symbolicate": "0.80.10", + "metro-transform-plugins": "0.80.10", + "metro-transform-worker": "0.80.10", "mime-types": "^2.1.27", "node-fetch": "^2.2.0", "nullthrows": "^1.1.1", - "rimraf": "^3.0.2", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "strip-ansi": "^6.0.0", "throat": "^5.0.0", - "ws": "^7.5.1", + "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { @@ -14983,13 +14607,14 @@ } }, "node_modules/metro-babel-transformer": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.80.9.tgz", - "integrity": "sha512-d76BSm64KZam1nifRZlNJmtwIgAeZhZG3fi3K+EmPOlrR8rDtBxQHDSN3fSGeNB9CirdTyabTMQCkCup6BXFSQ==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.80.10.tgz", + "integrity": "sha512-GXHueUzgzcazfzORDxDzWS9jVVRV6u+cR6TGvHOfGdfLzJCj7/D0PretLfyq+MwN20twHxLW+BUXkoaB8sCQBg==", "peer": true, "dependencies": { "@babel/core": "^7.20.0", - "hermes-parser": "0.20.1", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.23.0", "nullthrows": "^1.1.1" }, "engines": { @@ -14997,82 +14622,89 @@ } }, "node_modules/metro-babel-transformer/node_modules/hermes-estree": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.20.1.tgz", - "integrity": "sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.23.0.tgz", + "integrity": "sha512-Rkp0PNLGpORw4ktsttkVbpYJbrYKS3hAnkxu8D9nvQi6LvSbuPa+tYw/t2u3Gjc35lYd/k95YkjqyTcN4zspag==", "peer": true }, "node_modules/metro-babel-transformer/node_modules/hermes-parser": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.20.1.tgz", - "integrity": "sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.23.0.tgz", + "integrity": "sha512-xLwM4ylfHGwrm+2qXfO1JT/fnqEDGSnpS/9hQ4VLtqTexSviu2ZpBgz07U8jVtndq67qdb/ps0qvaWDZ3fkTyg==", "peer": true, "dependencies": { - "hermes-estree": "0.20.1" + "hermes-estree": "0.23.0" } }, "node_modules/metro-cache": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.80.9.tgz", - "integrity": "sha512-ujEdSI43QwI+Dj2xuNax8LMo8UgKuXJEdxJkzGPU6iIx42nYa1byQ+aADv/iPh5sh5a//h5FopraW5voXSgm2w==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.80.10.tgz", + "integrity": "sha512-8CBtDJwMguIE5RvV3PU1QtxUG8oSSX54mIuAbRZmcQ0MYiOl9JdrMd4JCBvIyhiZLoSStph425SMyCSnjtJsdA==", "peer": true, "dependencies": { - "metro-core": "0.80.9", - "rimraf": "^3.0.2" + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "metro-core": "0.80.10" }, "engines": { "node": ">=18" } }, "node_modules/metro-cache-key": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.80.9.tgz", - "integrity": "sha512-hRcYGhEiWIdM87hU0fBlcGr+tHDEAT+7LYNCW89p5JhErFt/QaAkVx4fb5bW3YtXGv5BTV7AspWPERoIb99CXg==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.80.10.tgz", + "integrity": "sha512-57qBhO3zQfoU/hP4ZlLW5hVej2jVfBX6B4NcSfMj4LgDPL3YknWg80IJBxzQfjQY/m+fmMLmPy8aUMHzUp/guA==", "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, "engines": { "node": ">=18" } }, "node_modules/metro-config": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.80.9.tgz", - "integrity": "sha512-28wW7CqS3eJrunRGnsibWldqgwRP9ywBEf7kg+uzUHkSFJNKPM1K3UNSngHmH0EZjomizqQA2Zi6/y6VdZMolg==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.80.10.tgz", + "integrity": "sha512-0GYAw0LkmGbmA81FepKQepL1KU/85Cyv7sAiWm6QWeV6AcVCpsKg6jGLqGHJ0LLPL60rWzA4TV1DQAlzdJAEtA==", "peer": true, "dependencies": { "connect": "^3.6.5", "cosmiconfig": "^5.0.5", + "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.6.3", - "metro": "0.80.9", - "metro-cache": "0.80.9", - "metro-core": "0.80.9", - "metro-runtime": "0.80.9" + "metro": "0.80.10", + "metro-cache": "0.80.10", + "metro-core": "0.80.10", + "metro-runtime": "0.80.10" }, "engines": { "node": ">=18" } }, "node_modules/metro-core": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.80.9.tgz", - "integrity": "sha512-tbltWQn+XTdULkGdzHIxlxk4SdnKxttvQQV3wpqqFbHDteR4gwCyTR2RyYJvxgU7HELfHtrVbqgqAdlPByUSbg==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.80.10.tgz", + "integrity": "sha512-nwBB6HbpGlNsZMuzxVqxqGIOsn5F3JKpsp8PziS7Z4mV8a/jA1d44mVOgYmDa2q5WlH5iJfRIIhdz24XRNDlLA==", "peer": true, "dependencies": { + "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", - "metro-resolver": "0.80.9" + "metro-resolver": "0.80.10" }, "engines": { "node": ">=18" } }, "node_modules/metro-file-map": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.80.9.tgz", - "integrity": "sha512-sBUjVtQMHagItJH/wGU9sn3k2u0nrCl0CdR4SFMO1tksXLKbkigyQx4cbpcyPVOAmGTVuy3jyvBlELaGCAhplQ==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.80.10.tgz", + "integrity": "sha512-ytsUq8coneaN7ZCVk1IogojcGhLIbzWyiI2dNmw2nnBgV/0A+M5WaTTgZ6dJEz3dzjObPryDnkqWPvIGLCPtiw==", "peer": true, "dependencies": { "anymatch": "^3.0.3", "debug": "^2.2.0", "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "invariant": "^2.2.4", "jest-worker": "^29.6.3", @@ -15104,11 +14736,12 @@ "peer": true }, "node_modules/metro-minify-terser": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.80.9.tgz", - "integrity": "sha512-FEeCeFbkvvPuhjixZ1FYrXtO0araTpV6UbcnGgDUpH7s7eR5FG/PiJz3TsuuPP/HwCK19cZtQydcA2QrCw446A==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.80.10.tgz", + "integrity": "sha512-Xyv9pEYpOsAerrld7cSLIcnCCpv8ItwysOmTA+AKf1q4KyE9cxrH2O2SA0FzMCkPzwxzBWmXwHUr+A89BpEM6g==", "peer": true, "dependencies": { + "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" }, "engines": { @@ -15116,38 +14749,43 @@ } }, "node_modules/metro-resolver": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.80.9.tgz", - "integrity": "sha512-wAPIjkN59BQN6gocVsAvvpZ1+LQkkqUaswlT++cJafE/e54GoVkMNCmrR4BsgQHr9DknZ5Um/nKueeN7kaEz9w==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.80.10.tgz", + "integrity": "sha512-EYC5CL7f+bSzrqdk1bylKqFNGabfiI5PDctxoPx70jFt89Jz+ThcOscENog8Jb4LEQFG6GkOYlwmPpsi7kx3QA==", "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, "engines": { "node": ">=18" } }, "node_modules/metro-runtime": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.80.9.tgz", - "integrity": "sha512-8PTVIgrVcyU+X/rVCy/9yxNlvXsBCk5JwwkbAm/Dm+Abo6NBGtNjWF0M1Xo/NWCb4phamNWcD7cHdR91HhbJvg==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.80.10.tgz", + "integrity": "sha512-Xh0N589ZmSIgJYAM+oYwlzTXEHfASZac9TYPCNbvjNTn0EHKqpoJ/+Im5G3MZT4oZzYv4YnvzRtjqS5k0tK94A==", "peer": true, "dependencies": { - "@babel/runtime": "^7.0.0" + "@babel/runtime": "^7.0.0", + "flow-enums-runtime": "^0.0.6" }, "engines": { "node": ">=18" } }, "node_modules/metro-source-map": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.80.9.tgz", - "integrity": "sha512-RMn+XS4VTJIwMPOUSj61xlxgBvPeY4G6s5uIn6kt6HB6A/k9ekhr65UkkDD7WzHYs3a9o869qU8tvOZvqeQzgw==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.80.10.tgz", + "integrity": "sha512-EyZswqJW8Uukv/HcQr6K19vkMXW1nzHAZPWJSEyJFKIbgp708QfRZ6vnZGmrtFxeJEaFdNup4bGnu8/mIOYlyA==", "peer": true, "dependencies": { "@babel/traverse": "^7.20.0", "@babel/types": "^7.20.0", + "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", - "metro-symbolicate": "0.80.9", + "metro-symbolicate": "0.80.10", "nullthrows": "^1.1.1", - "ob1": "0.80.9", + "ob1": "0.80.10", "source-map": "^0.5.6", "vlq": "^1.0.0" }, @@ -15165,13 +14803,14 @@ } }, "node_modules/metro-symbolicate": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.80.9.tgz", - "integrity": "sha512-Ykae12rdqSs98hg41RKEToojuIW85wNdmSe/eHUgMkzbvCFNVgcC0w3dKZEhSsqQOXapXRlLtHkaHLil0UD/EA==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.80.10.tgz", + "integrity": "sha512-qAoVUoSxpfZ2DwZV7IdnQGXCSsf2cAUExUcZyuCqGlY5kaWBb0mx2BL/xbMFDJ4wBp3sVvSBPtK/rt4J7a0xBA==", "peer": true, "dependencies": { + "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", - "metro-source-map": "0.80.9", + "metro-source-map": "0.80.10", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "through2": "^2.0.1", @@ -15194,15 +14833,16 @@ } }, "node_modules/metro-transform-plugins": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.80.9.tgz", - "integrity": "sha512-UlDk/uc8UdfLNJhPbF3tvwajyuuygBcyp+yBuS/q0z3QSuN/EbLllY3rK8OTD9n4h00qZ/qgxGv/lMFJkwP4vg==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.80.10.tgz", + "integrity": "sha512-leAx9gtA+2MHLsCeWK6XTLBbv2fBnNFu/QiYhWzMq8HsOAP4u1xQAU0tSgPs8+1vYO34Plyn79xTLUtQCRSSUQ==", "peer": true, "dependencies": { "@babel/core": "^7.20.0", "@babel/generator": "^7.20.0", "@babel/template": "^7.0.0", "@babel/traverse": "^7.20.0", + "flow-enums-runtime": "^0.0.6", "nullthrows": "^1.1.1" }, "engines": { @@ -15210,22 +14850,23 @@ } }, "node_modules/metro-transform-worker": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.80.9.tgz", - "integrity": "sha512-c/IrzMUVnI0hSVVit4TXzt3A1GiUltGVlzCmLJWxNrBGHGrJhvgePj38+GXl1Xf4Fd4vx6qLUkKMQ3ux73bFLQ==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.80.10.tgz", + "integrity": "sha512-zNfNLD8Rz99U+JdOTqtF2o7iTjcDMMYdVS90z6+81Tzd2D0lDWVpls7R1hadS6xwM+ymgXFQTjM6V6wFoZaC0g==", "peer": true, "dependencies": { "@babel/core": "^7.20.0", "@babel/generator": "^7.20.0", "@babel/parser": "^7.20.0", "@babel/types": "^7.20.0", - "metro": "0.80.9", - "metro-babel-transformer": "0.80.9", - "metro-cache": "0.80.9", - "metro-cache-key": "0.80.9", - "metro-minify-terser": "0.80.9", - "metro-source-map": "0.80.9", - "metro-transform-plugins": "0.80.9", + "flow-enums-runtime": "^0.0.6", + "metro": "0.80.10", + "metro-babel-transformer": "0.80.10", + "metro-cache": "0.80.10", + "metro-cache-key": "0.80.10", + "metro-minify-terser": "0.80.10", + "metro-source-map": "0.80.10", + "metro-transform-plugins": "0.80.10", "nullthrows": "^1.1.1" }, "engines": { @@ -15320,18 +14961,18 @@ } }, "node_modules/metro/node_modules/hermes-estree": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.20.1.tgz", - "integrity": "sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.23.0.tgz", + "integrity": "sha512-Rkp0PNLGpORw4ktsttkVbpYJbrYKS3hAnkxu8D9nvQi6LvSbuPa+tYw/t2u3Gjc35lYd/k95YkjqyTcN4zspag==", "peer": true }, "node_modules/metro/node_modules/hermes-parser": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.20.1.tgz", - "integrity": "sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.23.0.tgz", + "integrity": "sha512-xLwM4ylfHGwrm+2qXfO1JT/fnqEDGSnpS/9hQ4VLtqTexSviu2ZpBgz07U8jVtndq67qdb/ps0qvaWDZ3fkTyg==", "peer": true, "dependencies": { - "hermes-estree": "0.20.1" + "hermes-estree": "0.23.0" } }, "node_modules/metro/node_modules/ms": { @@ -16241,10 +15882,13 @@ "peer": true }, "node_modules/ob1": { - "version": "0.80.9", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.80.9.tgz", - "integrity": "sha512-v9yOxowkZbxWhKOaaTyLjIm1aLy4ebMNcSn4NYJKOAI/Qv+SkfEfszpLr2GIxsccmb2Y2HA9qtsqiIJ80ucpVA==", + "version": "0.80.10", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.80.10.tgz", + "integrity": "sha512-dJHyB0S6JkMorUSfSGcYGkkg9kmq3qDUu3ygZUKIfkr47XOPuG35r2Sk6tbwtHXbdKIXmcMvM8DF2CwgdyaHfQ==", "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, "engines": { "node": ">=18" } @@ -19200,54 +18844,6 @@ } } }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/vite/node_modules/@esbuild/darwin-arm64": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", @@ -19264,294 +18860,6 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/vite/node_modules/esbuild": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", diff --git a/lib/user-interface/react-app/package.json b/lib/user-interface/react-app/package.json index 7e61e5376..411a8384d 100644 --- a/lib/user-interface/react-app/package.json +++ b/lib/user-interface/react-app/package.json @@ -13,12 +13,11 @@ }, "dependencies": { "@aws-amplify/ui-react": "^5.3.3", + "@cloudscape-design/chat-components": "^1.0.9", + "@cloudscape-design/component-toolkit": "^1.0.0-beta.64", "@cloudscape-design/components": "^3.0.651", "@cloudscape-design/design-tokens": "^3.0.36", "@cloudscape-design/global-styles": "^1.0.27", - "@fortawesome/fontawesome-svg-core": "^6.4.2", - "@fortawesome/free-solid-svg-icons": "^6.4.2", - "@fortawesome/react-fontawesome": "^0.2.0", "aws-amplify": "^5.3.20", "luxon": "^3.4.3", "react": "^18.2.0", diff --git a/lib/user-interface/react-app/src/common/helpers/options-helper.ts b/lib/user-interface/react-app/src/common/helpers/options-helper.ts index e06d31515..9519d295a 100644 --- a/lib/user-interface/react-app/src/common/helpers/options-helper.ts +++ b/lib/user-interface/react-app/src/common/helpers/options-helper.ts @@ -32,17 +32,24 @@ export abstract class OptionsHelper { } } - static getSelectOptionGroups( - data: T[] - ) { + static getSelectOptionGroups< + T extends { + provider: string; + name: string; + interface?: string; + isAgent?: boolean | null; + agentIsUpdated?: boolean | null; + }, + >(data: T[]) { const modelsMap = new Map(); data.forEach((item) => { - let items = modelsMap.get(item.provider); + const group = `${item.provider}:${item.interface}`; + let items = modelsMap.get(group); if (!items) { items = []; - modelsMap.set(item.provider, [item]); + modelsMap.set(group, [item]); } else { - modelsMap.set(item.provider, [...items, item]); + modelsMap.set(group, [...items, item]); } }); @@ -52,12 +59,13 @@ export abstract class OptionsHelper { const options: SelectProps.OptionGroup[] = keys.map((key) => { const items = modelsMap.get(key); items?.sort((a, b) => a.name.localeCompare(b.name)); - return { label: this.getProviderLabel(key), options: items?.map((item) => ({ - label: item.name, + label: + item.name + + (item.isAgent ? (item.agentIsUpdated! ? " ⭐️" : " ✅") : ""), value: `${item.provider}::${item.name}`, })) ?? [], }; @@ -81,8 +89,9 @@ export abstract class OptionsHelper { static getProviderLabel(provider: string) { let label = provider; - if (label === "sagemaker") label = "SageMaker"; - else if (label === "bedrock") label = "Bedrock"; + if (label.startsWith("sagemaker")) label = "SageMaker"; + else if (label === "bedrock:langchain") label = "Bedrock"; + else if (label === "bedrock:agent") label = "Bedrock Agents"; else if (label === "openai") label = "OpenAI"; return label; diff --git a/lib/user-interface/react-app/src/components/chatbot/BaseChatMessage.tsx b/lib/user-interface/react-app/src/components/chatbot/BaseChatMessage.tsx new file mode 100644 index 000000000..d0cf755ab --- /dev/null +++ b/lib/user-interface/react-app/src/components/chatbot/BaseChatMessage.tsx @@ -0,0 +1,157 @@ +import { + ExpandableSection, + ButtonGroup, + ButtonGroupProps, + Box, + StatusIndicator, +} from "@cloudscape-design/components"; +import { ReactElement, useEffect, useMemo, useState } from "react"; +import { Avatar } from "@cloudscape-design/chat-components"; + +export function BaseChatMessage({ + role, + waiting, + name, + avatarElement, + children, + expandableContent, + onFeedback, + onCopy, +}: { + readonly role: "ai" | "human"; + readonly waiting?: boolean; + readonly name?: string; + readonly avatarElement?: ReactElement; + readonly children?: ReactElement; + readonly expandableContent?: ReactElement; + readonly onFeedback?: (thumb: "up" | "down" | undefined) => void; + readonly onCopy?: () => void; +}) { + const [thumb, setThumb] = useState<"up" | "down" | undefined>(undefined); + + const buttonGroupItems = useMemo(() => { + const bg: ButtonGroupProps.Group[] = []; + if (onFeedback && role === "ai") { + bg.push({ + type: "group", + text: "Feedback", + items: [ + { + type: "icon-button", + id: "thumbs-up", + iconName: thumb == "up" ? "thumbs-up-filled" : "thumbs-up", + text: "Thumbs Up", + }, + { + type: "icon-button", + id: "thumbs-down", + iconName: thumb == "down" ? "thumbs-down-filled" : "thumbs-down", + text: "Thumbs Down", + }, + ], + }); + } + + if (onCopy) { + bg.push({ + type: "group", + text: "Actions", + items: [ + { + type: "icon-button", + id: "copy", + iconName: "copy", + text: "Copy", + popoverFeedback: ( + Message copied + ), + }, + ], + }); + } + return bg; + }, [thumb, role, onCopy, onFeedback]); + + useEffect(() => { + if (onFeedback) onFeedback(thumb); + }, [thumb, onFeedback]); + + return ( +
+
+ {role === "ai" ? ( + + ) : ( + + )} +
+ +
+
+ {children} +
+ {(onCopy || onFeedback) && ( + + { + if (e.detail.id === "thumbs-up") { + if (thumb === "up") { + setThumb(undefined); + } else setThumb("up"); + } else if (e.detail.id === "thumbs-down") { + if (thumb === "down") { + setThumb(undefined); + } else setThumb("down"); + } else if (e.detail.id === "copy") { + onCopy?.(); + } + }} + /> + + )} + {!waiting && expandableContent && ( + + {expandableContent} + + )} +
+
+ ); +} diff --git a/lib/user-interface/react-app/src/components/chatbot/CopyButton.tsx b/lib/user-interface/react-app/src/components/chatbot/CopyButton.tsx new file mode 100644 index 000000000..354c39dff --- /dev/null +++ b/lib/user-interface/react-app/src/components/chatbot/CopyButton.tsx @@ -0,0 +1,32 @@ +import { + Button, + Popover, + StatusIndicator, +} from "@cloudscape-design/components"; + +export function CopyWithPopoverButton(props: { + readonly text?: string; + readonly onCopy: () => void; + readonly disabled?: boolean; +}) { + return ( + + {props.text ?? "Copied to clipboard"} + + } + > + - -
-
- + No models available. Please make sure you have access to + Amazon Bedrock or alternatively deploy a self hosted model on + SageMaker or add API_KEY to Secrets Manager +
} - loadingText="Loading workspaces (might take few seconds)..." - statusType={state.workspacesStatus} - placeholder="Select a workspace (RAG data source)" filteringType="auto" - selectedOption={state.selectedWorkspace} - options={workspaceOptions} + selectedOption={state.selectedModel} onChange={({ detail }) => { - if (detail.selectedOption?.value === "__create__") { - navigate("/rag/workspaces/create"); - } else { - setState((state) => ({ - ...state, - selectedWorkspace: detail.selectedOption, - })); - - StorageHelper.setSelectedWorkspaceId( - detail.selectedOption?.value ?? "" - ); + setState((state) => ({ + ...state, + selectedModel: detail.selectedOption, + selectedModelMetadata: getSelectedModelMetadata( + state.models, + detail.selectedOption + ), + })); + if (detail.selectedOption?.value) { + StorageHelper.setSelectedLLM(detail.selectedOption.value); } }} - empty={"No Workspaces available"} + options={modelsOptions} /> - )} -
-
- -
- -